diff --git a/Makefile b/Makefile index 658078b..145ee68 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ CFLAGS += -Wall -Wextra LDLIBS += -pthread -lcurl STRIP = strip VERSION = v0.1 -OBJS = alertik.o events.o env_events.o notifiers.o log.o +OBJS = alertik.o events.o env_events.o notifiers.o log.o syslog.o ifeq ($(LOG_FILE),yes) CFLAGS += -DUSE_FILE_AS_LOG diff --git a/alertik.c b/alertik.c index 3d0f811..746f7e5 100644 --- a/alertik.c +++ b/alertik.c @@ -23,137 +23,20 @@ #include "env_events.h" #include "log.h" #include "notifiers.h" - -/* Uncomment/comment to enable/disable the following settings. */ -// #define USE_FILE_AS_LOG /* stdout if commented. */ - -#define FIFO_MAX 64 -#define SYSLOG_PORT 5140 - -/* Circular message buffer. */ -static struct circ_buffer { - int head; - int tail; - struct log_event log_ev [FIFO_MAX]; -} circ_buffer = {0}; - -/* Sync. */ -static pthread_mutex_t fifo_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_cond_t fifo_new_log_entry = PTHREAD_COND_INITIALIZER; +#include "syslog.h" /* Misc. */ #define LAST_SENT_THRESHOLD_SECS 10 /* Minimum time (in secs) between two */ time_t time_last_sent_notify; /* notifications. */ -/////////////////////////////////// NETWORK /////////////////////////////////// -static int push_msg_into_fifo(const char *msg, time_t timestamp); -static int create_socket(void) -{ - struct sockaddr_in svaddr; - int yes; - int fd; - - fd = socket(AF_INET, SOCK_DGRAM, 0); - if (fd < 0) - panic_errno("Unable to create UDP socket..."); - - memset(&svaddr, 0, sizeof(svaddr)); - svaddr.sin_family = AF_INET; - svaddr.sin_addr.s_addr = INADDR_ANY; - svaddr.sin_port = SYSLOG_PORT; - - if (bind(fd, (const struct sockaddr *)&svaddr, sizeof(svaddr)) < 0) - panic_errno("Unable to bind..."); - - yes = 1; - if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, - sizeof(yes)) < 0) { - panic_errno("Unable to reuse address..."); - } - - return fd; -} - -static int read_new_upd_msg(int fd) -{ - struct sockaddr_storage cli; - char msg[MSG_MAX] = {0}; - socklen_t clilen; - ssize_t ret; - - ret = recvfrom(fd, msg, sizeof msg - 1, 0, (struct sockaddr*)&cli, - &clilen); - - if (ret < 0) - return -1; - - if (push_msg_into_fifo(msg, time(NULL)) < 0) - panic("Circular buffer full! (size: %d)\n", FIFO_MAX); - - return 0; -} - -///////////////////////////////// FIFO //////////////////////////////////////// - -static int push_msg_into_fifo(const char *msg, time_t timestamp) -{ - int next; - int head; - - pthread_mutex_lock(&fifo_mutex); - head = circ_buffer.head; - next = head + 1; - if (next >= FIFO_MAX) - next = 0; - - if (next == circ_buffer.tail) { - pthread_mutex_unlock(&fifo_mutex); - return -1; - } - - memcpy(circ_buffer.log_ev[head].msg, msg, MSG_MAX); - circ_buffer.log_ev[head].timestamp = timestamp; - - circ_buffer.head = next; - pthread_cond_signal(&fifo_new_log_entry); - pthread_mutex_unlock(&fifo_mutex); - - return 0; -} - -static int pop_msg_from_fifo(struct log_event *ev) -{ - int next; - int tail; - - pthread_mutex_lock(&fifo_mutex); - while (circ_buffer.head == circ_buffer.tail) { - pthread_cond_wait(&fifo_new_log_entry, &fifo_mutex); - } - - next = circ_buffer.tail + 1; - if (next >= FIFO_MAX) - next = 0; - - tail = circ_buffer.tail; - ev->timestamp = circ_buffer.log_ev[tail].timestamp; - memcpy(ev->msg, circ_buffer.log_ev[tail].msg, MSG_MAX); - - circ_buffer.tail = next; - pthread_mutex_unlock(&fifo_mutex); - - return 0; -} - -///////////////////////////// MESSAGE HANDLING //////////////////////////////// static void *handle_messages(void *p) { ((void)p); size_t i; struct log_event ev = {0}; - while (pop_msg_from_fifo(&ev) >= 0) { + while (syslog_pop_msg_from_fifo(&ev) >= 0) { print_log_event(&ev); if ((time(NULL) - time_last_sent_notify) <= LAST_SENT_THRESHOLD_SECS) { @@ -189,12 +72,12 @@ int main(void) log_msg(" (https://github.com/Theldus/alertik)\n"); log_msg("-------------------------------------------------\n"); - fd = create_socket(); + fd = syslog_create_udp_socket(); if (pthread_create(&handler, NULL, handle_messages, NULL)) panic_errno("Unable to create hanler thread!"); log_msg("Waiting for messages at :%d (UDP)...\n", SYSLOG_PORT); - while (read_new_upd_msg(fd) >= 0); + while (syslog_enqueue_new_upd_msg(fd) >= 0); return EXIT_SUCCESS; } diff --git a/alertik.h b/alertik.h index d7412c6..8a2140d 100644 --- a/alertik.h +++ b/alertik.h @@ -10,18 +10,6 @@ #include #include - #define panic_errno(s) \ - do {\ - log_msg("%s: %s", (s), strerror(errno)); \ - exit(EXIT_FAILURE); \ - } while(0); - - #define panic(...) \ - do {\ - log_msg(__VA_ARGS__); \ - exit(EXIT_FAILURE); \ - } while(0); - #define MIN(a,b) (((a)<(b))?(a):(b)) extern time_t time_last_sent_notify; diff --git a/log.c b/log.c index 4062c13..23ac3e7 100644 --- a/log.c +++ b/log.c @@ -30,10 +30,10 @@ static inline void open_log_file(void) if (curr_file == STDOUT_FILENO) return; - if (stat("log", &sb) < 0) + if (stat("log", &sb) < 0) { if (mkdir("log", 0755) < 0) return; - + } curr_file = openat(AT_FDCWD, LOG_FILE, O_WRONLY|O_CREAT|O_APPEND, 0666); @@ -46,7 +46,6 @@ static void close_log_file(void) { if (curr_file || curr_file == STDOUT_FILENO) goto out; - fsync(curr_file); close(curr_file); out: diff --git a/log.h b/log.h index ab292ed..d9391e7 100644 --- a/log.h +++ b/log.h @@ -6,9 +6,23 @@ #ifndef LOG_H #define LOG_H + #include "events.h" + /* Uncomment/comment to enable/disable the following settings. */ // #define USE_FILE_AS_LOG /* stdout if commented. */ + #define panic_errno(s) \ + do {\ + log_msg("%s: %s", (s), strerror(errno)); \ + exit(EXIT_FAILURE); \ + } while(0); + + #define panic(...) \ + do {\ + log_msg(__VA_ARGS__); \ + exit(EXIT_FAILURE); \ + } while(0); + #define LOG_FILE "log/log.txt" extern char *get_formatted_time(time_t time, char *time_str); diff --git a/syslog.c b/syslog.c new file mode 100644 index 0000000..7fa9be1 --- /dev/null +++ b/syslog.c @@ -0,0 +1,138 @@ +/* + * Alertik: a tiny 'syslog' server & notification tool for Mikrotik routers. + * This is free and unencumbered software released into the public domain. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "log.h" +#include "syslog.h" + +/* + * UDP message handling and FIFO. + */ + +/* Circular message buffer. */ +static struct circ_buffer { + int head; + int tail; + struct log_event log_ev [FIFO_MAX]; +} circ_buffer = {0}; + +/* Sync. */ +static pthread_mutex_t fifo_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t fifo_new_log_entry = PTHREAD_COND_INITIALIZER; +static int syslog_push_msg_into_fifo(const char *, time_t); + + +/* Create an UDP socket to read from. */ +int syslog_create_udp_socket(void) +{ + struct sockaddr_in svaddr; + int yes; + int fd; + + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) + panic_errno("Unable to create UDP socket..."); + + memset(&svaddr, 0, sizeof(svaddr)); + svaddr.sin_family = AF_INET; + svaddr.sin_addr.s_addr = INADDR_ANY; + svaddr.sin_port = SYSLOG_PORT; + + if (bind(fd, (const struct sockaddr *)&svaddr, sizeof(svaddr)) < 0) + panic_errno("Unable to bind..."); + + yes = 1; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, + sizeof(yes)) < 0) { + panic_errno("Unable to reuse address..."); + } + + return fd; +} + +/**/ +int syslog_enqueue_new_upd_msg(int fd) +{ + struct sockaddr_storage cli; + char msg[MSG_MAX] = {0}; + socklen_t clilen; + ssize_t ret; + + ret = recvfrom(fd, msg, sizeof msg - 1, 0, (struct sockaddr*)&cli, + &clilen); + + if (ret < 0) + return -1; + + if (syslog_push_msg_into_fifo(msg, time(NULL)) < 0) + panic("Circular buffer full! (size: %d)\n", FIFO_MAX); + + return 0; +} + + + +///////////////////////////////// FIFO //////////////////////////////////////// +static int syslog_push_msg_into_fifo(const char *msg, time_t timestamp) +{ + int next; + int head; + + pthread_mutex_lock(&fifo_mutex); + head = circ_buffer.head; + next = head + 1; + if (next >= FIFO_MAX) + next = 0; + + if (next == circ_buffer.tail) { + pthread_mutex_unlock(&fifo_mutex); + return -1; + } + memcpy(circ_buffer.log_ev[head].msg, msg, MSG_MAX); + circ_buffer.log_ev[head].timestamp = timestamp; + + circ_buffer.head = next; + pthread_cond_signal(&fifo_new_log_entry); + pthread_mutex_unlock(&fifo_mutex); + return 0; +} + +int syslog_pop_msg_from_fifo(struct log_event *ev) +{ + int next; + int tail; + + pthread_mutex_lock(&fifo_mutex); + while (circ_buffer.head == circ_buffer.tail) { + pthread_cond_wait(&fifo_new_log_entry, &fifo_mutex); + } + + next = circ_buffer.tail + 1; + if (next >= FIFO_MAX) + next = 0; + + tail = circ_buffer.tail; + ev->timestamp = circ_buffer.log_ev[tail].timestamp; + memcpy(ev->msg, circ_buffer.log_ev[tail].msg, MSG_MAX); + + circ_buffer.tail = next; + pthread_mutex_unlock(&fifo_mutex); + return 0; +} diff --git a/syslog.h b/syslog.h new file mode 100644 index 0000000..d73f6c4 --- /dev/null +++ b/syslog.h @@ -0,0 +1,16 @@ +/* + * Alertik: a tiny 'syslog' server & notification tool for Mikrotik routers. + * This is free and unencumbered software released into the public domain. + */ + +#ifndef SYSLOG_H +#define SYSLOG_H + + #define FIFO_MAX 64 + #define SYSLOG_PORT 5140 + + extern int syslog_create_udp_socket(void); + extern int syslog_enqueue_new_upd_msg(int fd); + extern int syslog_pop_msg_from_fifo(struct log_event *ev); + +#endif /* SYSLOG_H */