mirror of
https://github.com/clearlinux/uwsgi.git
synced 2026-08-18 19:45:48 +00:00
bad0edfc10
Reported by Coverity as CID #971006
471 lines
11 KiB
C
471 lines
11 KiB
C
#include "../uwsgi.h"
|
|
|
|
extern struct uwsgi_server uwsgi;
|
|
|
|
// generate a uwsgi signal on alarm
|
|
void uwsgi_alarm_init_signal(struct uwsgi_alarm_instance *uai) {
|
|
uai->data8 = atoi(uai->arg);
|
|
}
|
|
|
|
void uwsgi_alarm_func_signal(struct uwsgi_alarm_instance *uai, char *msg, size_t len) {
|
|
uwsgi_route_signal(uai->data8);
|
|
}
|
|
|
|
// simply log an alarm
|
|
void uwsgi_alarm_init_log(struct uwsgi_alarm_instance *uai) {
|
|
}
|
|
|
|
void uwsgi_alarm_func_log(struct uwsgi_alarm_instance *uai, char *msg, size_t len) {
|
|
if (msg[len-1] != '\n') {
|
|
if (uai->arg && strlen(uai->arg) > 0) {
|
|
uwsgi_log_verbose("ALARM: %s %.*s\n", uai->arg, len, msg);
|
|
}
|
|
else {
|
|
uwsgi_log_verbose("ALARM: %.*s\n", len, msg);
|
|
}
|
|
}
|
|
else {
|
|
if (uai->arg && strlen(uai->arg) > 0) {
|
|
uwsgi_log_verbose("ALARM: %s %.*s", uai->arg, len, msg);
|
|
}
|
|
else {
|
|
uwsgi_log_verbose("ALARM: %.*s", len, msg);
|
|
}
|
|
}
|
|
}
|
|
|
|
// run a command on alarm
|
|
void uwsgi_alarm_init_cmd(struct uwsgi_alarm_instance *uai) {
|
|
uai->data_ptr = uai->arg;
|
|
}
|
|
|
|
void uwsgi_alarm_func_cmd(struct uwsgi_alarm_instance *uai, char *msg, size_t len) {
|
|
int pipe[2];
|
|
if (socketpair(AF_UNIX, SOCK_STREAM, 0, pipe)) {
|
|
return;
|
|
}
|
|
uwsgi_socket_nb(pipe[0]);
|
|
uwsgi_socket_nb(pipe[1]);
|
|
if (write(pipe[1], msg, len) != (ssize_t) len) {
|
|
close(pipe[0]);
|
|
close(pipe[1]);
|
|
return;
|
|
}
|
|
uwsgi_run_command(uai->data_ptr, pipe, -1);
|
|
close(pipe[0]);
|
|
close(pipe[1]);
|
|
}
|
|
|
|
// pass the log line to a mule
|
|
|
|
void uwsgi_alarm_init_mule(struct uwsgi_alarm_instance *uai) {
|
|
uai->data32 = atoi(uai->arg);
|
|
if (uai->data32 > (uint32_t) uwsgi.mules_cnt) {
|
|
uwsgi_log_alarm("] invalid mule_id (%d mules available), fallback to 0\n", uwsgi.mules_cnt);
|
|
uai->data32 = 0;
|
|
}
|
|
}
|
|
|
|
void uwsgi_alarm_func_mule(struct uwsgi_alarm_instance *uai, char *msg, size_t len) {
|
|
// skip if mules are not available
|
|
if (uwsgi.mules_cnt == 0)
|
|
return;
|
|
int fd = uwsgi.shared->mule_queue_pipe[0];
|
|
if (uai->data32 > 0) {
|
|
int mule_id = uai->data32 - 1;
|
|
fd = uwsgi.mules[mule_id].queue_pipe[0];
|
|
}
|
|
mule_send_msg(fd, msg, len);
|
|
}
|
|
|
|
|
|
// register a new alarm
|
|
void uwsgi_register_alarm(char *name, void (*init) (struct uwsgi_alarm_instance *), void (*func) (struct uwsgi_alarm_instance *, char *, size_t)) {
|
|
struct uwsgi_alarm *old_ua = NULL, *ua = uwsgi.alarms;
|
|
while (ua) {
|
|
// skip already initialized alarms
|
|
if (!strcmp(ua->name, name)) {
|
|
return;
|
|
}
|
|
old_ua = ua;
|
|
ua = ua->next;
|
|
}
|
|
|
|
ua = uwsgi_calloc(sizeof(struct uwsgi_alarm));
|
|
ua->name = name;
|
|
ua->init = init;
|
|
ua->func = func;
|
|
|
|
if (old_ua) {
|
|
old_ua->next = ua;
|
|
}
|
|
else {
|
|
uwsgi.alarms = ua;
|
|
}
|
|
}
|
|
|
|
// register embedded alarms
|
|
void uwsgi_register_embedded_alarms() {
|
|
uwsgi_register_alarm("signal", uwsgi_alarm_init_signal, uwsgi_alarm_func_signal);
|
|
uwsgi_register_alarm("cmd", uwsgi_alarm_init_cmd, uwsgi_alarm_func_cmd);
|
|
uwsgi_register_alarm("mule", uwsgi_alarm_init_mule, uwsgi_alarm_func_mule);
|
|
uwsgi_register_alarm("log", uwsgi_alarm_init_log, uwsgi_alarm_func_log);
|
|
}
|
|
|
|
static int uwsgi_alarm_add(char *name, char *plugin, char *arg) {
|
|
struct uwsgi_alarm *ua = uwsgi.alarms;
|
|
while (ua) {
|
|
if (!strcmp(ua->name, plugin)) {
|
|
break;
|
|
}
|
|
ua = ua->next;
|
|
}
|
|
|
|
if (!ua)
|
|
return -1;
|
|
|
|
struct uwsgi_alarm_instance *old_uai = NULL, *uai = uwsgi.alarm_instances;
|
|
while (uai) {
|
|
old_uai = uai;
|
|
uai = uai->next;
|
|
}
|
|
|
|
uai = uwsgi_calloc(sizeof(struct uwsgi_alarm_instance));
|
|
uai->name = name;
|
|
uai->alarm = ua;
|
|
uai->arg = arg;
|
|
uai->last_msg = uwsgi_malloc(uwsgi.log_master_bufsize);
|
|
|
|
if (old_uai) {
|
|
old_uai->next = uai;
|
|
}
|
|
else {
|
|
uwsgi.alarm_instances = uai;
|
|
}
|
|
|
|
ua->init(uai);
|
|
return 0;
|
|
}
|
|
|
|
// get an alarm instance by its name
|
|
static struct uwsgi_alarm_instance *uwsgi_alarm_get_instance(char *name) {
|
|
struct uwsgi_alarm_instance *uai = uwsgi.alarm_instances;
|
|
while (uai) {
|
|
if (!strcmp(name, uai->name)) {
|
|
return uai;
|
|
}
|
|
uai = uai->next;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
#ifdef UWSGI_PCRE
|
|
static int uwsgi_alarm_log_add(char *alarms, char *regexp, int negate) {
|
|
|
|
struct uwsgi_alarm_log *old_ual = NULL, *ual = uwsgi.alarm_logs;
|
|
while (ual) {
|
|
old_ual = ual;
|
|
ual = ual->next;
|
|
}
|
|
|
|
ual = uwsgi_calloc(sizeof(struct uwsgi_alarm_log));
|
|
if (uwsgi_regexp_build(regexp, &ual->pattern, &ual->pattern_extra)) {
|
|
free(ual);
|
|
return -1;
|
|
}
|
|
ual->negate = negate;
|
|
|
|
if (old_ual) {
|
|
old_ual->next = ual;
|
|
}
|
|
else {
|
|
uwsgi.alarm_logs = ual;
|
|
}
|
|
|
|
// map instances to the log
|
|
char *list = uwsgi_str(alarms);
|
|
char *p, *ctx = NULL;
|
|
uwsgi_foreach_token(list, ",", p, ctx) {
|
|
struct uwsgi_alarm_instance *uai = uwsgi_alarm_get_instance(p);
|
|
if (!uai) {
|
|
free(list);
|
|
return -1;
|
|
}
|
|
struct uwsgi_alarm_ll *old_uall = NULL, *uall = ual->alarms;
|
|
while (uall) {
|
|
old_uall = uall;
|
|
uall = uall->next;
|
|
}
|
|
|
|
uall = uwsgi_calloc(sizeof(struct uwsgi_alarm_ll));
|
|
uall->alarm = uai;
|
|
if (old_uall) {
|
|
old_uall->next = uall;
|
|
}
|
|
else {
|
|
ual->alarms = uall;
|
|
}
|
|
}
|
|
free(list);
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
static void uwsgi_alarm_thread_loop(struct uwsgi_thread *ut) {
|
|
// add uwsgi_alarm_fd;
|
|
struct uwsgi_alarm_fd *uafd = uwsgi.alarm_fds;
|
|
while(uafd) {
|
|
event_queue_add_fd_read(ut->queue, uafd->fd);
|
|
uafd = uafd->next;
|
|
}
|
|
char *buf = uwsgi_malloc(uwsgi.alarm_msg_size + sizeof(long));
|
|
for (;;) {
|
|
int interesting_fd = -1;
|
|
int ret = event_queue_wait(ut->queue, -1, &interesting_fd);
|
|
if (ret > 0) {
|
|
if (interesting_fd == ut->pipe[1]) {
|
|
ssize_t len = read(ut->pipe[1], buf, uwsgi.alarm_msg_size + sizeof(long));
|
|
if (len > (ssize_t)(sizeof(long) + 1)) {
|
|
size_t msg_size = len - sizeof(long);
|
|
char *msg = buf + sizeof(long);
|
|
long ptr = 0;
|
|
memcpy(&ptr, buf, sizeof(long));
|
|
struct uwsgi_alarm_instance *uai = (struct uwsgi_alarm_instance *) ptr;
|
|
if (!uai)
|
|
break;
|
|
uwsgi_alarm_run(uai, msg, msg_size);
|
|
}
|
|
}
|
|
// check for alarm_fd
|
|
else {
|
|
uafd = uwsgi.alarm_fds;
|
|
int fd_read = 0;
|
|
while(uafd) {
|
|
if (interesting_fd == uafd->fd) {
|
|
if (fd_read) goto raise;
|
|
size_t remains = uafd->buf_len;
|
|
while(remains) {
|
|
ssize_t len = read(uafd->fd, uafd->buf + (uafd->buf_len-remains), remains);
|
|
if (len <= 0) {
|
|
uwsgi_error("[uwsgi-alarm-fd]/read()");
|
|
uwsgi_log("[uwsgi-alarm-fd] i will stop monitoring fd %d\n", uafd->fd);
|
|
event_queue_del_fd(ut->queue, uafd->fd, event_queue_read());
|
|
break;
|
|
}
|
|
remains-=len;
|
|
}
|
|
fd_read = 1;
|
|
raise:
|
|
uwsgi_alarm_run(uafd->alarm, uafd->msg, uafd->msg_len);
|
|
}
|
|
uafd = uafd->next;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
free(buf);
|
|
}
|
|
|
|
// initialize alarms, instances and log regexps
|
|
void uwsgi_alarms_init() {
|
|
|
|
if (!uwsgi.master_process) return;
|
|
|
|
// first of all, create instance of alarms
|
|
struct uwsgi_string_list *usl = uwsgi.alarm_list;
|
|
while (usl) {
|
|
char *line = uwsgi_str(usl->value);
|
|
char *space = strchr(line, ' ');
|
|
if (!space) {
|
|
uwsgi_log("invalid alarm syntax: %s\n", usl->value);
|
|
exit(1);
|
|
}
|
|
*space = 0;
|
|
char *plugin = space + 1;
|
|
char *colon = strchr(plugin, ':');
|
|
if (!colon) {
|
|
uwsgi_log("invalid alarm syntax: %s\n", usl->value);
|
|
exit(1);
|
|
}
|
|
*colon = 0;
|
|
char *arg = colon + 1;
|
|
// here the alarm is mapped to a name and initialized
|
|
if (uwsgi_alarm_add(line, plugin, arg)) {
|
|
uwsgi_log("invalid alarm: %s\n", usl->value);
|
|
exit(1);
|
|
}
|
|
usl = usl->next;
|
|
}
|
|
|
|
if (!uwsgi.alarm_instances) return;
|
|
|
|
// map alarm file descriptors
|
|
usl = uwsgi.alarm_fd_list;
|
|
while(usl) {
|
|
char *space0 = strchr(usl->value, ' ');
|
|
if (!space0) {
|
|
uwsgi_log("invalid alarm-fd syntax: %s\n", usl->value);
|
|
exit(1);
|
|
}
|
|
*space0 = 0;
|
|
size_t buf_len = 1;
|
|
char *space1 = strchr(space0+1, ' ');
|
|
if (!space1) {
|
|
uwsgi_log("invalid alarm-fd syntax: %s\n", usl->value);
|
|
exit(1);
|
|
}
|
|
|
|
char *colon = strchr(space0+1, ':');
|
|
if (colon) {
|
|
buf_len = strtoul(colon+1, NULL, 10);
|
|
*colon = 0;
|
|
}
|
|
int fd = atoi(space0+1);
|
|
uwsgi_add_alarm_fd(fd, usl->value, buf_len, space1+1, strlen(space1+1));
|
|
*space0 = ' ';
|
|
*space1 = ' ';
|
|
if (colon) {
|
|
*colon = ':';
|
|
}
|
|
usl = usl->next;
|
|
}
|
|
|
|
#ifdef UWSGI_PCRE
|
|
// then map log-alarm
|
|
usl = uwsgi.alarm_logs_list;
|
|
while (usl) {
|
|
char *line = uwsgi_str(usl->value);
|
|
char *space = strchr(line, ' ');
|
|
if (!space) {
|
|
uwsgi_log("invalid log-alarm syntax: %s\n", usl->value);
|
|
exit(1);
|
|
}
|
|
*space = 0;
|
|
char *regexp = space + 1;
|
|
// here the log-alarm is created
|
|
if (uwsgi_alarm_log_add(line, regexp, usl->custom)) {
|
|
uwsgi_log("invalid log-alarm: %s\n", usl->value);
|
|
exit(1);
|
|
}
|
|
|
|
usl = usl->next;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void uwsgi_alarm_thread_start() {
|
|
if (!uwsgi.alarm_instances) return;
|
|
// start the alarm_thread
|
|
uwsgi.alarm_thread = uwsgi_thread_new(uwsgi_alarm_thread_loop);
|
|
if (!uwsgi.alarm_thread) {
|
|
uwsgi_log("unable to spawn alarm thread\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
void uwsgi_alarm_trigger_uai(struct uwsgi_alarm_instance *uai, char *msg, size_t len) {
|
|
struct iovec iov[2];
|
|
iov[0].iov_base = &uai;
|
|
iov[0].iov_len = sizeof(long);
|
|
iov[1].iov_base = msg;
|
|
iov[1].iov_len = len;
|
|
|
|
// now send the message to the alarm thread
|
|
if (writev(uwsgi.alarm_thread->pipe[0], iov, 2) != (ssize_t) (len+sizeof(long))) {
|
|
uwsgi_error("[uwsgi-alarm-error] uwsgi_alarm_trigger()/writev()");
|
|
}
|
|
}
|
|
|
|
#ifdef UWSGI_PCRE
|
|
// check if a log should raise an alarm
|
|
void uwsgi_alarm_log_check(char *msg, size_t len) {
|
|
if (!uwsgi_strncmp(msg, len, "[uwsgi-alarm", 12))
|
|
return;
|
|
struct uwsgi_alarm_log *ual = uwsgi.alarm_logs;
|
|
while (ual) {
|
|
if (uwsgi_regexp_match(ual->pattern, ual->pattern_extra, msg, len) >= 0) {
|
|
if (!ual->negate) {
|
|
struct uwsgi_alarm_ll *uall = ual->alarms;
|
|
while (uall) {
|
|
if (uwsgi.alarm_cheap)
|
|
uwsgi_alarm_trigger_uai(uall->alarm, msg, len);
|
|
else
|
|
uwsgi_alarm_run(uall->alarm, msg, len);
|
|
uall = uall->next;
|
|
}
|
|
}
|
|
else {
|
|
break;
|
|
}
|
|
}
|
|
ual = ual->next;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// call the alarm func
|
|
void uwsgi_alarm_run(struct uwsgi_alarm_instance *uai, char *msg, size_t len) {
|
|
time_t now = uwsgi_now();
|
|
// avoid alarm storming/loop if last message is the same
|
|
if (!uwsgi_strncmp(msg, len, uai->last_msg, uai->last_msg_size)) {
|
|
if (now - uai->last_run < uwsgi.alarm_freq)
|
|
return;
|
|
}
|
|
uai->alarm->func(uai, msg, len);
|
|
uai->last_run = uwsgi_now();
|
|
memcpy(uai->last_msg, msg, len);
|
|
uai->last_msg_size = len;
|
|
}
|
|
|
|
// this is the api function workers,mules and whatever you want can call from code
|
|
void uwsgi_alarm_trigger(char *alarm_instance_name, char *msg, size_t len) {
|
|
if (!uwsgi.alarm_thread) return;
|
|
if (len > uwsgi.alarm_msg_size) return;
|
|
struct uwsgi_alarm_instance *uai = uwsgi_alarm_get_instance(alarm_instance_name);
|
|
if (!uai) return;
|
|
|
|
uwsgi_alarm_trigger_uai(uai, msg, len);
|
|
}
|
|
|
|
struct uwsgi_alarm_fd *uwsgi_add_alarm_fd(int fd, char *alarm, size_t buf_len, char *msg, size_t msg_len) {
|
|
struct uwsgi_alarm_fd *old_uafd = NULL, *uafd = uwsgi.alarm_fds;
|
|
struct uwsgi_alarm_instance *uai = uwsgi_alarm_get_instance(alarm);
|
|
if (!uai) {
|
|
uwsgi_log("unable to find alarm \"%s\"\n", alarm);
|
|
exit(1);
|
|
}
|
|
|
|
if (!buf_len) buf_len = 1;
|
|
|
|
while(uafd) {
|
|
// check if an equal alarm has been added
|
|
if (uafd->fd == fd && uafd->alarm == uai) {
|
|
return uafd;
|
|
}
|
|
old_uafd = uafd;
|
|
uafd = uafd->next;
|
|
}
|
|
|
|
uafd = uwsgi_calloc(sizeof(struct uwsgi_alarm_fd));
|
|
uafd->fd = fd;
|
|
uafd->buf = uwsgi_malloc(buf_len);
|
|
uafd->buf_len = buf_len;
|
|
uafd->msg = msg;
|
|
uafd->msg_len = msg_len;
|
|
uafd->alarm = uai;
|
|
|
|
if (!old_uafd) {
|
|
uwsgi.alarm_fds = uafd;
|
|
}
|
|
else {
|
|
old_uafd->next = uafd;
|
|
}
|
|
|
|
// avoid the fd to be closed
|
|
uwsgi_add_safe_fd(fd);
|
|
uwsgi_log("[uwsgi-alarm] added fd %d\n", fd);
|
|
|
|
return uafd;
|
|
}
|