Compare commits

...
34 Commits
Author SHA1 Message Date
roberto@natty32 6eed48b28d updated Changelog and copyright year 2011-04-06 09:29:46 +02:00
roberto@netbsd64 9c5d289098 better locking for NetBSD and OpenBSD 2011-04-06 08:16:03 +02:00
roberto@solarisexpress 42ab7f23d8 added timegm to solaris 2011-04-06 06:03:17 +00:00
roberto@natty32 c9c2f4232e preparing for 0.9.7.2 release 2011-04-06 05:06:38 +02:00
roberto@longshot d4f23cc6bd use realpath() for document_root 2011-04-05 20:55:48 +02:00
roberto@natty32 b0db67d4d4 refactored post limit management 2011-04-05 16:51:40 +02:00
roberto@natty32 703cad6715 disallow empty socket names 2011-04-05 11:32:15 +02:00
roberto@natty32 667d67460f do not build netlink support (still useless for non-third-party plugins) 2011-04-05 09:00:58 +02:00
roberto@natty32 35cf9ae328 implemented exc_info in WSGI start_response and added --reload-on-as and --reload-on-rss 2011-04-05 08:58:22 +02:00
roberto@natty32 c04131af4b fixed syslog support 2011-04-04 17:17:47 +02:00
roberto@natty32 9cc4db1a12 various fixes 2011-04-04 09:46:17 +02:00
roberto@natty32 b326500913 --static-map mountpoint=documentroot option 2011-04-04 08:31:17 +02:00
roberto@natty32 a26579fcf5 better plugin loading 2011-04-03 08:18:51 +02:00
roberto@natty32 a2b9c44433 -ldl should be used only for Linux 2011-04-02 15:57:57 +02:00
roberto@natty32 c3b97da1d4 various Riccardo Magliocchetti build fixes 2011-04-02 15:26:00 +02:00
roberto@natty32 048cf0232a nailed connection between emperor and rabbitmq 2011-04-01 16:11:18 +02:00
roberto@natty32 89c113bee6 added EXILE mode for vassals 2011-04-01 08:35:20 +02:00
roberto@natty32 6b9969a302 allow emperor config files to be taken via http 2011-04-01 08:09:34 +02:00
roberto@natty32 a6e7513d2a declare exchange automatically 2011-04-01 07:13:09 +02:00
roberto@natty32 8a04f4810f allow vassals configuration to be stored on amqp/rabbitmq servers 2011-04-01 06:31:54 +02:00
roberto@natty32 1d9d443de0 amqp/rabbitmq emperor fixes 2011-04-01 05:17:50 +02:00
roberto@natty32 00e5809a71 preliminary amqp/rabbitmq support for emperor 2011-04-01 03:14:51 +02:00
roberto@freebsd64 07ba4a040b fixed freebsd kvm_open 2011-03-30 20:48:01 +02:00
roberto@mrspurr 7b319d230a allow building of psgi plugin without ithreads 2011-03-30 08:03:48 +02:00
roberto@natty32 641bc2daec fixed unbitstaff build profile 2011-03-29 12:06:13 +02:00
roberto@dj2 fbaa30cc08 various fixes 2011-03-28 11:31:40 -05:00
roberto@dj2 a0c2c9056b fixed a couple fo emperor race conditions 2011-03-28 09:37:17 -05:00
roberto@dj2 30ab5fd76b added --exit-on-reload 2011-03-28 07:31:51 -05:00
roberto@dj2 30beab4017 fixed a regression in setgroups() 2011-03-28 05:38:29 -05:00
roberto@dj2 4ec1493b09 fixed subscription system 2011-03-28 04:29:04 -05:00
roberto@dj2 e7cbe9709e build netlink support in Linux 2011-03-28 04:17:07 -05:00
roberto@dj2 aacaeba525 shared sockets support 2011-03-28 04:15:31 -05:00
roberto@dj2 6e4da5efb7 add netlink library 2011-03-28 04:11:31 -05:00
roberto@natty32 87443a4ff2 Added tag 0.9.7.1 for changeset 486e7760bcbc 2011-03-26 09:39:57 +01:00
29 changed files with 2296 additions and 294 deletions
+2
View File
@@ -17,3 +17,5 @@ eb8aff2926230bb114fb90f67203440a2c534bf1 0.9.7-rc2
d9b9b540f7dce8cb05d2e61ca8b4d75f2ea25f62 0.9.7.1
d9b9b540f7dce8cb05d2e61ca8b4d75f2ea25f62 0.9.7.1
0000000000000000000000000000000000000000 0.9.7.1
0000000000000000000000000000000000000000 0.9.7.1
486e7760bcbc2191ddb9b4aee6c98dbd5fc4c754 0.9.7.1
+20
View File
@@ -1,3 +1,23 @@
*** april 2011 ***
* 0.9.7.2 [20110406]
- new option --touch-reload <file> to reload the stack on <file> modification
--static-map <mountpoint=documentroot> allows to serve static files
- fixed --post-limit management
- disallow empty socket names
- implemented exception_info WSGI support
- new options --reload-on-as <n> and --reload-on-rss <n> allows
to recycle workers when their memory usage is higher than <n> MB
- fixed syslog support (use --log-syslog[=facility] to enable it)
- improved plugin loading system
- added support for RabbitMQ as event dispatcher for the Emperor
- fixed FreeBSD memory report
- PSGI plugin can be compiled without ithreads
- various Emperor fixes
- fixed a regression with setgroups()
- support for shared sockets (used in jails within network namespaces)
*** march 2011 ***
* 0.9.7.1 [20110326]
+1
View File
@@ -1,4 +1,5 @@
[uwsgi]
inherit = unbit
embedded_plugins = python
bin_name = ../bin/uwsgi
plugin_dir = ../bin/uwsgi_plugins
+66
View File
@@ -0,0 +1,66 @@
import django
from django.core.management.base import BaseCommand
from django.conf import settings
import os
import sys
class Command(BaseCommand):
help = "Runs this project as a uWSGI application. Requires the uwsgi binary in system path."
http_port = '8000'
socket_addr = None
def handle(self, *args, **options):
for arg in args:
k,v = arg.split('=')
if k == 'http':
if self.http_port:
self.http_port = v
elif k == 'socket':
self.http_port = None
self.socket_addr = v
# load http and python plugin: first the specific version, otherwise try with the generic one
if self.http_port:
os.environ['UWSGI_PLUGINS'] = 'http,python%d%d:python' % (sys.version_info[0], sys.version_info[1])
else:
os.environ['UWSGI_PLUGINS'] = 'python%d%d:python' % (sys.version_info[0], sys.version_info[1])
# load the Django WSGI handler
os.environ['UWSGI_MODULE'] = 'django.core.handlers.wsgi:WSGIHandler()'
# DJANGO settings
if options['settings']:
os.environ['DJANGO_SETTINGS_MODULE'] = options['settings']
else:
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
# bind the http server to the default port
if self.http_port:
os.environ['UWSGI_HTTP'] = ':%s' % self.http_port
elif self.socket_addr:
os.environ['UWSGI_SOCKET'] = self.socket_addr
# map admin static files
os.environ['UWSGI_STATIC_MAP'] = '%s=%s' % (settings.ADMIN_MEDIA_PREFIX, os.path.join(django.__path__[0], 'contrib', 'admin', 'media'))
# remove sockets/pidfile at exit
os.environ['UWSGI_VACUUM'] = '1'
# retrieve/set the PythonHome
os.environ['UWSGI_PYHOME'] = sys.prefix
# increase buffer size a bit
os.environ['UWSGI_BUFFER_SIZE'] = '8192'
# add threads for concurrency
os.environ['UWSGI_THREADS'] = '8'
# enable the master process
os.environ['UWSGI_MASTER'] = '1'
# use uWSGI python module aliasing to fix the PYTHONPATH
os.environ['UWSGI_PYMODULE_ALIAS'] = '%s=./' % os.path.basename(os.getcwd())
# exec the uwsgi binary
os.execvp('uwsgi', ('uwsgi',))
def usage(self, subcomand):
return r"""
run this project on the uWSGI server
http=PORT run the embedded http server on port PORT
socket=ADDR bind the uwsgi server on address ADDR (this will disable the http server)
"""
+250 -86
View File
@@ -10,24 +10,29 @@ struct uwsgi_instance {
struct uwsgi_instance *ui_next;
char name[0xff];
pid_t pid ;
pid_t pid;
int status;
time_t born;
time_t last_mod;
uint64_t respawns;
int use_config;
int pipe[2];
int pipe_config[2];
char *config;
uint32_t config_len;
};
struct uwsgi_instance *ui;
struct uwsgi_instance *emperor_get(char *name) {
struct uwsgi_instance *c_ui = ui;
while(c_ui->ui_next) {
while (c_ui->ui_next) {
c_ui = c_ui->ui_next;
if (!strcmp(c_ui->name, name)) {
@@ -50,6 +55,10 @@ void emperor_del(struct uwsgi_instance *c_ui) {
// this will destroy the whole uWSGI instance (and workers)
close(c_ui->pipe[0]);
if (c_ui->use_config) {
close(c_ui->pipe_config[0]);
}
uwsgi_log("removed uwsgi instance %s\n", c_ui->name);
free(c_ui);
@@ -71,32 +80,45 @@ void emperor_stop(struct uwsgi_instance *c_ui) {
void emperor_respawn(struct uwsgi_instance *c_ui, time_t mod) {
// reload the uWSGI instance
if (write(c_ui->pipe[0], "\1", 1) != 1) {
uwsgi_error("write()");
}
if (c_ui->use_config) {
if (write(c_ui->pipe[0], "\0", 1) != 1) {
uwsgi_error("write()");
}
}
else {
if (write(c_ui->pipe[0], "\1", 1) != 1) {
uwsgi_error("write()");
}
}
c_ui->respawns++;
c_ui->respawns++;
c_ui->last_mod = mod;
uwsgi_log("reload the uwsgi instance %s\n", c_ui->name);
uwsgi_log("reload the uwsgi instance %s\n", c_ui->name);
}
void emperor_add(char *name, time_t born) {
void emperor_add(char *name, time_t born, char *config, uint32_t config_size) {
struct uwsgi_instance *c_ui = ui;
struct uwsgi_instance *n_ui = NULL;
pid_t pid ;
pid_t pid;
char *argv[4];
char *uef ;
char *uef;
char **uenvs;
while(c_ui->ui_next) {
c_ui = c_ui->ui_next;
}
while (c_ui->ui_next) {
c_ui = c_ui->ui_next;
}
n_ui = uwsgi_malloc(sizeof(struct uwsgi_instance));
memset(n_ui, 0, sizeof(struct uwsgi_instance));
if (config) {
n_ui->use_config = 1;
n_ui->config = config;
n_ui->config_len = config_size;
}
c_ui->ui_next = n_ui;
uwsgi_log("c_ui->ui_next = %p\n", c_ui->ui_next);
n_ui->ui_prev = c_ui;
@@ -109,6 +131,13 @@ void emperor_add(char *name, time_t born) {
goto clear;
}
if (n_ui->use_config) {
if (socketpair(AF_UNIX, SOCK_STREAM, 0, n_ui->pipe_config)) {
uwsgi_error("socketpair()");
goto clear;
}
}
// a new uWSGI instance will start
pid = fork();
if (pid < 0) {
@@ -118,6 +147,16 @@ void emperor_add(char *name, time_t born) {
n_ui->pid = pid;
// close the right side of the pipe
close(n_ui->pipe[1]);
if (n_ui->use_config) {
close(n_ui->pipe_config[1]);
}
if (n_ui->use_config) {
if (write(n_ui->pipe_config[0], n_ui->config, n_ui->config_len) <= 0) {
uwsgi_error("write()");
}
close(n_ui->pipe_config[0]);
}
return;
}
else {
@@ -131,10 +170,19 @@ void emperor_add(char *name, time_t born) {
}
free(uef);
if (n_ui->use_config) {
uef = uwsgi_num2str(n_ui->pipe_config[1]);
if (setenv("UWSGI_EMPEROR_FD_CONFIG", uef, 1)) {
uwsgi_error("setenv()");
exit(1);
}
free(uef);
}
uenvs = environ;
while(*uenvs) {
while (*uenvs) {
if (!strncmp(*uenvs, "UWSGI_VASSAL_", 13)) {
char *ne = uwsgi_concat2("UWSGI_", *uenvs+13);
char *ne = uwsgi_concat2("UWSGI_", *uenvs + 13);
char *oe = uwsgi_concat2n(*uenvs, strchr(*uenvs, '=') - *uenvs, "", 0);
if (unsetenv(oe)) {
uwsgi_error("unsetenv()");
@@ -156,13 +204,21 @@ void emperor_add(char *name, time_t born) {
// close the left side of the pipe
close(n_ui->pipe[0]);
if (n_ui->use_config) {
close(n_ui->pipe_config[0]);
}
// set args
argv[0] = uwsgi.binary_path;
if (!strcmp(name+(strlen(name)-4), ".xml")) argv[1] = "--xml";
if (!strcmp(name+(strlen(name)-4), ".ini")) argv[1] = "--ini";
if (!strcmp(name+(strlen(name)-4), ".yml")) argv[1] = "--yaml";
if (!strcmp(name+(strlen(name)-5), ".yaml")) argv[1] = "--yaml";
if (!strcmp(name + (strlen(name) - 4), ".xml"))
argv[1] = "--xml";
if (!strcmp(name + (strlen(name) - 4), ".ini"))
argv[1] = "--ini";
if (!strcmp(name + (strlen(name) - 4), ".yml"))
argv[1] = "--yaml";
if (!strcmp(name + (strlen(name) - 5), ".yaml"))
argv[1] = "--yaml";
argv[2] = name;
argv[3] = NULL;
// start !!!
@@ -173,7 +229,7 @@ void emperor_add(char *name, time_t born) {
exit(1);
}
clear:
clear:
free(n_ui);
c_ui->ui_next = NULL;
@@ -196,28 +252,54 @@ void emperor_loop() {
glob_t g;
int i;
struct dirent *de;
char *amqp_port;
int amqp_fd = -1;
char *amqp_routing_key;
signal(SIGPIPE, SIG_IGN);
memset(&ui_base, 0, sizeof(struct uwsgi_instance));
uwsgi_log("*** starting uWSGI Emperor ***\n");
if (!glob(uwsgi.emperor_dir, GLOB_MARK, NULL, &g)) {
if (g.gl_pathc == 1 && g.gl_pathv[0][strlen(g.gl_pathv[0])-1] == '/' ) {
simple_mode = 1;
if (chdir(uwsgi.emperor_dir)) {
uwsgi_error("chdir()");
exit(1);
amqp_port = strchr(uwsgi.emperor_dir, ':');
if (amqp_port) {
reconnect:
while(amqp_fd == -1) {
uwsgi_log("connecting to AMQP server...\n");
amqp_fd = uwsgi_connect(uwsgi.emperor_dir, -1, 0);
if (amqp_fd < 0) {
sleep(1);
}
}
uwsgi_log("subscribing to queue...\n");
if (uwsgi_amqp_consume_queue(amqp_fd, "/", "", "uwsgi.emperor", "fanout") < 0) {
close(amqp_fd);
amqp_fd = -1;
goto reconnect;
}
}
else {
uwsgi_error("glob()");
exit(1);
if (!glob(uwsgi.emperor_dir, GLOB_MARK, NULL, &g)) {
if (g.gl_pathc == 1 && g.gl_pathv[0][strlen(g.gl_pathv[0]) - 1] == '/') {
simple_mode = 1;
if (chdir(uwsgi.emperor_dir)) {
uwsgi_error("chdir()");
exit(1);
}
}
}
else {
uwsgi_error("glob()");
exit(1);
}
}
ui = &ui_base;
for(;;) {
for (;;) {
if (!i_am_alone) {
@@ -227,22 +309,95 @@ void emperor_loop() {
}
}
if (simple_mode) {
if (amqp_fd > -1) {
uint64_t msgsize;
if (uwsgi_waitfd(amqp_fd, 3)) {
char *config = uwsgi_amqp_consume(amqp_fd, &msgsize, &amqp_routing_key);
if (!config) {
uwsgi_log("problem with RabbitMQ server, trying reconnection...\n");
close(amqp_fd);
amqp_fd = -1;
goto reconnect;
}
if (amqp_routing_key) {
uwsgi_log("AMQP routing_key = %s\n", amqp_routing_key);
char *config_file = uwsgi_concat2("emperor://", amqp_routing_key);
free(amqp_routing_key);
ui_current = emperor_get(config_file);
if (ui_current) {
free(ui_current->config);
ui_current->config = config;
ui_current->config_len = msgsize;
if (!msgsize) {
emperor_del(ui_current);
}
else {
emperor_respawn(ui_current, time(NULL));
}
}
else {
if (msgsize > 0) {
emperor_add(config_file, time(NULL), config, msgsize);
}
}
free(config_file);
}
else {
if (msgsize) {
if (msgsize >= 0xff) { free(config); continue; }
uwsgi_log("%.*s\n", (int)msgsize, config);
char *config_file = uwsgi_concat2n(config, msgsize, "", 0);
free(config);
if (strncmp(config_file, "http://", 7)) {
if (stat(config_file, &st)) {
free(config_file);
continue;
}
if (!S_ISREG(st.st_mode)) {
free(config_file);
continue;
}
}
ui_current = emperor_get(config_file);
if (ui_current) {
emperor_respawn(ui_current, time(NULL));
}
else {
emperor_add(config_file, time(NULL), NULL, 0);
}
free(config_file);
}
}
}
}
else if (simple_mode) {
DIR *dir = opendir(".");
while((de = readdir(dir)) != NULL) {
if (!strcmp(de->d_name+(strlen(de->d_name)-4), ".xml") ||
!strcmp(de->d_name+(strlen(de->d_name)-4), ".ini") ||
!strcmp(de->d_name+(strlen(de->d_name)-4), ".yml") ||
!strcmp(de->d_name+(strlen(de->d_name)-5), ".yaml")
while ((de = readdir(dir)) != NULL) {
if (!strcmp(de->d_name + (strlen(de->d_name) - 4), ".xml") || !strcmp(de->d_name + (strlen(de->d_name) - 4), ".ini") || !strcmp(de->d_name + (strlen(de->d_name) - 4), ".yml") || !strcmp(de->d_name + (strlen(de->d_name) - 5), ".yaml")
) {
if (strlen(de->d_name) >= 0xff) continue;
if (stat(de->d_name, &st)) continue;
if (strlen(de->d_name) >= 0xff)
continue;
if (stat(de->d_name, &st))
continue;
if (!S_ISREG(st.st_mode))
continue;
if (!S_ISREG(st.st_mode)) continue;
ui_current = emperor_get(de->d_name);
if (ui_current) {
@@ -252,7 +407,7 @@ void emperor_loop() {
}
}
else {
emperor_add(de->d_name, st.st_mtime);
emperor_add(de->d_name, st.st_mtime, NULL, 0);
}
}
}
@@ -264,33 +419,36 @@ void emperor_loop() {
continue;
}
for(i=0;i<(int)g.gl_pathc;i++) {
if (!strcmp(g.gl_pathv[i]+(strlen(g.gl_pathv[i])-4), ".xml") ||
!strcmp(g.gl_pathv[i]+(strlen(g.gl_pathv[i])-4), ".ini") ||
!strcmp(g.gl_pathv[i]+(strlen(g.gl_pathv[i])-4), ".yml") ||
!strcmp(g.gl_pathv[i]+(strlen(g.gl_pathv[i])-5), ".yaml")
) {
for (i = 0; i < (int) g.gl_pathc; i++) {
if (!strcmp(g.gl_pathv[i] + (strlen(g.gl_pathv[i]) - 4), ".xml") ||
!strcmp(g.gl_pathv[i] + (strlen(g.gl_pathv[i]) - 4), ".ini") ||
!strcmp(g.gl_pathv[i] + (strlen(g.gl_pathv[i]) - 4), ".yml") ||
!strcmp(g.gl_pathv[i] + (strlen(g.gl_pathv[i]) - 5), ".yaml")
) {
if (strlen(g.gl_pathv[i]) >= 0xff) continue;
if (strlen(g.gl_pathv[i]) >= 0xff)
continue;
if (stat(g.gl_pathv[i], &st)) continue;
if (stat(g.gl_pathv[i], &st))
continue;
if (!S_ISREG(st.st_mode)) continue;
if (!S_ISREG(st.st_mode))
continue;
ui_current = emperor_get(g.gl_pathv[i]);
ui_current = emperor_get(g.gl_pathv[i]);
if (ui_current) {
// check if mtime is changed and the uWSGI instance must be reloaded
if (st.st_mtime > ui_current->last_mod) {
emperor_respawn(ui_current, st.st_mtime);
}
}
else {
emperor_add(g.gl_pathv[i], st.st_mtime, NULL, 0);
}
}
if (ui_current) {
// check if mtime is changed and the uWSGI instance must be reloaded
if (st.st_mtime > ui_current->last_mod) {
emperor_respawn(ui_current, st.st_mtime);
}
}
else {
emperor_add(g.gl_pathv[i], st.st_mtime);
}
}
}
}
@@ -298,8 +456,8 @@ void emperor_loop() {
ui_current = ui;
has_children = 0;
while(ui_current->ui_next) {
ui_current = ui_current->ui_next;
while (ui_current->ui_next) {
ui_current = ui_current->ui_next;
has_children++;
}
@@ -307,42 +465,48 @@ void emperor_loop() {
diedpid = waitpid(WAIT_ANY, &waitpid_status, WNOHANG);
}
else {
// vacuum
waitpid(WAIT_ANY, &waitpid_status, WNOHANG);
diedpid = 0;
}
if (diedpid < 0) {
uwsgi_error("waitpid()");
}
ui_current = ui;
while(ui_current->ui_next) {
ui_current = ui_current->ui_next;
if (ui_current->pid == diedpid) {
while (ui_current->ui_next) {
ui_current = ui_current->ui_next;
if (ui_current->status == 1) {
if (ui_current->config) free(ui_current->config);
emperor_del(ui_current);
break;
}
else if (!ui_current->use_config && strncmp(ui_current->name, "http://",7) && stat(ui_current->name, &st)) {
emperor_stop(ui_current);
}
else if (ui_current->pid == diedpid) {
if (ui_current->status == 0) {
// respawn an accidentally dead instance
emperor_add(ui_current->name, ui_current->last_mod);
emperor_del(ui_current);
// respawn an accidentally dead instance if its exit code is not UWSGI_EXILE_CODE
if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_EXILE_CODE) {
emperor_del(ui_current);
}
else {
emperor_add(ui_current->name, ui_current->last_mod, ui_current->config, ui_current->config_len);
emperor_del(ui_current);
}
break;
}
else if (ui_current->status == 1) {
// remove 'marked for dead' instance
if (ui_current->config) free(ui_current->config);
emperor_del(ui_current);
break;
}
}
else if (ui_current->status == 1) {
emperor_del(ui_current);
break;
}
else if (stat(ui_current->name, &st)) {
emperor_stop(ui_current);
}
}
}
if (amqp_fd < 0)
sleep(3);
}
}
+799
View File
@@ -0,0 +1,799 @@
#include "../uwsgi.h"
#define AMQP_CONNECTION_HEADER "AMQP\0\0\x09\x01"
#ifdef __BIG_ENDIAN__
#define ntohll(x) x
#else
#define ntohll(x) ( ( (uint64_t)(ntohl( (uint32_t)((x << 32) >> 32) )) << 32) | ntohl( ((uint32_t)(x >> 32)) ) )
#endif
#define htonll(x) ntohll(x)
#define amqp_send(a, b, c) if (send(a, b, c, 0) < 0) { uwsgi_error("send()"); return -1; }
struct amqp_frame_header {
char type;
uint16_t channel;
uint32_t size;
} __attribute__((__packed__));
struct amqp_frame_method {
uint16_t class_id;
uint16_t method_id;
} __attribute__((__packed__));
static char *amqp_simple_get_frame(int, struct amqp_frame_header *);
static char *amqp_get_method(int, uint16_t, uint16_t, uint32_t *);
/*
static char *amqp_get_longstr(char *ptr, char *watermark) {
uint32_t longstr_size;
if (ptr+4 > watermark) return NULL;
memcpy(&longstr_size, ptr, 4);
longstr_size = ntohl(longstr_size);
if (ptr+4+longstr_size > watermark) return NULL;
return ptr+4+longstr_size;
}
*/
static char *amqp_get_str(char *ptr, char *watermark) {
uint8_t str_size;
// over engeneering...
if (ptr+1 > watermark) return NULL;
str_size = *ptr;
if (ptr+1+str_size > watermark) return NULL;
return ptr+1+str_size;
}
/*
static char *amqp_get_table(char *ptr, char *watermark) {
uint32_t table_size;
if (ptr+4 > watermark) return NULL;
memcpy(&table_size, ptr, 4);
table_size = ntohl(table_size);
if (ptr+4+table_size > watermark) return NULL;
return ptr+4+table_size;
}
*/
static char *amqp_get_short(char *ptr, char *watermark, uint16_t *sv) {
uint16_t tmp_short;
if (ptr+2 > watermark) return NULL;
memcpy(&tmp_short, ptr, 2);
*sv = ntohs(tmp_short);
return ptr+2;
}
static char *amqp_get_long(char *ptr, char *watermark, uint32_t *lv) {
uint32_t tmp_long;
if (ptr+4 > watermark) return NULL;
memcpy(&tmp_long, ptr, 4);
*lv = ntohl(tmp_long);
return ptr+4;
}
static char *amqp_get_longlong(char *ptr, char *watermark, uint64_t *llv) {
uint64_t tmp_longlong;
if (ptr+8 > watermark) return NULL;
memcpy(&tmp_longlong, ptr, 8);
*llv = ntohll(tmp_longlong);
return ptr+8;
}
static int amqp_send_ack(int fd, uint64_t delivery_tag) {
uint32_t size = 4 + 8 + 1;
size = htonl(size);
// send type and channel
amqp_send(fd, "\1\0\1", 3);
// send size
amqp_send(fd, &size, 4);
// send class 60 method 80
amqp_send(fd, "\x00\x3C\x00\x50", 4);
// set delivery_tag
delivery_tag = htonll(delivery_tag);
amqp_send(fd, &delivery_tag, 8);
// empty bits
amqp_send(fd, "\0", 1);
// send frame-end
amqp_send(fd, "\xCE", 1);
return 0;
}
char *uwsgi_amqp_consume(int fd, uint64_t *msgsize, char **routing_key) {
uint32_t size;
struct amqp_frame_header fh;
uint64_t delivery_tag;
uint64_t current_size = 0;
char *ptr;
char *watermark;
uint16_t sv;
char *frame = amqp_get_method(fd, 60, 60, &size);
if (!frame) return NULL;
ptr = frame+4;
watermark = frame+size;
// consumer_tag
ptr = amqp_get_str(ptr, watermark); if (!ptr) goto clear;
// delivery_tag (needed for ack)
ptr = amqp_get_longlong(ptr, watermark, &delivery_tag); if (!ptr) goto clear;
// redelivered
if (ptr+1 > watermark) goto clear;
ptr++;
// exchange
ptr = amqp_get_str(ptr, watermark); if (!ptr) goto clear;
// routing_key
if (ptr+1 > watermark) goto clear;
uint8_t rk_size = (uint8_t) *ptr;
ptr++;
if (ptr+rk_size > watermark) goto clear;
if (rk_size > 0) {
char *rkey = uwsgi_concat2n(ptr, rk_size, "", 0);
ptr+=rk_size;
*routing_key = rkey;
}
else {
*routing_key = NULL;
}
char *header = amqp_simple_get_frame(fd, &fh);
if (!header) goto clear;
if (fh.type != 2) goto clear2;
ptr = header;
watermark = ptr+fh.size;
// header class_id
ptr = amqp_get_short(ptr, watermark, &sv); if (!ptr) goto clear2;
// header weight
ptr = amqp_get_short(ptr, watermark, &sv); if (!ptr) goto clear2;
// message size;
ptr = amqp_get_longlong(ptr, watermark, msgsize); if (!ptr) goto clear2;
free(frame);
free(header);
char *fullbody = uwsgi_malloc(*msgsize);
char *message;
while(current_size < *msgsize) {
message = amqp_simple_get_frame(fd, &fh);
if (!message) goto clear;
if (fh.type != 3) {
free(message);
goto clear3;
}
if (fh.size+current_size > *msgsize) {
free(message);
goto clear3;
}
memcpy(fullbody+current_size, message, fh.size);
current_size+=fh.size;
free(message);
}
if (amqp_send_ack(fd, delivery_tag) < 0) {
goto clear3;
}
return fullbody;
clear3:
free(fullbody);
return NULL;
clear2:
free(header);
clear:
free(frame);
return NULL;
}
static int amqp_send_exchange_declare( int fd, char *exchange, char *exchange_type) {
uint32_t size = 4 + 2 + (1 +strlen(exchange)) + (1 +strlen(exchange_type)) + 1 + 4;
uint8_t shortsize = strlen(exchange) ;
size = htonl(size);
// send type and channel
amqp_send(fd, "\1\0\1", 3);
// send size
amqp_send(fd, &size, 4);
// send class 40 method 10
amqp_send(fd, "\x00\x28\x00\x0A", 4);
// send empty reserved
amqp_send(fd, "\0\0", 2);
// set exchange name
amqp_send(fd, &shortsize, 1);
amqp_send(fd, exchange, shortsize);
// set exchange type
shortsize = strlen(exchange_type);
amqp_send(fd, &shortsize, 1);
amqp_send(fd, exchange_type, shortsize);
// empty bits
amqp_send(fd, "\0", 1);
// empty table
amqp_send(fd, "\0\0\0\0", 4);
// send frame-end
amqp_send(fd, "\xCE", 1);
return 0;
}
static int amqp_send_queue_bind( int fd, char *queue, char *exchange) {
uint32_t size = 4 + 2 + (1 +strlen(queue)) + (1 +strlen(exchange)) + 1 + 1 + 4;
uint8_t shortsize = strlen(queue) ;
size = htonl(size);
// send type and channel
amqp_send(fd, "\1\0\1", 3);
// send size
amqp_send(fd, &size, 4);
// send class 50 method 20
amqp_send(fd, "\x00\x32\x00\x14", 4);
// send empty reserved
amqp_send(fd, "\0\0", 2);
// set queue name
amqp_send(fd, &shortsize, 1);
amqp_send(fd, queue, shortsize);
// set exchange name
shortsize = strlen(exchange);
amqp_send(fd, &shortsize, 1);
amqp_send(fd, exchange, shortsize);
// set empty routing-key
amqp_send(fd, "\0", 1);
// empty bits
amqp_send(fd, "\0", 1);
// empty table
amqp_send(fd, "\0\0\0\0", 4);
// send frame-end
amqp_send(fd, "\xCE", 1);
return 0;
}
static int amqp_send_queue_consume( int fd, char *queue) {
uint32_t size = 4 + 2 + (1 +strlen(queue)) + 1 + 1 + 4;
uint8_t shortsize = strlen(queue) ;
size = htonl(size);
// send type and channel
amqp_send(fd, "\1\0\1", 3);
// send size
amqp_send(fd, &size, 4);
// send class 60 method 20
amqp_send(fd, "\x00\x3C\x00\x14", 4);
// send empty reserved
amqp_send(fd, "\0\0", 2);
// set queue name
amqp_send(fd, &shortsize, 1);
amqp_send(fd, queue, shortsize);
// set tag name
amqp_send(fd, "\0", 1);
// empty bits
amqp_send(fd, "\0", 1);
// empty table
amqp_send(fd, "\0\0\0\0", 4);
// send frame-end
amqp_send(fd, "\xCE", 1);
return 0;
}
static int amqp_wait_connection_start(int fd) {
uint32_t size;
char *frame = amqp_get_method(fd, 10, 10, &size);
if (frame) {
free(frame);
return 0;
}
return -1;
}
static int amqp_wait_exchange_declare_ok(int fd) {
uint32_t size;
char *frame = amqp_get_method(fd, 40, 11, &size);
if (frame) {
free(frame);
return 0;
}
return -1;
}
static int amqp_wait_basic_consume_ok(int fd) {
uint32_t size;
char *frame = amqp_get_method(fd, 60, 21, &size);
if (frame) {
free(frame);
return 0;
}
return -1;
}
static int amqp_wait_channel_open_ok(int fd) {
uint32_t size;
char *frame = amqp_get_method(fd, 20, 11, &size);
if (frame) {
free(frame);
return 0;
}
return -1;
}
static int amqp_wait_queue_bind_ok(int fd) {
uint32_t size;
char *frame = amqp_get_method(fd, 50, 21, &size);
if (frame) {
free(frame);
return 0;
}
return -1;
}
static char *amqp_wait_queue_declare_ok(int fd) {
uint32_t size;
char *frame = amqp_get_method(fd, 50, 11, &size);
char *queue = NULL;
char *ptr;
char *watermark;
if (frame) {
ptr = frame+4;
watermark = frame+size;
ptr = amqp_get_str(ptr, watermark); if (!ptr) { free(frame); return NULL; }
queue = uwsgi_concat2n(frame+5, *(frame+4), "", 0);
free(frame);
return queue;
}
return NULL;
}
static int amqp_wait_connection_open_ok(int fd) {
uint32_t size;
char *frame = amqp_get_method(fd, 10, 41, &size);
if (frame) {
free(frame);
return 0;
}
return -1;
}
static int amqp_wait_connection_tune(int fd) {
uint32_t size;
char *frame = amqp_get_method(fd, 10, 30, &size);
uint16_t sv;
uint32_t lv;
char *watermark ;
char *ptr;
if (frame) {
ptr = frame+4;
watermark = frame+size;
ptr = amqp_get_short(ptr, watermark, &sv); if (!ptr) { free(frame); return -1; }
uwsgi_log("AMQP max channels: %d\n", sv);
ptr = amqp_get_long(ptr, watermark, &lv); if (!ptr) { free(frame); return -1; }
uwsgi_log("AMQP max frame size: %d\n", lv);
ptr = amqp_get_short(ptr, watermark, &sv); if (!ptr) { free(frame); return -1; }
uwsgi_log("AMQP heartbeath: %d\n", sv);
free(frame);
return 0;
}
return -1;
}
static char *amqp_simple_get_frame(int fd, struct amqp_frame_header *fh) {
char *ptr = (char *) fh;
size_t len = 0, rlen;
while(len < 7) {
rlen = recv(fd, ptr, 7-len, 0);
if (rlen <= 0) {
uwsgi_error("recv()");
return NULL;
}
len += rlen;
ptr += rlen;
}
fh->channel = ntohs(fh->channel);
fh->size = ntohl(fh->size);
len = 0;
char *frame = malloc(fh->size+1);
ptr = frame;
while(len < fh->size+1) {
rlen = recv(fd, ptr, (fh->size+1)-len, 0);
if (rlen <= 0) {
uwsgi_error("recv()");
return NULL;
}
len += rlen;
ptr += rlen;
}
return frame;
}
static char *amqp_get_method(int fd, uint16_t class_id, uint16_t method_id, uint32_t *size) {
struct amqp_frame_header fh;
struct amqp_frame_method *fm;
char *frame = amqp_simple_get_frame(fd, &fh);
if (!frame) return NULL;
if (fh.type != 1) goto clear;
fm = (struct amqp_frame_method *) frame;
fm->class_id = ntohs(fm->class_id);
fm->method_id = ntohs(fm->method_id);
if (fm->class_id != class_id) goto clear;
if (fm->method_id != method_id) goto clear;
*size = fh.size;
return frame;
clear:
free(frame);
return NULL;
}
static int amqp_send_channel_open(int fd, uint16_t id) {
uint32_t size = 4 + 1;
size = htonl(size);
// send type and channel
amqp_send(fd, "\1\0\1", 3);
// send size
amqp_send(fd, &size, 4);
// send class 20 method 10
amqp_send(fd, "\x00\x14\x00\x0A", 4);
amqp_send(fd, "\0", 1);
// send frame-end
amqp_send(fd, "\xCE", 1);
return 0;
}
int amqp_send_connection_open(int fd, char *vhost) {
uint8_t shortsize = strlen(vhost);
uint32_t size = 4 + 1 +strlen(vhost) + 2;
size = htonl(size);
// send type and channel
amqp_send(fd, "\1\0\0", 3);
// send size
amqp_send(fd, &size, 4);
// send class 10 method 28
amqp_send(fd, "\x00\x0A\x00\x28", 4);
amqp_send(fd, &shortsize, 1);
amqp_send(fd, vhost, strlen(vhost));
shortsize = 0;
amqp_send(fd, &shortsize, 1);
amqp_send(fd, &shortsize, 1);
// send frame-end
amqp_send(fd, "\xCE", 1);
return 0;
}
int amqp_send_connection_tune_ok(int fd, uint16_t max_chan, uint32_t max_frame_size, uint16_t heartbeat) {
uint32_t size = 4 + 2 + 4 + 2;
size = htonl(size);
max_chan = htons(max_chan);
max_frame_size = htonl(max_frame_size);
heartbeat = htons(heartbeat);
// send type and channel
amqp_send(fd, "\1\0\0", 3);
// send size
amqp_send(fd, &size, 4);
// send class 10 method 15
amqp_send(fd, "\x00\x0A\x00\x1F", 4);
amqp_send(fd, &max_chan, 2);
amqp_send(fd, &max_frame_size, 4);
amqp_send(fd, &heartbeat, 2);
// send frame-end
amqp_send(fd, "\xCE", 1);
return 0;
}
static int amqp_send_queue_declare(int fd, char *queue) {
uint32_t size = 4 + 2 + (1 +strlen(queue)) + 1 + 4;
uint8_t shortsize = strlen(queue) ;
size = htonl(size);
// send type and channel
amqp_send(fd, "\1\0\1", 3);
// send size
amqp_send(fd, &size, 4);
// send class 50 method 10
amqp_send(fd, "\x00\x32\x00\x0A", 4);
// send empty reserved
amqp_send(fd, "\0\0", 2);
// set queue name
amqp_send(fd, &shortsize, 1);
amqp_send(fd, queue, shortsize);
// empty bits
amqp_send(fd, "\0", 1);
// empty table
amqp_send(fd, "\0\0\0\0", 4);
// send frame-end
amqp_send(fd, "\xCE", 1);
return 0;
}
static char *amqp_get_queue(int fd, char *queue) {
if (amqp_send_queue_declare(fd, queue) < 0) {
return NULL;
}
return amqp_wait_queue_declare_ok(fd);
}
static int amqp_send_connection_start_ok(int fd, char *mech, char *sasl_response, int sasl_response_size, char *locale) {
uint32_t size = 4 + 4 + (1 +strlen(mech)) + (4 + sasl_response_size) + (1 + strlen(locale));
uint8_t shortsize ;
size = htonl(size);
// send type and channel
amqp_send(fd, "\1\0\0", 3);
// send size
amqp_send(fd, &size, 4);
// send class 10 method 11
amqp_send(fd, "\x00\x0A\x00\x0B", 4);
// send empty client properties
amqp_send(fd, "\0\0\0\0", 4);
// send mechanism short string
shortsize = strlen(mech);
amqp_send(fd, &shortsize, 1);
amqp_send(fd, mech, strlen(mech));
// send sasl response
size = htonl(sasl_response_size);
amqp_send(fd, &size, 4);
amqp_send(fd, sasl_response, sasl_response_size);
// send locale
shortsize = strlen(locale);
amqp_send(fd, &shortsize, 1);
amqp_send(fd, locale, strlen(locale));
// send frame-end
amqp_send(fd, "\xCE", 1);
return 0;
}
int uwsgi_amqp_consume_queue(int fd, char *vhost, char *queue, char *exchange, char *exchange_type) {
if (send(fd, AMQP_CONNECTION_HEADER, 8, 0) < 0) {
uwsgi_error("send()");
return -1;
}
if (amqp_wait_connection_start(fd) < 0) {
uwsgi_log("AMQP error waiting for Connection.start\n");
return -1;
}
uwsgi_log("sending Connection.start-ok\n");
if (amqp_send_connection_start_ok(fd, "PLAIN", "\0guest\0guest", 12, "en_US") < 0) {
uwsgi_log("AMQP error sending Connection.start-ok\n");
return -1;
}
if (amqp_wait_connection_tune(fd) < 0) {
uwsgi_log("AMQP error waiting for Connection.tune\n");
return -1;
}
uwsgi_log("sending Connection.tune-ok\n");
if (amqp_send_connection_tune_ok(fd, 0, 0xffff, 0) < 0) {
uwsgi_log("AMQP error sending Connection.tune-ok\n");
return -1;
}
uwsgi_log("sending Connection.open\n");
if (amqp_send_connection_open(fd, vhost) < 0) {
uwsgi_log("AMQP error sending Connection.open\n");
return -1;
}
if (amqp_wait_connection_open_ok(fd) < 0) {
uwsgi_log("AMQP error waiting for Connection.open-ok\n");
return -1;
}
uwsgi_log("sending Channel.open\n");
if (amqp_send_channel_open(fd, 1) < 0) {
uwsgi_log("AMQP error sending Channel.open\n");
return -1;
}
if (amqp_wait_channel_open_ok(fd) < 0) {
uwsgi_log("AMQP error waiting for Channel.open-ok\n");
return -1;
}
queue = amqp_get_queue(fd, queue);
if (!queue) {
uwsgi_log("AMQP error sending Queue.declare\n");
return -1;
}
if (exchange) {
if (amqp_send_exchange_declare(fd, exchange, exchange_type) < 0) {
uwsgi_log("AMQP error sending Exchange.declare\n");
free(queue);
return -1;
}
if (amqp_wait_exchange_declare_ok(fd) < 0) {
uwsgi_log("AMQP error waiting for Exchange.declare-ok\n");
free(queue);
return -1;
}
if (amqp_send_queue_bind(fd, queue, exchange) < 0) {
uwsgi_log("AMQP error sending Queue.bind\n");
free(queue);
return -1;
}
if (amqp_wait_queue_bind_ok(fd) < 0) {
uwsgi_log("AMQP error waiting for Queue.bind-ok\n");
free(queue);
return -1;
}
}
if (amqp_send_queue_consume(fd, queue) < 0) {
uwsgi_log("AMQP error sending Basic.consume\n");
free(queue);
return -1;
}
if (amqp_wait_basic_consume_ok(fd) < 0) {
uwsgi_log("AMQP error waiting for Basic.consume-ok\n");
free(queue);
return -1;
}
free(queue);
return 0;
}
+379
View File
@@ -0,0 +1,379 @@
#include "../uwsgi.h"
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <net/if.h>
#define NLMSG_TAIL(nmsg) \
((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
#ifndef VETH_INFO_PEER
# define VETH_INFO_PEER 1
#endif
struct uwsgi_nl_req {
struct nlmsghdr nlmsg;
struct ifinfomsg ifinfomsg;
};
struct uwsgi_nl_ipreq {
struct nlmsghdr nlmsg;
struct ifaddrmsg ifaddrmsg;
};
struct uwsgi_nl_rtreq {
struct nlmsghdr nlmsg;
struct rtmsg rtmsg;
};
int uwsgi_nl_send(struct nlmsghdr *);
struct nlmsghdr *uwsgi_netlink_alloc() {
size_t len = NLMSG_ALIGN(8192) + NLMSG_ALIGN(sizeof(struct nlmsghdr *));
struct nlmsghdr *nlmsg = (struct nlmsghdr *) uwsgi_malloc(len);
memset(nlmsg, 0, len);
struct uwsgi_nl_req *unr = (struct uwsgi_nl_req *)nlmsg;
unr->ifinfomsg.ifi_family = AF_UNSPEC;
nlmsg->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
nlmsg->nlmsg_type = RTM_NEWLINK;
nlmsg->nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
return nlmsg;
}
struct nlmsghdr *uwsgi_netlink_ip_alloc() {
size_t len = NLMSG_ALIGN(8192) + NLMSG_ALIGN(sizeof(struct nlmsghdr *));
struct nlmsghdr *nlmsg = (struct nlmsghdr *) uwsgi_malloc(len);
memset(nlmsg, 0, len);
struct uwsgi_nl_ipreq *uni = (struct uwsgi_nl_ipreq *)nlmsg;
uni->ifaddrmsg.ifa_family = AF_INET;
uni->ifaddrmsg.ifa_scope = 0;
nlmsg->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
nlmsg->nlmsg_type = RTM_NEWADDR;
nlmsg->nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK|NLM_F_CREATE|NLM_F_EXCL;
return nlmsg;
}
struct nlmsghdr *uwsgi_netlink_rt_alloc() {
size_t len = NLMSG_ALIGN(8192) + NLMSG_ALIGN(sizeof(struct nlmsghdr *));
struct nlmsghdr *nlmsg = (struct nlmsghdr *) uwsgi_malloc(len);
memset(nlmsg, 0, len);
struct uwsgi_nl_rtreq *unr = (struct uwsgi_nl_rtreq *)nlmsg;
unr->rtmsg.rtm_family = AF_INET;
unr->rtmsg.rtm_table = RT_TABLE_MAIN;
unr->rtmsg.rtm_protocol = RTPROT_STATIC;
unr->rtmsg.rtm_scope = RT_SCOPE_UNIVERSE;
unr->rtmsg.rtm_type = RTN_UNICAST;
nlmsg->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
nlmsg->nlmsg_type = RTM_NEWROUTE;
nlmsg->nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK|NLM_F_CREATE|NLM_F_EXCL;
return nlmsg;
}
int uwsgi_netlink_rt(char *src, char *dst, int dst_prefix, char *gw) {
struct nlmsghdr *nlmsg = uwsgi_netlink_rt_alloc();
struct rtattr *rta;
struct in_addr ia;
struct in_addr oa;
struct in_addr ga;
struct uwsgi_nl_rtreq *unr = (struct uwsgi_nl_rtreq *)nlmsg;
if (inet_pton(AF_INET, src, &ia) <= 0) {
uwsgi_error("inet_pton()");
free(nlmsg);
return -1;
}
if (inet_pton(AF_INET, dst, &oa) <= 0) {
uwsgi_error("inet_pton()");
free(nlmsg);
return -1;
}
if (inet_pton(AF_INET, gw, &ga) <= 0) {
uwsgi_error("inet_pton()");
free(nlmsg);
return -1;
}
rta = NLMSG_TAIL(nlmsg);
rta->rta_type = RTA_PREFSRC;
rta->rta_len = RTA_LENGTH(4);
memcpy(RTA_DATA(rta), &ia.s_addr, 4);
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len);
rta = NLMSG_TAIL(nlmsg);
rta->rta_type = RTA_DST;
rta->rta_len = RTA_LENGTH(4);
memcpy(RTA_DATA(rta), &oa.s_addr, 4);
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len);
rta = NLMSG_TAIL(nlmsg);
rta->rta_type = RTA_GATEWAY;
rta->rta_len = RTA_LENGTH(4);
memcpy(RTA_DATA(rta), &ga.s_addr, 4);
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len);
unr->rtmsg.rtm_src_len = 0;
unr->rtmsg.rtm_dst_len = dst_prefix;
return uwsgi_nl_send(nlmsg);
}
int uwsgi_netlink_gw(char *iface, char *ip) {
struct nlmsghdr *nlmsg = uwsgi_netlink_rt_alloc();
struct rtattr *rta;
struct in_addr ia;
uint32_t zero = 0;
int index = if_nametoindex(iface);
if (!index) return -1;
if (inet_pton(AF_INET, ip, &ia) <= 0) {
uwsgi_error("inet_pton()");
free(nlmsg);
return -1;
}
rta = NLMSG_TAIL(nlmsg);
rta->rta_type = RTA_GATEWAY;
rta->rta_len = RTA_LENGTH(4);
memcpy(RTA_DATA(rta), &ia.s_addr, 4);
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len);
rta = NLMSG_TAIL(nlmsg);
rta->rta_type = RTA_DST;
rta->rta_len = RTA_LENGTH(4);
memcpy(RTA_DATA(rta), &zero, 4);
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len);
rta = NLMSG_TAIL(nlmsg);
rta->rta_type = RTA_OIF;
rta->rta_len = RTA_LENGTH(sizeof(int));
memcpy(RTA_DATA(rta), &index, sizeof(int));
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len);
return uwsgi_nl_send(nlmsg);
}
int uwsgi_netlink_ip(char *iface, char *ip, int prefix) {
struct nlmsghdr *nlmsg = uwsgi_netlink_ip_alloc();
struct uwsgi_nl_ipreq *uni = (struct uwsgi_nl_ipreq *)nlmsg;
struct rtattr *rta;
struct in_addr ia;
int index = if_nametoindex(iface);
if (!index) return -1;
uni->ifaddrmsg.ifa_index = index;
uni->ifaddrmsg.ifa_prefixlen = prefix;
if (inet_pton(AF_INET, ip, &ia) <= 0) {
uwsgi_error("inet_pton()");
free(nlmsg);
return -1;
}
rta = NLMSG_TAIL(nlmsg);
rta->rta_type = IFA_LOCAL;
rta->rta_len = RTA_LENGTH(sizeof(struct in_addr));
memcpy(RTA_DATA(rta), &ia, sizeof(struct in_addr));
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len);
rta = NLMSG_TAIL(nlmsg);
rta->rta_type = IFA_ADDRESS;
rta->rta_len = RTA_LENGTH(sizeof(struct in_addr));
memcpy(RTA_DATA(rta), &ia, sizeof(struct in_addr));
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len);
return uwsgi_nl_send(nlmsg);
}
int uwsgi_netlink_veth_attach(char *veth1, pid_t pid) {
struct nlmsghdr *nlmsg = uwsgi_netlink_alloc();
struct uwsgi_nl_req *unr = (struct uwsgi_nl_req *)nlmsg;
struct rtattr *rta;
int index = if_nametoindex(veth1);
if (!index) return -1;
unr->ifinfomsg.ifi_index = index;
rta = NLMSG_TAIL(nlmsg);
rta->rta_type = IFLA_NET_NS_PID;
rta->rta_len = RTA_LENGTH(sizeof(pid_t));
memcpy(RTA_DATA(rta), &pid, sizeof(pid_t));
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len);
return uwsgi_nl_send(nlmsg);
}
int uwsgi_netlink_ifup(char *iface) {
struct nlmsghdr *nlmsg = uwsgi_netlink_alloc();
struct uwsgi_nl_req *unr = (struct uwsgi_nl_req *)nlmsg;
int index = if_nametoindex(iface);
if (!index) return -1;
unr->ifinfomsg.ifi_index = index;
unr->ifinfomsg.ifi_change |= IFF_UP;
unr->ifinfomsg.ifi_flags |= IFF_UP;
return uwsgi_nl_send(nlmsg);
}
int uwsgi_netlink_del(char *iface) {
struct nlmsghdr *nlmsg = uwsgi_netlink_alloc();
struct uwsgi_nl_req *unr = (struct uwsgi_nl_req *)nlmsg;
int index = if_nametoindex(iface);
if (!index) return -1;
nlmsg->nlmsg_type = RTM_DELLINK;
unr->ifinfomsg.ifi_index = index;
return uwsgi_nl_send(nlmsg);
}
int uwsgi_netlink_veth(char *veth0, char *veth1) {
struct rtattr *rta, *rta0, *rta1, *rta2;
struct nlmsghdr *nlmsg = uwsgi_netlink_alloc();
nlmsg->nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL;
// IFLA_LINKINFO
rta0 = NLMSG_TAIL(nlmsg);
rta0->rta_type = IFLA_LINKINFO;
rta0->rta_len = RTA_LENGTH(0);
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta0->rta_len);
// IFLA_INFO_KIND
rta = NLMSG_TAIL(nlmsg);
rta->rta_type = IFLA_INFO_KIND;
rta->rta_len = RTA_LENGTH(4);
memcpy(RTA_DATA(rta), "veth", 4);
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len);
// IFLA_INFO_DATA
rta1 = NLMSG_TAIL(nlmsg);
rta1->rta_type = IFLA_INFO_DATA;
rta1->rta_len = RTA_LENGTH(0);
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta1->rta_len);
// VETH_INFO_PEER
rta2 = NLMSG_TAIL(nlmsg);
rta2->rta_type = VETH_INFO_PEER;
rta2->rta_len = RTA_LENGTH(0);
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta2->rta_len);
nlmsg->nlmsg_len += sizeof(struct ifinfomsg);
// IFLA_IFNAME
rta = NLMSG_TAIL(nlmsg);
rta->rta_type = IFLA_IFNAME;
rta->rta_len = RTA_LENGTH(strlen(veth1));
memcpy(RTA_DATA(rta), veth1, strlen(veth1));
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len);
rta2->rta_len = (void *)NLMSG_TAIL(nlmsg) - (void *)rta2;
rta1->rta_len = (void *)NLMSG_TAIL(nlmsg) - (void *)rta1;
rta0->rta_len = (void *)NLMSG_TAIL(nlmsg) - (void *)rta0;
// IFLA_IFNAME
rta = NLMSG_TAIL(nlmsg);
rta->rta_type = IFLA_IFNAME;
rta->rta_len = RTA_LENGTH(strlen(veth0));
memcpy(RTA_DATA(rta), veth0, strlen(veth0));
nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len);
return uwsgi_nl_send(nlmsg);
}
int uwsgi_nl_send(struct nlmsghdr *nlmsg) {
struct sockaddr_nl nladdr;
struct iovec iov = {
.iov_base = (void*)nlmsg,
.iov_len = nlmsg->nlmsg_len,
};
struct msghdr msg = {
.msg_name = &nladdr,
.msg_namelen = sizeof(nladdr),
.msg_iov = &iov,
.msg_iovlen = 1,
};
int ret;
int nlfd;
memset(&nladdr, 0, sizeof(struct sockaddr_nl));
nladdr.nl_family = AF_NETLINK;
nladdr.nl_pid = 0;
nladdr.nl_groups = 0;
nlfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (nlfd < 0) {
uwsgi_error("socket()");
free(nlmsg);
return -1;
}
ret = sendmsg(nlfd, &msg, 0);
if (ret < 0) {
uwsgi_error("sendmsg()");
free(nlmsg);
close(nlfd);
return -1;
}
ret = recvmsg(nlfd, &msg, 0);
if (ret < 0) {
uwsgi_error("recvmsg()");
free(nlmsg);
close(nlfd);
return -1;
}
if (nlmsg->nlmsg_type == NLMSG_ERROR) {
struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(nlmsg);
ret = err->error;
}
free(nlmsg);
close(nlfd);
return ret;
}
+29
View File
@@ -0,0 +1,29 @@
/* function written by Ben Taylor (found in the qemu-devel list) */
#include "../uwsgi.h"
time_t timegm(struct tm *t) {
time_t tl, tb;
struct tm *tg;
tl = mktime (t);
if (tl == -1) {
t->tm_hour--;
tl = mktime (t);
if (tl == -1)
return -1; /* can't deal with output from strptime */
tl += 3600;
}
tg = gmtime (&tl);
tg->tm_isdst = 0;
tb = mktime (tg);
if (tb == -1) {
tg->tm_hour--;
tb = mktime (tg);
if (tb == -1)
return -1; /* can't deal with output from gmtime */
tb += 3600;
}
return (tl - (tb - tl));
}
+6 -10
View File
@@ -134,21 +134,17 @@ void uwsgi_rwunlock(void *lock) { uwsgi_unlock(lock); }
#define UWSGI_LOCK_SIZE 8
#define UWSGI_RWLOCK_SIZE 8
static int lock_counter = 0;
void uwsgi_lock_init(void *lock) {
char filename[17];
FILE *tf = tmpfile();
int fd;
if (snprintf(filename, 17, ".uwsgiflock%d", lock_counter) < 0) {
uwsgi_log("unable to create lock %d\n", lock_counter);
}
int fd = open(filename, O_CREAT|O_RDWR|O_TRUNC);
if (fd < 0) {
uwsgi_error_open(filename);
if (!tf) {
uwsgi_error_open("temp lock file");
exit(1);
}
fd = fileno(tf);
memcpy(lock, &fd, sizeof(int));
}
+4
View File
@@ -169,7 +169,11 @@ void get_memusage() {
kvm_t *kv;
int cnt;
#if defined(__FreeBSD__)
kv = kvm_open(NULL, "/dev/null", NULL, O_RDONLY, NULL);
#else
kv = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL);
#endif
if (kv) {
#if defined(__FreeBSD__) || defined(__DragonFly__)
+42 -7
View File
@@ -42,6 +42,7 @@ void uwsgi_subscribe(char *subscription) {
if (!udp_address) return;
char *subscription_key = strchr(udp_address+1, ':');
if (!subscription_key) return;
udp_address = uwsgi_concat2n(subscription, subscription_key-subscription, "", 0);
ssb = subscrbuf;
@@ -343,6 +344,18 @@ void master_loop(char **argv, char **environ) {
}
}
if (uwsgi.touch_reload) {
struct stat tr_st;
if (stat(uwsgi.touch_reload, &tr_st)) {
uwsgi_error("stat()");
uwsgi_log("unable to stat() %s, touch-reload will be disabled\n", uwsgi.touch_reload);
uwsgi.touch_reload = NULL;
}
else {
uwsgi.last_touch_reload_mtime = tr_st.st_mtime;
}
}
for (;;) {
//uwsgi_log("ready_to_reload %d %d\n", ready_to_reload, uwsgi.numproc);
@@ -394,18 +407,24 @@ void master_loop(char **argv, char **environ) {
diedpid = waitpid(WAIT_ANY, &waitpid_status, WNOHANG);
}
if (uwsgi.exit_on_reload) {
uwsgi_log("uWSGI: GAME OVER (insert coin)\n");
exit(0);
}
uwsgi_log( "binary reloading uWSGI...\n");
if (chdir(uwsgi.cwd)) {
uwsgi_error("chdir()");
exit(1);
}
/* check fd table (a module can obviosly open some fd on initialization...) */
uwsgi_log( "closing all non-uwsgi socket fds > 2 (_SC_OPEN_MAX = %ld)...\n", sysconf(_SC_OPEN_MAX));
for (i = 3; i < sysconf(_SC_OPEN_MAX); i++) {
int found = 0;
for(j=0;j<uwsgi.sockets_cnt;j++) {
if (i == uwsgi.sockets[j].fd) {
uwsgi_log("found fd %d\n", i);
uwsgi_log("found fd %d mapped to socket %d (%s)\n", i, j, uwsgi.sockets[j].name);
found = 1;
break;
}
@@ -616,8 +635,7 @@ void master_loop(char **argv, char **environ) {
// remove me
if (byte == 0) {
close(uwsgi.emperor_fd);
uwsgi.has_emperor = 0;
kill_them_all(0);
if (!uwsgi.to_hell) kill_them_all(0);
}
// reload me
else if (byte == 1) {
@@ -627,8 +645,9 @@ void master_loop(char **argv, char **environ) {
else {
uwsgi_log("lost connection with my emperor !!!\n");
close(uwsgi.emperor_fd);
uwsgi.has_emperor = 0;
kill_them_all(0);
if (!uwsgi.to_hell) kill_them_all(0);
sleep(2);
exit(1);
}
}
}
@@ -944,12 +963,14 @@ void master_loop(char **argv, char **environ) {
}
// resubscribe every 10 cycles
if (uwsgi.subscriptions_cnt > 0 && (master_cycles % 10) == 0) {
if (uwsgi.subscriptions_cnt > 0 && ((master_cycles % 10) == 0 || master_cycles == 1)) {
for(i=0;i<uwsgi.subscriptions_cnt;i++) {
uwsgi_subscribe(uwsgi.subscriptions[i]);
}
}
#endif
if (uwsgi.cache_store && uwsgi.cache_filesize && uwsgi.cache_store_sync && ((master_cycles % uwsgi.cache_store_sync) == 0)) {
if (msync(uwsgi.cache_items, uwsgi.cache_filesize, MS_ASYNC)) {
uwsgi_error("msync()");
@@ -962,8 +983,22 @@ void master_loop(char **argv, char **environ) {
}
}
// check touch_reload
if (uwsgi.touch_reload && !uwsgi.to_heaven && !uwsgi.to_hell) {
struct stat tr_st;
if (stat(uwsgi.touch_reload, &tr_st)) {
uwsgi_error("stat()");
uwsgi_log("unable to stat() %s, touch-reload will be disabled\n", uwsgi.touch_reload);
uwsgi.touch_reload = NULL;
}
else {
if (tr_st.st_mtime > uwsgi.last_touch_reload_mtime) {
uwsgi_log("*** %s has been touched... grace them all !!! ***\n");
grace_them_all(0);
}
}
}
#endif
// now check for lb pool
+53 -22
View File
@@ -2,25 +2,6 @@
extern struct uwsgi_server uwsgi;
void embed_plugins() {
#ifdef UWSGI_EMBED_PLUGIN_PSGI
if (uwsgi.plugin_arg_psgi)
uwsgi_load_plugin(5, "psgi_plugin.so", uwsgi.plugin_arg_psgi, 0);
#endif
#ifdef UWSGI_EMBED_PLUGIN_LUA
if (uwsgi.plugin_arg_lua)
uwsgi_load_plugin(6, "lua_plugin.so", uwsgi.plugin_arg_lua, 0);
#endif
#ifdef UWSGI_EMBED_PLUGIN_RACK
if (uwsgi.plugin_arg_rack)
uwsgi_load_plugin(7, "rack_plugin.so", uwsgi.plugin_arg_rack, 0);
#endif
}
int uwsgi_load_plugin(int modifier, char *plugin, char *pargs, int absolute) {
void *plugin_handle;
@@ -28,6 +9,59 @@ int uwsgi_load_plugin(int modifier, char *plugin, char *pargs, int absolute) {
char *plugin_name;
char *plugin_entry_symbol;
struct uwsgi_plugin *up;
int i;
char *colon = strchr(plugin, ':');
if (colon) {
colon[0] = 0;
}
check:
for (i = 0; i < 0xFF; i++) {
if (uwsgi.p[i]->name) {
if (!strcmp(plugin, uwsgi.p[i]->name)) {
#ifdef UWSGI_DEBUG
uwsgi_log("%s plugin already available\n", plugin);
#endif
return 0;
}
}
if (uwsgi.p[i]->alias) {
if (!strcmp(plugin, uwsgi.p[i]->alias)) {
#ifdef UWSGI_DEBUG
uwsgi_log("%s plugin already available\n", plugin);
#endif
return 0;
}
}
}
for(i=0;i<uwsgi.gp_cnt;i++) {
if (uwsgi.gp[i]->name) {
if (!strcmp(plugin, uwsgi.gp[i]->name)) {
#ifdef UWSGI_DEBUG
uwsgi_log("%s plugin already available\n", plugin);
#endif
return 0;
}
}
if (uwsgi.gp[i]->alias) {
if (!strcmp(plugin, uwsgi.gp[i]->alias)) {
#ifdef UWSGI_DEBUG
uwsgi_log("%s plugin already available\n", plugin);
#endif
return 0;
}
}
}
if (colon) {
plugin = colon+1;
colon[0] = ':';
colon = NULL;
goto check;
}
if (absolute) {
plugin_name = malloc(strlen(plugin) + 1);
@@ -58,7 +92,4 @@ int uwsgi_load_plugin(int modifier, char *plugin, char *pargs, int absolute) {
}
return 0;
return -1;
}
+1
View File
@@ -447,6 +447,7 @@ int erlang_opt(int i, char *optarg) {
struct uwsgi_plugin erlang_plugin = {
.name = "erlang",
.options = erlang_options,
.manage_opt = erlang_opt,
.init = erlang_init,
+186 -79
View File
@@ -12,10 +12,12 @@
#include "../../uwsgi.h"
#define LONG_ARGS_FASTROUTER 150001
#define LONG_ARGS_FASTROUTER_EVENTS 150002
#define LONG_ARGS_FASTROUTER_USE_PATTERN 150003
#define LONG_ARGS_FASTROUTER_USE_BASE 150004
#define LONG_ARGS_FASTROUTER 150001
#define LONG_ARGS_FASTROUTER_EVENTS 150002
#define LONG_ARGS_FASTROUTER_USE_PATTERN 150003
#define LONG_ARGS_FASTROUTER_USE_BASE 150004
#define LONG_ARGS_FASTROUTER_SUBSCRIPTION_SERVER 150005
#define LONG_ARGS_FASTROUTER_TIMEOUT 150006
#define FASTROUTER_STATUS_FREE 0
#define FASTROUTER_STATUS_CONNECTING 1
@@ -23,6 +25,9 @@
#define FASTROUTER_STATUS_RECV_VARS 3
#define FASTROUTER_STATUS_RESPONSE 4
#define add_timeout(x) uwsgi_add_rb_timer(ufr.timeouts, time(NULL)+ufr.socket_timeout, x)
#define del_timeout(x) rb_erase(&x->timeout->rbt, ufr.timeouts); free(x->timeout);
struct uwsgi_fastrouter {
char *socket_name;
int use_cache;
@@ -33,6 +38,13 @@ struct uwsgi_fastrouter {
char *base;
int base_len;
char *subscription_server;
struct uwsgi_dict *subscription_dict;
int socket_timeout;
struct rb_root *timeouts;
} ufr;
struct option fastrouter_options[] = {
@@ -41,11 +53,27 @@ struct option fastrouter_options[] = {
{"fastrouter-use-pattern", required_argument, 0, LONG_ARGS_FASTROUTER_USE_PATTERN},
{"fastrouter-use-base", required_argument, 0, LONG_ARGS_FASTROUTER_USE_BASE},
{"fastrouter-events", required_argument, 0, LONG_ARGS_FASTROUTER_EVENTS},
{"fastrouter-subscription-server", required_argument, 0, LONG_ARGS_FASTROUTER_SUBSCRIPTION_SERVER},
{"fastrouter-timeout", required_argument, 0, LONG_ARGS_FASTROUTER_TIMEOUT},
{0, 0, 0, 0},
};
extern struct uwsgi_server uwsgi;
void fastrouter_manage_subscription(char *key, uint16_t keylen, char *val, uint16_t vallen, void *data) {
struct uwsgi_subscribe_req *usr = (struct uwsgi_subscribe_req *) data;
if (!uwsgi_strncmp("key", 3, key, keylen)) {
usr->key = val;
usr->keylen = vallen;
}
else if (!uwsgi_strncmp("address", 7, key, keylen)) {
usr->address = val;
usr->address_len = vallen;
}
}
struct fastrouter_session {
int fd;
@@ -62,9 +90,53 @@ struct fastrouter_session {
char *instance_address;
uint64_t instance_address_len;
struct uwsgi_subscriber_name *un;
int pass_fd;
struct uwsgi_rb_timer *timeout;
int instance_failed;
};
static void close_session(struct fastrouter_session **fr_table, struct fastrouter_session *fr_session) {
close(fr_session->fd);
fr_table[fr_session->fd] = NULL;
if (fr_session->instance_fd != -1) {
if (ufr.subscription_server && (fr_session->instance_failed || fr_session->status == FASTROUTER_STATUS_CONNECTING)) {
uwsgi_log("marking %.*s as failed\n", (int) fr_session->instance_address_len,fr_session->instance_address);
fr_session->un->len = 0;
}
close(fr_session->instance_fd);
fr_table[fr_session->instance_fd] = NULL;
}
del_timeout(fr_session);
free(fr_session);
}
static struct uwsgi_rb_timer *reset_timeout(struct fastrouter_session *fr_session) {
del_timeout(fr_session);
return add_timeout(fr_session);
}
static void expire_timeouts(struct fastrouter_session **fr_table) {
time_t current = time(NULL);
struct uwsgi_rb_timer *urbt;
for(;;) {
urbt = uwsgi_min_rb_timer(ufr.timeouts);
if (urbt == NULL) return;
if (urbt->key <= current) {
close_session(fr_table, (struct fastrouter_session *)urbt->data);
uwsgi_log("timeout !!!\n");
continue;
}
break;
}
}
void fr_get_hostname(char *key, uint16_t keylen, char *val, uint16_t vallen, void *data) {
struct fastrouter_session *fr_session = (struct fastrouter_session *) data;
@@ -91,18 +163,27 @@ struct fastrouter_session *alloc_fr_session() {
void fastrouter_loop() {
int fr_queue;
int fr_server;
int fr_server = -1;
int nevents;
int interesting_fd;
int new_connection;
ssize_t len;
int i;
time_t delta;
char bbuf[UMAX16];
char *tcp_port;
char *tmp_socket_name;
int tmp_socket_name_len;
struct uwsgi_subscribe_req usr;
char *magic_table[0xff];
struct uwsgi_rb_timer *min_timeout;
void *events;
struct msghdr msg;
union {
@@ -123,11 +204,32 @@ void fastrouter_loop() {
int soopt;
socklen_t solen = sizeof(int);
int ufr_subserver = -1;
for(i=0;i<2048;i++) {
fr_table[i] = NULL;
}
fr_server = bind_to_tcp(ufr.socket_name, uwsgi.listen_queue, ufr.socket_name);
if (ufr.socket_name[0] == '=') {
int shared_socket = atoi(ufr.socket_name+1);
if (shared_socket >= 0 && shared_socket < uwsgi.shared_sockets_cnt) {
if (uwsgi.shared_sockets[shared_socket].name) {
fr_server = uwsgi.shared_sockets[shared_socket].fd;
}
else {
uwsgi_log("unable to use shared socket %d\n", shared_socket);
}
}
}
else {
tcp_port = strchr(ufr.socket_name, ':');
if (tcp_port) {
fr_server = bind_to_tcp(ufr.socket_name, uwsgi.listen_queue, tcp_port);
}
else {
fr_server = bind_to_unix(ufr.socket_name, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket);
}
}
fr_queue = event_queue_init();
@@ -135,13 +237,38 @@ void fastrouter_loop() {
event_queue_add_fd_read(fr_queue, fr_server);
if (ufr.subscription_server) {
ufr_subserver = bind_to_udp(ufr.subscription_server, 0, 0);
event_queue_add_fd_read(fr_queue, ufr_subserver);
ufr.subscription_dict = uwsgi_dict_create(30, 0);
}
if (ufr.pattern) {
init_magic_table(magic_table);
}
ufr.timeouts = uwsgi_init_rb_timer();
if (!ufr.socket_timeout) ufr.socket_timeout = 30;
for (;;) {
nevents = event_queue_wait_multi(fr_queue, -1, events, ufr.nevents);
min_timeout = uwsgi_min_rb_timer(ufr.timeouts);
if (min_timeout == NULL ) {
delta = -1;
}
else {
delta = min_timeout->key - time(NULL);
if (delta <= 0) {
expire_timeouts(fr_table);
delta = 0;
}
}
nevents = event_queue_wait_multi(fr_queue, delta, events, ufr.nevents);
if (nevents == 0) {
expire_timeouts(fr_table);
}
for (i=0;i<nevents;i++) {
@@ -161,11 +288,25 @@ void fastrouter_loop() {
fr_table[new_connection]->status = FASTROUTER_STATUS_RECV_HDR;
fr_table[new_connection]->h_pos = 0;
fr_table[new_connection]->pos = 0;
fr_table[new_connection]->instance_failed = 0;
fr_table[new_connection]->instance_address_len = 0;
fr_table[new_connection]->timeout = add_timeout(fr_table[new_connection]);
event_queue_add_fd_read(fr_queue, new_connection);
}
else if (interesting_fd == ufr_subserver) {
len = recv(ufr_subserver, bbuf, 4096, 0);
#ifdef UWSGI_EVENT_USE_PORT
event_queue_add_fd_read(fr_queue, ufr_subserver);
#endif
if (len > 0) {
memset(&usr, 0, sizeof(struct uwsgi_subscribe_req));
uwsgi_hooked_parse(bbuf+4, len-4, fastrouter_manage_subscription, &usr);
uwsgi_add_subscriber(ufr.subscription_dict, usr.key, usr.keylen, usr.address, usr.address_len);
}
}
else {
fr_session = fr_table[interesting_fd];
@@ -173,25 +314,19 @@ void fastrouter_loop() {
if (fr_session == NULL) continue;
if (event_queue_interesting_fd_has_error(events, i)) {
close(fr_session->fd);
fr_table[fr_session->fd] = NULL;
if (fr_session->instance_fd != -1) {
close(fr_session->instance_fd);
fr_table[fr_session->instance_fd] = NULL;
}
free(fr_session);
close_session(fr_table, fr_session);
continue;
}
fr_session->timeout = reset_timeout(fr_session);
switch(fr_session->status) {
case FASTROUTER_STATUS_RECV_HDR:
len = recv(fr_session->fd, (char *)(&fr_session->uh) + fr_session->h_pos, 4-fr_session->h_pos, 0);
if (len <= 0) {
uwsgi_error("recv()");
close(fr_session->fd);
fr_table[fr_session->fd] = NULL;
free(fr_session);
close_session(fr_table, fr_session);
break;
}
fr_session->h_pos += len;
@@ -208,24 +343,18 @@ void fastrouter_loop() {
len = recv(fr_session->fd, fr_session->buffer + fr_session->pos, fr_session->uh.pktsize - fr_session->pos, 0);
if (len <= 0) {
uwsgi_error("recv()");
close(fr_session->fd);
fr_table[fr_session->fd] = NULL;
free(fr_session);
close_session(fr_table, fr_session);
break;
}
fr_session->pos += len;
if (fr_session->pos == fr_session->uh.pktsize) {
if (uwsgi_hooked_parse(fr_session->buffer, fr_session->uh.pktsize, fr_get_hostname, (void *) fr_session)) {
close(fr_session->fd);
fr_table[fr_session->fd] = NULL;
free(fr_session);
close_session(fr_table, fr_session);
break;
}
if (fr_session->hostname_len == 0) {
close(fr_session->fd);
fr_table[fr_session->fd] = NULL;
free(fr_session);
close_session(fr_table, fr_session);
break;
}
@@ -240,6 +369,13 @@ void fastrouter_loop() {
fr_session->instance_address_len = tmp_socket_name_len;
fr_session->instance_address = tmp_socket_name;
}
else if (ufr.subscription_server) {
fr_session->un = uwsgi_get_subscriber(ufr.subscription_dict, fr_session->hostname, fr_session->hostname_len);
if (fr_session->un && fr_session->un->len) {
fr_session->instance_address = fr_session->un->name;
fr_session->instance_address_len = fr_session->un->len;
}
}
else if (ufr.base) {
tmp_socket_name = uwsgi_concat2nn(ufr.base, ufr.base_len, fr_session->hostname, fr_session->hostname_len, &tmp_socket_name_len);
fr_session->instance_address_len = tmp_socket_name_len;
@@ -248,9 +384,7 @@ void fastrouter_loop() {
// no address found
if (!fr_session->instance_address_len) {
close(fr_session->fd);
fr_table[fr_session->fd] = NULL;
free(fr_session);
close_session(fr_table, fr_session);
break;
}
@@ -262,9 +396,11 @@ void fastrouter_loop() {
if (tmp_socket_name) free(tmp_socket_name);
if (fr_session->instance_fd < 0) {
close(fr_session->fd);
fr_table[fr_session->fd] = NULL;
free(fr_session);
if (ufr.subscription_server) {
uwsgi_log("marking %.*s as failed\n", (int) fr_session->instance_address_len,fr_session->instance_address);
fr_session->un->len = 0;
}
close_session(fr_table, fr_session);
break;
}
@@ -283,21 +419,15 @@ void fastrouter_loop() {
if (getsockopt(fr_session->instance_fd, SOL_SOCKET, SO_ERROR, (void *) (&soopt), &solen) < 0) {
uwsgi_error("getsockopt()");
close(fr_session->fd);
close(fr_session->instance_fd);
fr_table[fr_session->fd] = NULL;
fr_table[fr_session->instance_fd] = NULL;
free(fr_session);
fr_session->instance_failed = 1;
close_session(fr_table, fr_session);
break;
}
if (soopt) {
uwsgi_log("unable to connect() to uwsgi instance: %s\n", strerror(soopt));
close(fr_session->fd);
close(fr_session->instance_fd);
fr_table[fr_session->fd] = NULL;
fr_table[fr_session->instance_fd] = NULL;
free(fr_session);
fr_session->instance_failed = 1;
close_session(fr_table, fr_session);
break;
}
@@ -327,21 +457,13 @@ void fastrouter_loop() {
uwsgi_error("sendmsg()");
}
close(fr_session->fd);
close(fr_session->instance_fd);
fr_table[fr_session->fd] = NULL;
fr_table[fr_session->instance_fd] = NULL;
free(fr_session);
close_session(fr_table, fr_session);
break;
}
if (writev(fr_session->instance_fd, iov, 2) < 0) {
uwsgi_error("writev()");
close(fr_session->fd);
close(fr_session->instance_fd);
fr_table[fr_session->fd] = NULL;
fr_table[fr_session->instance_fd] = NULL;
free(fr_session);
close_session(fr_table, fr_session);
break;
}
@@ -358,11 +480,7 @@ void fastrouter_loop() {
len = recv(fr_session->instance_fd, fr_session->buffer, 0xffff, 0);
if (len <= 0) {
if (len < 0) uwsgi_error("recv()");
close(fr_session->fd);
close(fr_session->instance_fd);
fr_table[fr_session->fd] = NULL;
fr_table[fr_session->instance_fd] = NULL;
free(fr_session);
close_session(fr_table, fr_session);
break;
}
@@ -370,11 +488,7 @@ void fastrouter_loop() {
if (len <= 0) {
if (len < 0) uwsgi_error("send()");
close(fr_session->fd);
close(fr_session->instance_fd);
fr_table[fr_session->fd] = NULL;
fr_table[fr_session->instance_fd] = NULL;
free(fr_session);
close_session(fr_table, fr_session);
break;
}
}
@@ -385,11 +499,7 @@ void fastrouter_loop() {
len = recv(fr_session->fd, fr_session->buffer, 0xffff, 0);
if (len <= 0) {
if (len < 0) uwsgi_error("recv()");
close(fr_session->fd);
close(fr_session->instance_fd);
fr_table[fr_session->fd] = NULL;
fr_table[fr_session->instance_fd] = NULL;
free(fr_session);
close_session(fr_table, fr_session);
break;
}
@@ -398,11 +508,7 @@ void fastrouter_loop() {
if (len <= 0) {
if (len < 0) uwsgi_error("send()");
close(fr_session->fd);
close(fr_session->instance_fd);
fr_table[fr_session->fd] = NULL;
fr_table[fr_session->instance_fd] = NULL;
free(fr_session);
close_session(fr_table, fr_session);
break;
}
}
@@ -414,13 +520,7 @@ void fastrouter_loop() {
// fallback to destroy !!!
default:
uwsgi_log("default action\n");
close(fr_session->fd);
fr_table[fr_session->fd] = NULL;
if (fr_session->instance_fd != -1) {
close(fr_session->instance_fd);
fr_table[fr_session->instance_fd] = NULL;
}
free(fr_session);
close_session(fr_table, fr_session);
break;
}
@@ -456,6 +556,9 @@ int fastrouter_opt(int i, char *optarg) {
case LONG_ARGS_FASTROUTER:
ufr.socket_name = optarg;
return 1;
case LONG_ARGS_FASTROUTER_SUBSCRIPTION_SERVER:
ufr.subscription_server = optarg;
return 1;
case LONG_ARGS_FASTROUTER_EVENTS:
ufr.nevents = atoi(optarg);
return 1;
@@ -469,6 +572,9 @@ int fastrouter_opt(int i, char *optarg) {
// optimization
ufr.base_len = strlen(ufr.base);
return 1;
case LONG_ARGS_FASTROUTER_TIMEOUT:
ufr.socket_timeout = atoi(optarg);
return -1;
}
return 0;
}
@@ -476,6 +582,7 @@ int fastrouter_opt(int i, char *optarg) {
struct uwsgi_plugin fastrouter_plugin = {
.name = "fastrouter",
.options = fastrouter_options,
.manage_opt = fastrouter_opt,
.init = fastrouter_init,
+11 -3
View File
@@ -145,13 +145,13 @@ struct http_session {
struct uwsgi_rb_timer *timeout;
};
struct uwsgi_rb_timer *reset_timeout(struct http_session *uhttp_session) {
static struct uwsgi_rb_timer *reset_timeout(struct http_session *uhttp_session) {
del_timeout(uhttp_session);
return add_timeout(uhttp_session);
}
void close_session(struct http_session **uhttp_table, struct http_session *uhttp_session) {
static void close_session(struct http_session **uhttp_table, struct http_session *uhttp_session) {
close(uhttp_session->fd);
uhttp_table[uhttp_session->fd] = NULL;
@@ -170,7 +170,7 @@ void close_session(struct http_session **uhttp_table, struct http_session *uhttp
}
void expire_timeouts(struct http_session **uhttp_table) {
static void expire_timeouts(struct http_session **uhttp_table) {
time_t current = time(NULL);
struct uwsgi_rb_timer *urbt;
@@ -429,12 +429,14 @@ void http_loop() {
struct uwsgi_rb_timer *min_timeout;
void *events;
#ifndef __sun__
struct msghdr msg;
union {
struct cmsghdr cmsg;
char control [CMSG_SPACE (sizeof (int))];
} msg_control;
struct cmsghdr *cmsg;
#endif
union uwsgi_sockaddr uhttp_addr;
socklen_t uhttp_addr_len = sizeof(struct sockaddr_un);
@@ -705,6 +707,8 @@ void http_loop() {
uhttp_session->iov_len++;
}
#ifndef __sun__
// fd passing: PERFORMANCE EXTREME BOOST !!!
if (uhttp_session->pass_fd && !uhttp_session->remains) {
msg.msg_name = NULL;
@@ -736,6 +740,7 @@ void http_loop() {
break;
}
#endif
#ifdef __sun__
if (uhttp_session->iov_len > IOV_MAX) {
int remains = uhttp_session->iov_len;
@@ -875,6 +880,8 @@ int http_init() {
uwsgi_log("unable to register the http gateway\n");
exit(1);
}
uwsgi_log("HTTP router/proxy bound on %s\n", uhttp.socket_name);
}
return 0;
@@ -934,6 +941,7 @@ int http_opt(int i, char *optarg) {
struct uwsgi_plugin http_plugin = {
.name = "http",
.options = http_options,
.manage_opt = http_opt,
.help = http_help,
+1
View File
@@ -1,6 +1,7 @@
#undef __USE_GNU
#include "../../uwsgi.h"
#define HAS_BOOL 1
#include <EXTERN.h>
#include <perl.h>
#include "XSUB.h"
+8 -1
View File
@@ -26,8 +26,11 @@ XS(XS_stream)
uwsgi_log("type %d\n", SvTYPE(stack));
response = (AV* ) SvRV(stack) ;
#ifdef my_perl
psgi_response(wsgi_req, my_perl, response);
#else
psgi_response(wsgi_req, uperl.main, response);
#endif
//mXPUSHp("x", 1);
XSRETURN(0);
@@ -146,6 +149,7 @@ void uwsgi_psgi_app() {
}
#ifdef my_perl
void uwsgi_perl_enable_threads() {
int i;
@@ -192,6 +196,7 @@ void uwsgi_perl_enable_threads() {
}
#endif
@@ -412,7 +417,9 @@ struct uwsgi_plugin psgi_plugin = {
.init_apps = uwsgi_psgi_app,
//.magic = uwsgi_perl_magic,
//.help = uwsgi_perl_help,
#ifdef my_perl
.enable_threads = uwsgi_perl_enable_threads,
#endif
.manage_opt = uwsgi_perl_manage_options,
.init_thread = uwsgi_perl_init_thread,
.request = uwsgi_perl_request,
+1
View File
@@ -439,6 +439,7 @@ PyObject *uwsgi_uwsgi_loader(void *arg1) {
if (quick_callable[strlen(quick_callable) -2 ] == '(' && quick_callable[strlen(quick_callable) -1] ==')') {
quick_callable[strlen(quick_callable) -2 ] = 0;
tmp_callable = PyDict_GetItemString(wsgi_dict, quick_callable);
quick_callable[strlen(quick_callable) -2 ] = '(';
if (tmp_callable) {
return python_call(tmp_callable, PyTuple_New(0), 0);
}
+2 -1
View File
@@ -85,7 +85,6 @@ int uwsgi_python_init() {
uwsgi_log("Python version: %.*s %s\n", pyversion-Py_GetVersion(), Py_GetVersion(), Py_GetCompiler()+1);
if (up.home != NULL) {
uwsgi_log("Setting PythonHome to %s...\n", up.home);
#ifdef PYTHREE
wchar_t *wpyhome;
wpyhome = malloc((sizeof(wchar_t) * strlen(up.home)) + 2);
@@ -99,6 +98,7 @@ int uwsgi_python_init() {
#else
Py_SetPythonHome(up.home);
#endif
uwsgi_log("Set PythonHome to %s\n", up.home);
}
#ifdef PYTHREE
@@ -1004,6 +1004,7 @@ void uwsgi_python_resume(struct wsgi_request *wsgi_req) {
struct uwsgi_plugin python_plugin = {
.name = "python",
.alias = "python",
.modifier1 = 0,
.init = uwsgi_python_init,
.post_fork = uwsgi_python_post_fork,
-8
View File
@@ -266,14 +266,6 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
}
if (uwsgi.limit_post) {
if (wsgi_req->post_cl > uwsgi.limit_post) {
uwsgi_log("Invalid (too big) CONTENT_LENGTH. skip.\n");
return -1;
}
}
if (!up.ignore_script_name) {
if (!wsgi_req->script_name)
+26 -16
View File
@@ -14,22 +14,36 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) {
PyObject *h_key, *h_value;
int i, j;
struct uwsgi_header uh;
PyObject *exc_info = NULL;
struct wsgi_request *wsgi_req = current_wsgi_req();
int base = 0;
int shift = 0;
// use writev()
// this must be done before headers management
if (PyTuple_Size(args) > 2) {
exc_info = PyTuple_GetItem(args, 2);
if (exc_info && exc_info != Py_None) {
PyObject *exc_type = PyTuple_GetItem(exc_info, 0);
PyObject *exc_val = PyTuple_GetItem(exc_info, 1);
PyObject *exc_tb = PyTuple_GetItem(exc_info, 2);
// is a Web3 response ?
/*
if (PyTuple_Size(args) == 3) {
shift = 0;
}
*/
if (!exc_type || !exc_val || !exc_tb) {
PyErr_Print();
goto clear;
}
head = PyTuple_GetItem(args, 0+shift);
Py_INCREF(exc_type);
Py_INCREF(exc_val);
Py_INCREF(exc_tb);
// in this way, error will be reported to the log
PyErr_Restore(exc_type, exc_val, exc_tb);
goto clear;
}
}
head = PyTuple_GetItem(args, 0);
if (!head) {
goto clear;
}
@@ -93,19 +107,16 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) {
uh.pktsize += wsgi_req->hvec[2].iov_len;
}
headers = PyTuple_GetItem(args, 1);
if (!headers) goto clear;
headers = PyTuple_GetItem(args, 1+shift);
if (!headers) {
goto clear;
}
if (!PyList_Check(headers)) {
uwsgi_log( "http headers must be in a python list\n");
goto clear;
}
wsgi_req->header_cnt = PyList_Size(headers);
if (wsgi_req->header_cnt > uwsgi.max_vars) {
wsgi_req->header_cnt = uwsgi.max_vars;
}
@@ -174,7 +185,6 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) {
//uwsgi_log("%d %p\n", wsgi_req->poll.fd, up.wsgi_writeout);
Py_INCREF(up.wsgi_writeout);
return up.wsgi_writeout;
clear:
+97 -30
View File
@@ -675,6 +675,13 @@ int uwsgi_parse_vars(struct wsgi_request *wsgi_req) {
}
else if (!uwsgi_strncmp("CONTENT_LENGTH", 14, wsgi_req->hvec[wsgi_req->var_cnt].iov_base, wsgi_req->hvec[wsgi_req->var_cnt].iov_len)) {
wsgi_req->post_cl = get_content_length(ptrbuf, strsize);
if (uwsgi.limit_post) {
if (wsgi_req->post_cl > uwsgi.limit_post) {
uwsgi_log("Invalid (too big) CONTENT_LENGTH. skip.\n");
return -1;
}
}
}
if (wsgi_req->var_cnt < uwsgi.vec_size - (4 + 1)) {
@@ -779,42 +786,25 @@ int uwsgi_parse_vars(struct wsgi_request *wsgi_req) {
}
}
// check i fa file name uwsgi.check_static+env['PATH_INFO'] exists
// check if a file named uwsgi.check_static+env['PATH_INFO'] exists
if (uwsgi.check_static && wsgi_req->path_info_len > 1) {
struct stat st;
char *filename = uwsgi_concat2n(uwsgi.check_static, uwsgi.check_static_len, wsgi_req->path_info, wsgi_req->path_info_len);
if (!uwsgi_file_serve(wsgi_req, uwsgi.check_static, uwsgi.check_static_len, wsgi_req->path_info, wsgi_req->path_info_len)) {
return -1;
}
}
// check static-map
struct uwsgi_static_map *usm = uwsgi.static_maps;
while(usm) {
#ifdef UWSGI_DEBUG
uwsgi_log("checking for %s\n", filename);
uwsgi_log("checking for %.*s <-> %.*s\n", wsgi_req->path_info_len, wsgi_req->path_info, usm->mountpoint_len, usm->mountpoint);
#endif
if (!stat(filename, &st)) {
if (wsgi_req->if_modified_since_len) {
time_t ims = parse_http_date(wsgi_req->if_modified_since, wsgi_req->if_modified_since_len);
if (st.st_mtime <= ims) {
wsgi_req->status = 304;
wsgi_req->headers_size = write(wsgi_req->poll.fd, wsgi_req->protocol, wsgi_req->protocol_len);
wsgi_req->headers_size += write(wsgi_req->poll.fd, " 304 Not Modified\r\n\r\n", 21);
return -1;
}
}
if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
char http_last_modified[49];
#ifdef UWSGI_DEBUG
uwsgi_log("file %s found\n", filename);
#endif
// no need to set content-type/content-length, they will be fixed by the http server/router
wsgi_req->sendfile_fd = open(filename, O_RDONLY);
wsgi_req->headers_size = write(wsgi_req->poll.fd, wsgi_req->protocol, wsgi_req->protocol_len);
wsgi_req->headers_size += write(wsgi_req->poll.fd, " 200 OK\r\n", 9);
set_http_date(st.st_mtime, http_last_modified);
wsgi_req->headers_size += write(wsgi_req->poll.fd, http_last_modified, 48);
wsgi_req->header_cnt = 1;
wsgi_req->response_size += uwsgi_sendfile(wsgi_req);
wsgi_req->status = 200;
free(filename);
if (!uwsgi_starts_with(wsgi_req->path_info, wsgi_req->path_info_len, usm->mountpoint, usm->mountpoint_len)) {
if (!uwsgi_file_serve(wsgi_req, usm->document_root, usm->document_root_len, wsgi_req->path_info+usm->mountpoint_len, wsgi_req->path_info_len-usm->mountpoint_len)) {
return -1;
}
}
free(filename);
usm = usm->next;
}
return 0;
@@ -1317,3 +1307,80 @@ int uwsgi_simple_send_string(char *socket_name, uint8_t modifier1, uint8_t modif
return 0;
}
int uwsgi_file_serve(struct wsgi_request *wsgi_req, char *document_root, uint16_t document_root_len, char *path_info, uint16_t path_info_len) {
struct stat st;
char real_filename[PATH_MAX];
char *filename = uwsgi_concat3n(document_root, document_root_len, "/", 1, path_info, path_info_len);
#ifdef UWSGI_DEBUG
uwsgi_log("checking for %s\n", filename);
#endif
if (!realpath(filename, real_filename)) {
#ifdef UWSGI_DEBUG
uwsgi_log("unable to get realpath() of the static file\n");
#endif
free(filename);
return -1;
}
free(filename);
if (uwsgi_starts_with(real_filename, strlen(real_filename), document_root, document_root_len)) {
uwsgi_log("security error: %s is not under %.*s\n", real_filename, document_root_len, document_root);
return -1;
}
if (!stat(real_filename, &st)) {
if (wsgi_req->if_modified_since_len) {
time_t ims = parse_http_date(wsgi_req->if_modified_since, wsgi_req->if_modified_since_len);
if (st.st_mtime <= ims) {
wsgi_req->status = 304;
wsgi_req->headers_size = write(wsgi_req->poll.fd, wsgi_req->protocol, wsgi_req->protocol_len);
wsgi_req->headers_size += write(wsgi_req->poll.fd, " 304 Not Modified\r\n\r\n", 21);
return 0;
}
}
if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
char http_last_modified[49];
#ifdef UWSGI_DEBUG
uwsgi_log("file %s found\n", real_filename);
#endif
// no need to set content-type/content-length, they will be fixed by the http server/router
wsgi_req->headers_size = write(wsgi_req->poll.fd, wsgi_req->protocol, wsgi_req->protocol_len);
wsgi_req->headers_size += write(wsgi_req->poll.fd, " 200 OK\r\n", 9);
if (uwsgi.file_serve_mode == 1) {
wsgi_req->header_cnt = 2;
wsgi_req->headers_size += write(wsgi_req->poll.fd, "X-Accel-Redirect: ", 18);
wsgi_req->headers_size += write(wsgi_req->poll.fd, path_info, path_info_len);
wsgi_req->headers_size += write(wsgi_req->poll.fd, "\r\n", 2);
set_http_date(st.st_mtime, http_last_modified);
wsgi_req->headers_size += write(wsgi_req->poll.fd, http_last_modified, 48);
}
else if (uwsgi.file_serve_mode == 2) {
wsgi_req->header_cnt = 2;
wsgi_req->headers_size += write(wsgi_req->poll.fd, "X-Sendfile: ", 12);
wsgi_req->headers_size += write(wsgi_req->poll.fd, real_filename, strlen(real_filename));
wsgi_req->headers_size += write(wsgi_req->poll.fd, "\r\n", 2);
set_http_date(st.st_mtime, http_last_modified);
wsgi_req->headers_size += write(wsgi_req->poll.fd, http_last_modified, 48);
}
else {
wsgi_req->header_cnt = 1;
set_http_date(st.st_mtime, http_last_modified);
wsgi_req->headers_size += write(wsgi_req->poll.fd, http_last_modified, 48);
wsgi_req->sendfile_fd = open(real_filename, O_RDONLY);
wsgi_req->response_size += uwsgi_sendfile(wsgi_req);
}
wsgi_req->status = 200;
return 0;
}
}
return -1;
}
+1 -1
View File
@@ -51,7 +51,7 @@ class uWSGIDistribution(Distribution):
setup(name='uWSGI',
version='0.9.7.1',
version='0.9.7.2',
description='The uWSGI server',
author='Unbit',
author_email='info@unbit.it',
+20
View File
@@ -317,6 +317,26 @@ char *generate_socket_name(char *socket_name) {
char *new_socket;
char *tcp_port;
int i;
char *ptr = socket_name;
// ltrim spaces
for(i=0;i<(int)strlen(socket_name);i++) {
if (isspace((int)socket_name[i])) {
ptr++;
}
else {
break;
}
}
socket_name = ptr;
if (socket_name[0] == 0) {
uwsgi_log("invalid/empty uwsgi socket name\n");
exit(1);
}
tcp_port = strchr(socket_name, ':');
if (!tcp_port) return socket_name;
+1 -1
View File
@@ -250,7 +250,7 @@ int uwsgi_request_spooler(struct wsgi_request *wsgi_req) {
if (unlink(spool_filename)) {
uwsgi_error("unlink()");
uwsgi_log("something horrible happened !!! check your spooler ASAP !!!\n");
goodbye_cruel_world();
exit(1);
}
}
return 0;
+75 -3
View File
@@ -188,12 +188,18 @@ void logto(char *logfile) {
void log_syslog(char *syslog_opts) {
if (syslog_opts == NULL) {
syslog_opts= "uwsgi";
}
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, uwsgi.shared->worker_log_pipe)) {
uwsgi_error("socketpair()\n");
exit(1);
}
#ifdef UWSGI_DEBUG
uwsgi_log("log pipe %d %d\n", uwsgi.shared->worker_log_pipe[0], uwsgi.shared->worker_log_pipe[1]);
#endif
if (uwsgi.shared->worker_log_pipe[1] != 1) {
if (dup2(uwsgi.shared->worker_log_pipe[1], 1) < 0) {
@@ -203,14 +209,16 @@ void log_syslog(char *syslog_opts) {
}
#ifdef UWSGI_DEBUG
uwsgi_log("opening syslog\n");
#endif
if (dup2(1, 2) < 0) {
uwsgi_error("dup2()");
exit(1);
}
openlog("uwsgi", 0, LOG_DAEMON );
openlog(syslog_opts, 0, LOG_DAEMON );
}
@@ -260,7 +268,7 @@ void uwsgi_as_root() {
#endif
if (!getuid()) {
if (!uwsgi.master_as_root) {
if (!uwsgi.master_as_root && !uwsgi.uidname) {
uwsgi_log("uWSGI running as root, you can use --uid/--gid/--chroot options\n");
}
@@ -357,6 +365,10 @@ void uwsgi_as_root() {
uwsgi_error("setgid()");
exit(1);
}
if (setgroups(0, NULL)) {
uwsgi_error("setgroups()");
exit(1);
}
}
if (uwsgi.uid) {
if (!uwsgi.master_as_root) uwsgi_log("setuid() to %d\n", uwsgi.uid);
@@ -396,7 +408,7 @@ void uwsgi_close_request(struct wsgi_request *wsgi_req) {
// get memory usage
if (uwsgi.shared->options[UWSGI_OPTION_MEMORY_DEBUG] == 1)
if (uwsgi.shared->options[UWSGI_OPTION_MEMORY_DEBUG] == 1 || uwsgi.reload_on_as || uwsgi.reload_on_rss)
get_memusage();
@@ -430,6 +442,14 @@ void uwsgi_close_request(struct wsgi_request *wsgi_req) {
goodbye_cruel_world();
}
if (uwsgi.reload_on_as && (int) (uwsgi.workers[uwsgi.mywid].vsz_size / 1024 / 1024) >= uwsgi.reload_on_as) {
goodbye_cruel_world();
}
if (uwsgi.reload_on_rss && (int) (uwsgi.workers[uwsgi.mywid].rss_size / 1024 / 1024) >= uwsgi.reload_on_rss) {
goodbye_cruel_world();
}
}
@@ -714,6 +734,13 @@ inline int uwsgi_strncmp(char *src, int slen, char *dst, int dlen) {
}
inline int uwsgi_starts_with(char *src, int slen, char *dst, int dlen) {
if (slen < dlen) return -1;
return memcmp(src, dst, dlen);
}
inline int uwsgi_startswith(char *src, char *what, int wlen) {
int i;
@@ -1290,6 +1317,7 @@ char *uwsgi_open_and_read(char *url, int *size, int add_zero, char *magic_table[
char *magic_buf;
// http url ?
if (!strncmp("http://", url, 7)) {
domain = url+7;
uri = strchr(domain, '/');
@@ -1340,6 +1368,8 @@ char *uwsgi_open_and_read(char *url, int *size, int add_zero, char *magic_table[
len = write(fd, "\r\n\r\n", 4);
int http_status_code_ptr = 0;
while( read(fd, &byte, 1) == 1) {
if (byte == '\r' && body == 0) {
body = 1;
@@ -1364,6 +1394,18 @@ char *uwsgi_open_and_read(char *url, int *size, int add_zero, char *magic_table[
}
else {
body = 0;
http_status_code_ptr++;
if (http_status_code_ptr == 10) {
if (byte != '2') {
uwsgi_log("Not usable HTTP response: %cxx\n", byte);
if (uwsgi.has_emperor) {
exit(UWSGI_EXILE_CODE);
}
else {
exit(1);
}
}
}
}
}
@@ -1376,6 +1418,35 @@ char *uwsgi_open_and_read(char *url, int *size, int add_zero, char *magic_table[
}
}
else if (!strncmp("emperor://", url, 10)) {
if (uwsgi.emperor_fd_config < 0) {
uwsgi_log("this is not a vassal instance\n");
exit(1);
}
char *tmp_buffer[4096];
ssize_t rlen = 1;
*size = 0;
while(rlen > 0) {
rlen = read(uwsgi.emperor_fd_config, tmp_buffer, 4096);
if (rlen > 0) {
*size += rlen;
buffer = realloc(buffer, *size);
if (!buffer) {
uwsgi_error("realloc()");
exit(1);
}
memcpy(buffer+(*size-rlen), tmp_buffer, rlen);
}
}
close(uwsgi.emperor_fd_config);
uwsgi.emperor_fd_config = -1;
if (add_zero) {
*size = *size + 1;
buffer = realloc(buffer, *size);
buffer[*size-1] = 0;
}
}
// fallback to file
else {
fd = open(url, O_RDONLY);
@@ -1468,6 +1539,7 @@ char *uwsgi_get_last_char(char *what, char c) {
char *ptr = NULL;
if (!strncmp("http://", what, 7)) j = 7;
if (!strncmp("emperor://", what, 10)) j = 10;
for(i=j;i<(int)strlen(what);i++) {
if (what[i] == c) {
+150 -21
View File
@@ -2,7 +2,7 @@
*** uWSGI ***
Copyright (C) 2009-2010 Unbit S.a.s. <info@unbit.it>
Copyright (C) 2009-2011 Unbit S.a.s. <info@unbit.it>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@@ -37,12 +37,14 @@ UWSGI_DECLARE_EMBEDDED_PLUGINS
static struct option long_base_options[] = {
{"socket", required_argument, 0, 's'},
{"shared-socket", required_argument, 0, LONG_ARGS_SHARED_SOCKET},
{"processes", required_argument, 0, 'p'},
{"workers", required_argument, 0, 'p'},
{"harakiri", required_argument, 0, 't'},
{"harakiri-verbose", no_argument, &uwsgi.harakiri_verbose, 1},
#ifdef UWSGI_XML
{"xmlconfig", required_argument, 0, 'x'},
{"xml", required_argument, 0, 'x'},
#endif
{"daemonize", required_argument, 0, 'd'},
{"listen", required_argument, 0, 'l'},
@@ -61,6 +63,7 @@ static struct option long_base_options[] = {
{"master", no_argument, 0, 'M'},
{"emperor", required_argument, 0, LONG_ARGS_EMPEROR},
{"reload-mercy", required_argument, 0, LONG_ARGS_RELOAD_MERCY},
{"exit-on-reload", no_argument, &uwsgi.exit_on_reload, 1},
{"help", no_argument, 0, 'h'},
{"reaper", no_argument, 0, 'r'},
{"max-requests", required_argument, 0, 'R'},
@@ -99,6 +102,9 @@ static struct option long_base_options[] = {
{"no-server", no_argument, &uwsgi.no_server, 1},
{"no-defer-accept", no_argument, &uwsgi.no_defer_accept, 1},
{"limit-as", required_argument, 0, LONG_ARGS_LIMIT_AS},
{"reload-on-as", required_argument, 0, LONG_ARGS_RELOAD_ON_AS},
{"reload-on-rss", required_argument, 0, LONG_ARGS_RELOAD_ON_RSS},
{"touch-reload", required_argument, 0, LONG_ARGS_TOUCH_RELOAD},
{"limit-post", required_argument, 0, LONG_ARGS_LIMIT_POST},
{"no-orphans", no_argument, &uwsgi.no_orphans, 1},
{"prio", required_argument, 0, LONG_ARGS_PRIO},
@@ -153,6 +159,8 @@ static struct option long_base_options[] = {
{"routing", no_argument, &uwsgi.routing, 1},
#endif
{"check-static", required_argument, 0, LONG_ARGS_CHECK_STATIC},
{"static-map", required_argument, 0, LONG_ARGS_STATIC_MAP},
{"file-serve-mode", required_argument, 0, LONG_ARGS_FILE_SERVE_MODE},
{"check-cache", no_argument, &uwsgi.check_cache, 1},
{"close-on-exec", no_argument, &uwsgi.close_on_exec, 1},
{"mode", required_argument, 0, LONG_ARGS_MODE},
@@ -224,6 +232,7 @@ void end_me(int signum)
void goodbye_cruel_world()
{
uwsgi.workers[uwsgi.mywid].manage_next_request = 0;
uwsgi_log("...The work of process %d is done. Seeya!\n", getpid());
exit(0);
}
@@ -520,6 +529,8 @@ int main(int argc, char *argv[], char *envp[])
uwsgi.master_queue = -1;
uwsgi.emperor_fd_config = -1;
uwsgi.cluster_fd = -1;
uwsgi.cores = 1;
@@ -553,6 +564,10 @@ int main(int argc, char *argv[], char *envp[])
uwsgi.master_process = 1;
uwsgi.no_orphans = 1;
uwsgi_log("*** has_emperor mode detected (fd: %d) ***\n", uwsgi.emperor_fd);
if (getenv("UWSGI_EMPEROR_FD_CONFIG")) {
uwsgi.emperor_fd_config = atoi(getenv("UWSGI_EMPEROR_FD_CONFIG"));
}
}
env_reloads = getenv("UWSGI_RELOADS");
@@ -782,6 +797,7 @@ int main(int argc, char *argv[], char *envp[])
#endif
magic_key = NULL;
has_percent = 0;
j = 0;
}
else {
has_percent++;
@@ -937,6 +953,33 @@ options_parsed:
fclose(pidfile);
}
for (i = 0; i < uwsgi.shared_sockets_cnt; i++) {
char *tcp_port = strchr(uwsgi.shared_sockets[i].name, ':');
if (tcp_port == NULL) {
uwsgi.shared_sockets[i].fd = bind_to_unix(uwsgi.shared_sockets[i].name, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket);
uwsgi.shared_sockets[i].family = AF_UNIX;
uwsgi_log("uwsgi shared socket %d bound to UNIX address %s fd %d\n", i, uwsgi.shared_sockets[i].name, uwsgi.shared_sockets[i].fd);
} else {
uwsgi.shared_sockets[i].fd = bind_to_tcp(uwsgi.shared_sockets[i].name, uwsgi.listen_queue, tcp_port);
uwsgi.shared_sockets[i].family = AF_INET;
uwsgi_log("uwsgi shared socket %d bound to TCP address %s fd %d\n", i, uwsgi.shared_sockets[i].name, uwsgi.shared_sockets[i].fd);
}
if (uwsgi.shared_sockets[i].fd < 0) {
uwsgi_log("unable to create shared socket on: %s\n", uwsgi.shared_sockets[i].name);
exit(1);
}
uwsgi.shared_sockets[i].bound = 1;
}
// call jail systems
for(i =0; i < uwsgi.gp_cnt; i++) {
if (uwsgi.gp[i]->jail) {
uwsgi.gp[i]->jail(uwsgi_start, argv);
}
}
#ifdef __linux__
#ifndef CLONE_NEWUTS
@@ -950,6 +993,11 @@ options_parsed:
#ifndef CLONE_NEWIPC
#define CLONE_NEWIPC 0x08000000
#endif
#ifndef CLONE_NEWNET
#define CLONE_NEWNET 0x40000000
#endif
if (uwsgi.ns) {
for(;;) {
char stack[PTHREAD_STACK_MIN];
@@ -1011,13 +1059,14 @@ int uwsgi_start(void *v_argv) {
int emperor_pipe[2];
#ifdef __linux__
char *ns_tmp_mountpoint=NULL, *ns_tmp_mountpoint2=NULL;
if (uwsgi.ns) {
if (getpid() != 1) {
uwsgi_log("your kernel does not support linux pid namespace\n");
exit(1);
}
char *ns_hostname = strchr(uwsgi.ns, ':');
if (ns_hostname) {
ns_hostname[0] = 0;
@@ -1037,27 +1086,32 @@ int uwsgi_start(void *v_argv) {
exit(1);
}
char *ns_tmp_mountpoint = uwsgi_concat2(uwsgi.ns, "/.uwsgi_ns_tmp_mountpoint");
mkdir(ns_tmp_mountpoint, S_IRWXU);
if (strcmp(uwsgi.ns, "/")) {
ns_tmp_mountpoint = uwsgi_concat2(uwsgi.ns, "/.uwsgi_ns_tmp_mountpoint");
mkdir(ns_tmp_mountpoint, S_IRWXU);
char *ns_tmp_mountpoint2 = uwsgi_concat2(ns_tmp_mountpoint, "/.uwsgi_ns_tmp_mountpoint");
mkdir(ns_tmp_mountpoint2, S_IRWXU);
ns_tmp_mountpoint2 = uwsgi_concat2(ns_tmp_mountpoint, "/.uwsgi_ns_tmp_mountpoint");
mkdir(ns_tmp_mountpoint2, S_IRWXU);
if (mount(uwsgi.ns, ns_tmp_mountpoint, "none", MS_BIND, NULL)) {
uwsgi_error("mount()");
}
if (chdir(ns_tmp_mountpoint)) {
uwsgi_error("chdir()");
}
if (mount(uwsgi.ns, ns_tmp_mountpoint, "none", MS_BIND, NULL)) {
uwsgi_error("mount()");
}
if (chdir(ns_tmp_mountpoint)) {
uwsgi_error("chdir()");
}
if (pivot_root(".", ns_tmp_mountpoint2)) {
uwsgi_error("pivot_root()");
exit(1);
}
if (pivot_root(".", ns_tmp_mountpoint2)) {
uwsgi_error("pivot_root()");
exit(1);
}
if (chdir("/")) {
uwsgi_error("chdir()");
exit(1);
}
if (chdir("/")) {
uwsgi_error("chdir()");
exit(1);
}
uwsgi_log("remounting /proc\n");
@@ -1089,8 +1143,11 @@ int uwsgi_start(void *v_argv) {
uwsgi_error("rmdir()");
}
free(ns_tmp_mountpoint2);
free(ns_tmp_mountpoint);
if (strcmp(uwsgi.ns, "/")) {
free(ns_tmp_mountpoint2);
free(ns_tmp_mountpoint);
}
}
#endif
@@ -1167,6 +1224,7 @@ int uwsgi_start(void *v_argv) {
// end of generic initialization
// start the Emperor if needed
if (uwsgi.emperor_dir) {
@@ -1306,11 +1364,13 @@ int uwsgi_start(void *v_argv) {
uwsgi_lock_init(uwsgi.cron_table_lock);
}
#ifdef UWSGI_SPOOLER
if (uwsgi.spool_dir) {
// spooler lock
uwsgi.spooler_lock = uwsgi_mmap_shared_lock();
uwsgi_lock_init(uwsgi.spooler_lock);
}
#endif
uwsgi.rpc_table_lock = uwsgi_mmap_shared_lock();
uwsgi_lock_init(uwsgi.rpc_table_lock);
@@ -2212,6 +2272,7 @@ end:
static int manage_base_opt(int i, char *optarg) {
char *p;
struct uwsgi_static_map *usm;
switch (i) {
@@ -2303,6 +2364,7 @@ end:
log_syslog(optarg);
uwsgi.log_syslog = 1;
uwsgi.log_master = 1;
uwsgi.master_process = 1;
return 1;
case LONG_ARGS_PRINT:
uwsgi_log("%s\n", optarg);
@@ -2380,6 +2442,55 @@ end:
uwsgi.check_static = optarg;
uwsgi.check_static_len = strlen(uwsgi.check_static);
return 1;
case LONG_ARGS_FILE_SERVE_MODE:
if (!strcasecmp("x-sendfile", optarg)) {
uwsgi.file_serve_mode = 2;
}
else if (!strcasecmp("xsendfile", optarg)) {
uwsgi.file_serve_mode = 2;
}
else if (!strcasecmp("x-accel-redirect", optarg)) {
uwsgi.file_serve_mode = 1;
}
else if (!strcasecmp("xaccelredirect", optarg)) {
uwsgi.file_serve_mode = 1;
}
else if (!strcasecmp("nginx", optarg)) {
uwsgi.file_serve_mode = 1;
}
return 1;
case LONG_ARGS_STATIC_MAP:
usm = uwsgi.static_maps;
if (!usm) {
usm = uwsgi_malloc(sizeof(struct uwsgi_static_map));
uwsgi.static_maps = usm;
}
else {
while(usm->next) {
if (!usm->next) {
usm->next = uwsgi_malloc(sizeof(struct uwsgi_static_map));
usm = usm->next;
break;
}
}
}
char *docroot = strchr(optarg, '=');
if (!docroot) {
uwsgi_log("invalid document root in static map\n");
exit(1);
}
usm->mountpoint = optarg;
usm->mountpoint_len = docroot-usm->mountpoint;
usm->document_root = realpath(docroot+1, NULL);
usm->document_root_len = strlen(usm->document_root);
uwsgi_log("static-mapped %.*s to %.*s\n", usm->mountpoint_len, usm->mountpoint, usm->document_root_len, usm->document_root);
usm->next = NULL;
return 1;
case LONG_ARGS_ATTACH_DAEMON:
if (uwsgi.startup_daemons_cnt < MAX_DAEMONS) {
uwsgi.startup_daemons[uwsgi.startup_daemons_cnt] = optarg;
@@ -2422,6 +2533,16 @@ end:
case LONG_ARGS_LIMIT_POST:
uwsgi.limit_post = (int) strtol(optarg, NULL, 10);
return 1;
case LONG_ARGS_RELOAD_ON_AS:
uwsgi.reload_on_as = atoi(optarg);
return 1;
case LONG_ARGS_RELOAD_ON_RSS:
uwsgi.reload_on_rss = atoi(optarg);
return 1;
case LONG_ARGS_TOUCH_RELOAD:
uwsgi.touch_reload = optarg;
uwsgi.master_process = 1;
return 1;
case LONG_ARGS_PRIO:
uwsgi.prio = (int) strtol(optarg, NULL, 10);
return 1;
@@ -2551,6 +2672,14 @@ end:
uwsgi_log("you can specify at most 8 --socket options\n");
}
return 1;
case LONG_ARGS_SHARED_SOCKET:
if (uwsgi.shared_sockets_cnt < MAX_SOCKETS) {
uwsgi.shared_sockets[uwsgi.shared_sockets_cnt].name = generate_socket_name(optarg);
uwsgi.shared_sockets_cnt++;
} else {
uwsgi_log("you can specify at most 8 --socket options\n");
}
return 1;
#ifdef UWSGI_XML
case 'x':
uwsgi.xml_config = optarg;
+59 -4
View File
@@ -2,7 +2,7 @@
/* indent -i8 -br -brs -brf -l0 -npsl -nip -npcs -npsl -di1 */
#define UWSGI_VERSION "0.9.7.1"
#define UWSGI_VERSION "0.9.7.2"
#define UMAX16 65536
@@ -99,7 +99,7 @@
#include <sys/utsname.h>
#ifdef __linux
#ifdef __linux__
#ifndef __USE_GNU
#define __USE_GNU
#endif
@@ -216,6 +216,17 @@ struct uwsgi_help_item {
char *value;
};
struct uwsgi_static_map {
char *mountpoint;
int mountpoint_len;
char *document_root;
int document_root_len;
struct uwsgi_static_map *next;
};
union uwsgi_sockaddr {
struct sockaddr sa;
@@ -379,6 +390,12 @@ struct uwsgi_opt {
#define LONG_ARGS_QUEUE_STORE_SYNC 17087
#define LONG_ARGS_PIDFILE2 17088
#define LONG_ARGS_MAP_SOCKET 17089
#define LONG_ARGS_SHARED_SOCKET 17090
#define LONG_ARGS_STATIC_MAP 17091
#define LONG_ARGS_FILE_SERVE_MODE 17092
#define LONG_ARGS_RELOAD_ON_AS 17093
#define LONG_ARGS_RELOAD_ON_RSS 17094
#define LONG_ARGS_TOUCH_RELOAD 17095
#define UWSGI_OK 0
@@ -452,6 +469,7 @@ struct uwsgi_opt {
#define UWSGI_RELOAD_CODE 17
#define UWSGI_END_CODE 30
#define UWSGI_EXILE_CODE 26
#define MAX_VARS 64
#define MAX_LOOPS 60
@@ -477,6 +495,7 @@ struct uwsgi_server;
struct uwsgi_plugin {
const char *name;
const char *alias;
uint8_t modifier1;
void *data;
int (*init) (void);
@@ -506,6 +525,8 @@ struct uwsgi_plugin {
uint16_t (*rpc)(void *, uint8_t, char **, char *);
void (*jail) (int (*)(void *), char**);
struct uwsgi_help_item *help;
};
@@ -756,6 +777,7 @@ struct uwsgi_server {
int has_emperor;
int emperor_fd;
int emperor_fd_config;
char *emperor_dir;
pid_t emperor_pid;
@@ -764,6 +786,7 @@ struct uwsgi_server {
int cpu_affinity;
int reload_mercy;
int exit_on_reload;
int option_index;
struct option *long_options;
struct uwsgi_opt **exported_opts;
@@ -800,6 +823,9 @@ struct uwsgi_server {
int log_syslog;
char *check_static;
size_t check_static_len;
int file_serve_mode;
struct uwsgi_static_map *static_maps;
char *logfile;
int logfile_chown;
@@ -830,6 +856,11 @@ struct uwsgi_server {
size_t limit_post;
int prio;
int reload_on_as;
int reload_on_rss;
char *touch_reload;
time_t last_touch_reload_mtime;
int grunt;
char *binary_path;
@@ -970,6 +1001,9 @@ struct uwsgi_server {
// leave a slot for no-orphan mode
struct pollfd sockets_poll[9];
int shared_sockets_cnt;
struct uwsgi_socket shared_sockets[MAX_SOCKETS];
char *map_socket[MAX_SOCKETS];
time_t respawn_delta;
@@ -1040,7 +1074,9 @@ struct uwsgi_server {
void *rb_timer_table_lock;
void *cron_table_lock;
void *rpc_table_lock;
#ifdef UWSGI_SPOOLER
void *spooler_lock;
#endif
void *daemon_table_lock;
@@ -1367,8 +1403,6 @@ void uwsgi_log_verbose(const char *,...);
int uwsgi_load_plugin(int, char *, char *, int);
void embed_plugins(void);
int unconfigured_hook(struct wsgi_request *);
@@ -1686,3 +1720,24 @@ void uwsgi_queue_fix(void);
int uwsgi_str2_num(char *);
int uwsgi_str3_num(char *);
int uwsgi_str4_num(char *);
#ifdef __linux__
int uwsgi_netlink_veth(char *, char *);
int uwsgi_netlink_veth_attach(char *, pid_t);
int uwsgi_netlink_ifup(char *);
int uwsgi_netlink_ip(char *, char *, int);
int uwsgi_netlink_gw(char *, char *);
int uwsgi_netlink_rt(char *, char *, int, char *);
int uwsgi_netlink_del(char *);
#endif
int uwsgi_amqp_consume_queue(int, char *, char *, char *, char *);
char *uwsgi_amqp_consume(int, uint64_t *, char **);
int uwsgi_file_serve(struct wsgi_request *, char *, uint16_t, char *, uint16_t);
inline int uwsgi_starts_with(char *, int, char *, int);
#ifdef __sun__
time_t timegm(struct tm *);
#endif
+6 -1
View File
@@ -157,7 +157,9 @@ class uConf(object):
print("using profile: %s" % filename)
self.config.read(filename)
self.gcc_list = ['utils', 'protocol', 'socket', 'logging', 'master', 'emperor',
'plugins', 'lock', 'cache', 'queue', 'event', 'signal', 'rpc', 'gateway', 'loop', 'lib/rbtree', 'rb_timers', 'uwsgi']
'plugins', 'lock', 'cache', 'queue', 'event', 'signal', 'rpc', 'gateway', 'loop', 'lib/rbtree', 'lib/amqp', 'rb_timers', 'uwsgi']
#if uwsgi_os == 'Linux':
# self.gcc_list.append('lib/netlink')
self.cflags = ['-O2', '-Wall', '-Werror', '-D_LARGEFILE_SOURCE', '-D_FILE_OFFSET_BITS=64'] + os.environ.get("CFLAGS", "").split()
try:
gcc_version = str(spcall("%s -dumpversion" % GCC))
@@ -174,6 +176,8 @@ class uConf(object):
self.ldflags = os.environ.get("LDFLAGS", "").split()
self.libs = ['-lpthread', '-rdynamic']
if uwsgi_os == 'Linux':
self.libs.append('-ldl')
# check for inherit option
inherit = self.get('inherit')
@@ -222,6 +226,7 @@ class uConf(object):
if uwsgi_os == 'SunOS':
self.libs.append('-lsendfile')
self.gcc_list.append('lib/sun_fixes')
if not uwsgi_os_v.startswith('Nexenta'):
self.libs.remove('-rdynamic')