summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Kozlov <xeb@mail.ru>2010-11-15 19:35:33 +0300
committerDmitry Kozlov <xeb@mail.ru>2010-11-15 19:35:33 +0300
commit06ea9ff88577821f6f125318c6c4d51cc48a3b17 (patch)
tree78952e683d006de61aebc6561aea108a3a094b4a
parentb85986e561d4fc6532c0666e38014b51b66f485a (diff)
downloadaccel-ppp-xebd-06ea9ff88577821f6f125318c6c4d51cc48a3b17.tar.gz
accel-ppp-xebd-06ea9ff88577821f6f125318c6c4d51cc48a3b17.zip
log: implemented log_tcp logging target which sends logs to specified host over tcp/ip
-rw-r--r--accel-pptpd/accel-pptp.conf.56
-rw-r--r--accel-pptpd/log.c2
-rw-r--r--accel-pptpd/log.h2
-rw-r--r--accel-pptpd/logs/CMakeLists.txt4
-rw-r--r--accel-pptpd/logs/log_file.c6
-rw-r--r--accel-pptpd/logs/log_pgsql.c2
-rw-r--r--accel-pptpd/logs/log_tcp.c291
7 files changed, 306 insertions, 7 deletions
diff --git a/accel-pptpd/accel-pptp.conf.5 b/accel-pptpd/accel-pptp.conf.5
index 4090153..f7266a9 100644
--- a/accel-pptpd/accel-pptp.conf.5
+++ b/accel-pptpd/accel-pptp.conf.5
@@ -29,6 +29,9 @@ containes list of modules to load
.BI log_file
This is logging target which logs messages to files. It support per-session/per-user features.
.TP
+.BI log_tcp
+This is logging target which logs messages over TCP/IP.
+.TP
.BI log_pgsql
This is logging target which logs messages to PostgreSQL.
.TP
@@ -248,6 +251,9 @@ Path to file to write general log.
.BI "log-emerg=" file
Path to file to write emergency messages.
.TP
+.BI "log-tcp=" x.x.x.x:port
+Send logs to specified host.
+.TP
.BI "copy=" n
If this options is given and greater then zero logging engine will duplicate session log in general log.
(Useful when per-session/per-user logs are not used)
diff --git a/accel-pptpd/log.c b/accel-pptpd/log.c
index 6fd60bc..e8f47b6 100644
--- a/accel-pptpd/log.c
+++ b/accel-pptpd/log.c
@@ -87,7 +87,7 @@ static void do_log(int level, const char *fmt, va_list ap, struct ppp_t *ppp)
m = clone_msg(cur_msg);
if (!m)
break;
- t->log(m, ppp);
+ t->log(t, m, ppp);
}
out:
diff --git a/accel-pptpd/log.h b/accel-pptpd/log.h
index 140dad1..ac2b799 100644
--- a/accel-pptpd/log.h
+++ b/accel-pptpd/log.h
@@ -39,7 +39,7 @@ struct log_target_t
{
struct list_head entry;
- void (*log)(struct log_msg_t *, struct ppp_t *ppp);
+ void (*log)(struct log_target_t *, struct log_msg_t *, struct ppp_t *ppp);
void (*reopen)(void);
};
diff --git a/accel-pptpd/logs/CMakeLists.txt b/accel-pptpd/logs/CMakeLists.txt
index b2c432d..ffcdc2f 100644
--- a/accel-pptpd/logs/CMakeLists.txt
+++ b/accel-pptpd/logs/CMakeLists.txt
@@ -1,7 +1,9 @@
ADD_LIBRARY(log_file SHARED log_file.c)
TARGET_LINK_LIBRARIES(log_file rt)
-INSTALL(TARGETS log_file
+ADD_LIBRARY(log_tcp SHARED log_tcp.c)
+
+INSTALL(TARGETS log_file log_tcp
LIBRARY DESTINATION usr/lib/accel-pptp
)
diff --git a/accel-pptpd/logs/log_file.c b/accel-pptpd/logs/log_file.c
index f343286..db08aa2 100644
--- a/accel-pptpd/logs/log_file.c
+++ b/accel-pptpd/logs/log_file.c
@@ -261,7 +261,7 @@ static void set_hdr(struct log_msg_t *msg, struct ppp_t *ppp)
msg->hdr->len = strlen(msg->hdr->msg);
}
-static void general_log(struct log_msg_t *msg, struct ppp_t *ppp)
+static void general_log(struct log_target_t *t, struct log_msg_t *msg, struct ppp_t *ppp)
{
if (ppp && !conf_copy) {
log_free_msg(msg);
@@ -286,7 +286,7 @@ static struct log_file_pd_t *find_pd(struct ppp_t *ppp, void *pd_key)
return NULL;
}
-static void per_user_log(struct log_msg_t *msg, struct ppp_t *ppp)
+static void per_user_log(struct log_target_t *t, struct log_msg_t *msg, struct ppp_t *ppp)
{
struct log_file_pd_t *lpd;
@@ -306,7 +306,7 @@ static void per_user_log(struct log_msg_t *msg, struct ppp_t *ppp)
queue_log(&lpd->lf, msg);
}
-static void per_session_log(struct log_msg_t *msg, struct ppp_t *ppp)
+static void per_session_log(struct log_target_t *t, struct log_msg_t *msg, struct ppp_t *ppp)
{
struct log_file_pd_t *lpd;
diff --git a/accel-pptpd/logs/log_pgsql.c b/accel-pptpd/logs/log_pgsql.c
index 0eed243..99a0e82 100644
--- a/accel-pptpd/logs/log_pgsql.c
+++ b/accel-pptpd/logs/log_pgsql.c
@@ -193,7 +193,7 @@ static void queue_log(struct log_msg_t *msg)
}
-static void general_log(struct log_msg_t *msg, struct ppp_t *ppp)
+static void general_log(struct log_target_t *t, struct log_msg_t *msg, struct ppp_t *ppp)
{
set_hdr(msg, ppp);
queue_log(msg);
diff --git a/accel-pptpd/logs/log_tcp.c b/accel-pptpd/logs/log_tcp.c
new file mode 100644
index 0000000..2579ac2
--- /dev/null
+++ b/accel-pptpd/logs/log_tcp.c
@@ -0,0 +1,291 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#include "log.h"
+#include "triton.h"
+#include "events.h"
+#include "ppp.h"
+#include "spinlock.h"
+#include "mempool.h"
+
+#include "memdebug.h"
+
+struct tcp_target_t
+{
+ struct log_target_t target;
+ struct list_head entry;
+ struct triton_md_handler_t hnd;
+ struct triton_timer_t conn_timer;
+ struct sockaddr_in addr;
+ char *buf;
+ int buf_size;
+ int buf_pos;
+ spinlock_t lock;
+ struct list_head queue;
+ int queue_len;
+ int connected:1;
+ int wait:1;
+};
+
+static int conf_connect_interval = 5;
+static int conf_queue_len = 1000;
+
+static struct triton_context_t tcp_ctx;
+
+static const char* level_name[]={" msg", "error", " warn", " info", "debug"};
+
+static void start_connect(struct tcp_target_t *t);
+
+static void disconnect(struct tcp_target_t *t)
+{
+ triton_md_unregister_handler(&t->hnd);
+ close(t->hnd.fd);
+
+ start_connect(t);
+}
+
+static void unpack_msg(struct tcp_target_t *t, struct log_msg_t *msg)
+{
+ struct log_chunk_t *chunk;
+ int pos = strlen(msg->hdr->msg);
+
+ strcpy(t->buf, msg->hdr->msg);
+
+ list_for_each_entry(chunk, msg->chunks, entry) {
+ memcpy(t->buf + pos, chunk->msg, chunk->len);
+ pos += chunk->len;
+ }
+
+ t->buf_size = pos;
+ t->buf_pos = 0;
+}
+
+static int send_log(struct tcp_target_t *t)
+{
+ struct log_msg_t *msg;
+ int n;
+
+ while (1) {
+ spin_lock(&t->lock);
+ if (!t->queue_len) {
+ t->wait = 0;
+ spin_unlock(&t->lock);
+ return 0;
+ }
+ msg = list_entry(t->queue.next, typeof(*msg), entry);
+ list_del(&msg->entry);
+ t->queue_len--;
+ spin_unlock(&t->lock);
+
+ unpack_msg(t, msg);
+
+ log_free_msg(msg);
+
+ while (t->buf_pos != t->buf_size) {
+ n = write(t->hnd.fd, t->buf + t->buf_pos, t->buf_size - t->buf_pos);
+ if (n < 0) {
+ if (errno == EAGAIN)
+ return 1;
+ if (errno != EPIPE)
+ log_emerg("log-tcp: write: %s\n", strerror(errno));
+ disconnect(t);
+ return 0;
+ }
+ t->buf_pos += n;
+ }
+ }
+}
+
+static void queue_log(struct tcp_target_t *t, struct log_msg_t *msg)
+{
+ int r;
+
+ spin_lock(&t->lock);
+ if (t->queue_len == conf_queue_len) {
+ spin_unlock(&t->lock);
+ log_free_msg(msg);
+ }
+ list_add_tail(&msg->entry, &t->queue);
+ t->queue_len++;
+ if (t->connected) {
+ r = t->wait;
+ t->wait = 1;
+ } else
+ r = 1;
+ spin_unlock(&t->lock);
+
+ if (!r) {
+ if (send_log(t))
+ triton_md_enable_handler(&t->hnd, MD_MODE_WRITE);
+ }
+}
+
+static void set_hdr(struct log_msg_t *msg, struct ppp_t *ppp)
+{
+ struct tm tm;
+ char timestamp[32];
+
+ localtime_r(&msg->timestamp.tv_sec, &tm);
+
+ strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", &tm);
+ sprintf(msg->hdr->msg, "[%s]: %s: %s: ", timestamp, level_name[msg->level], ppp ? ppp->ifname : "");
+ msg->hdr->len = strlen(msg->hdr->msg);
+}
+
+static void general_log(struct log_target_t *lt, struct log_msg_t *msg, struct ppp_t *ppp)
+{
+ struct tcp_target_t *t = container_of(lt, typeof(*t), target);
+
+ set_hdr(msg, ppp);
+ queue_log(t, msg);
+}
+
+static int log_tcp_write(struct triton_md_handler_t *h)
+{
+ struct tcp_target_t *t = container_of(h, typeof(*t), hnd);
+
+ if (!send_log(t))
+ triton_md_disable_handler(h, MD_MODE_WRITE);
+
+ return 0;
+}
+
+static int log_tcp_connect(struct triton_md_handler_t *h)
+{
+ struct tcp_target_t *t = container_of(h, typeof(*t), hnd);
+
+ if (connect(t->hnd.fd, &t->addr, sizeof(t->addr))) {
+ if (errno == EAGAIN)
+ return 0;
+ if (errno == EINPROGRESS)
+ return 0;
+ log_emerg("log-tcp: connect: %s\n", strerror(errno));
+ triton_md_unregister_handler(&t->hnd);
+ close(t->hnd.fd);
+ triton_timer_add(&tcp_ctx, &t->conn_timer, 0);
+ return 0;
+ }
+
+ t->hnd.write = log_tcp_write;
+
+ triton_md_disable_handler(&t->hnd, MD_MODE_WRITE);
+
+ spin_lock(&t->lock);
+ t->connected = 1;
+ t->wait = 1;
+ spin_unlock(&t->lock);
+
+ send_log(t);
+
+ return 0;
+}
+
+static void connect_timer(struct triton_timer_t *timer)
+{
+ struct tcp_target_t *t = container_of(timer, typeof(*t), conn_timer);
+
+ triton_timer_del(timer);
+
+ start_connect(t);
+}
+
+static void start_connect(struct tcp_target_t *t)
+{
+ t->hnd.write = log_tcp_connect;
+ t->hnd.fd = socket(PF_INET, SOCK_STREAM, 0);
+
+ if (!t->hnd.fd) {
+ log_emerg("log-tcp: socket: %s\n", strerror(errno));
+ return;
+ }
+
+ if (fcntl(t->hnd.fd, F_SETFL, O_NONBLOCK)) {
+ log_emerg("log-tcp: failed to set nonblocking mode: %s\n", strerror(errno));
+ close(t->hnd.fd);
+ return;
+ }
+
+ if (connect(t->hnd.fd, &t->addr, sizeof(t->addr))) {
+ if (errno != EINPROGRESS) {
+ log_emerg("log-tcp: connect: %s\n", strerror(errno));
+ close(t->hnd.fd);
+ return;
+ }
+ }
+
+ triton_md_register_handler(&tcp_ctx, &t->hnd);
+ triton_md_enable_handler(&t->hnd, MD_MODE_WRITE);
+}
+
+static int start_log(const char *_opt)
+{
+ struct tcp_target_t *t;
+ char *opt = strdup(_opt);
+ int port;
+ char *d;
+
+ d = strchr(opt, ':');
+ if (!d)
+ goto err;
+
+ *d = 0;
+
+ port = atoi(d + 1);
+ if (port <= 0)
+ goto err;
+
+ t = _malloc(sizeof(*t));
+ memset(t, 0, sizeof(*t));
+
+ t->buf = _malloc(LOG_MAX_SIZE + 64);
+
+ t->conn_timer.expire_tv.tv_sec = conf_connect_interval;
+ t->conn_timer.expire = connect_timer;
+
+ t->target.log = general_log;
+
+ memset(&t->addr, 0, sizeof(t->addr));
+ t->addr.sin_family = AF_INET;
+ t->addr.sin_port = htons(port);
+ t->addr.sin_addr.s_addr = inet_addr(opt);
+
+ INIT_LIST_HEAD(&t->queue);
+
+ start_connect(t);
+
+ log_register_target(&t->target);
+
+ return 0;
+
+err:
+ free(opt);
+ return -1;
+}
+
+static void __init init(void)
+{
+ struct conf_sect_t *s = conf_get_section("log");
+ struct conf_option_t *opt;
+
+ if (!s)
+ return;
+
+ triton_context_register(&tcp_ctx, NULL);
+
+ list_for_each_entry(opt, &s->items, entry) {
+ if (strcmp(opt->name, "log-tcp"))
+ continue;
+ if (!opt->val || start_log(opt->val))
+ log_emerg("log: log-tcp: invalid format: '%s'\n", opt->val);
+ }
+
+ triton_context_wakeup(&tcp_ctx);
+}
+