diff options
author | Dmitry Kozlov <xeb@mail.ru> | 2010-11-15 19:35:33 +0300 |
---|---|---|
committer | Dmitry Kozlov <xeb@mail.ru> | 2010-11-15 19:35:33 +0300 |
commit | 06ea9ff88577821f6f125318c6c4d51cc48a3b17 (patch) | |
tree | 78952e683d006de61aebc6561aea108a3a094b4a | |
parent | b85986e561d4fc6532c0666e38014b51b66f485a (diff) | |
download | accel-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.5 | 6 | ||||
-rw-r--r-- | accel-pptpd/log.c | 2 | ||||
-rw-r--r-- | accel-pptpd/log.h | 2 | ||||
-rw-r--r-- | accel-pptpd/logs/CMakeLists.txt | 4 | ||||
-rw-r--r-- | accel-pptpd/logs/log_file.c | 6 | ||||
-rw-r--r-- | accel-pptpd/logs/log_pgsql.c | 2 | ||||
-rw-r--r-- | accel-pptpd/logs/log_tcp.c | 291 |
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); +} + |