sammler/network.c

200 lines
4.2 KiB
C
Raw Normal View History

2006-08-03 19:49:07 +02:00
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
2006-09-30 20:27:56 +02:00
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
2006-08-03 19:49:07 +02:00
#include "configfile.h"
2007-04-01 00:17:50 +02:00
#include "event.h"
2006-10-08 16:33:07 +02:00
#include "helper.h"
2006-09-30 20:27:56 +02:00
#include "list.h"
2006-08-03 19:49:07 +02:00
#include "logging.h"
2006-09-30 20:27:56 +02:00
#include "network.h"
#include "plugins.h"
2006-09-30 20:27:56 +02:00
#include "rrdtool.h"
2006-08-03 19:49:07 +02:00
2006-10-11 16:47:48 +02:00
#define BUFSIZE 8192
2006-08-03 19:49:07 +02:00
2007-04-01 00:17:50 +02:00
struct fwd_addr {
struct list_head list;
struct sockaddr_in addr;
};
2006-10-08 16:33:07 +02:00
static int fwd_sock;
2007-04-01 00:17:50 +02:00
static LIST_HEAD(fwd_list);
2006-09-30 20:27:56 +02:00
// todo: never freed..
static char *tx_buf, *rx_buf;
2006-10-11 16:47:48 +02:00
static int tx_pos;
2006-09-30 20:27:56 +02:00
2007-04-01 13:21:51 +02:00
int net_submit(const char *hostname, const char *pluginname, const char *filename, int ds_id, const char *data)
2006-09-30 20:27:56 +02:00
{
2007-04-01 00:17:50 +02:00
if (list_empty(&fwd_list))
return 0;
2006-10-11 16:47:48 +02:00
int size = snprintf(tx_buf + tx_pos, BUFSIZE - tx_pos, "%s:%s:%s:%d %s\n",
2007-04-01 13:21:51 +02:00
hostname, pluginname, filename, ds_id, data);
2006-10-11 16:47:48 +02:00
if (size < 0 || size >= BUFSIZE - tx_pos) {
2006-09-30 20:27:56 +02:00
log_print(LOG_ERROR, "net_submit(): arguments too long");
2006-10-11 16:47:48 +02:00
// TODO: retry with flushed buffer?
2006-10-07 20:48:20 +02:00
return -1;
2006-09-30 20:27:56 +02:00
}
2006-10-11 16:47:48 +02:00
tx_pos += size;
2006-10-07 20:48:20 +02:00
return 0;
2006-09-30 20:27:56 +02:00
}
2007-04-01 00:17:50 +02:00
void net_submit_flush(void)
2006-09-30 20:27:56 +02:00
{
2007-04-01 00:17:50 +02:00
if (tx_pos == 0)
return;
struct fwd_addr *entry;
list_for_each_entry(entry, &fwd_list, list)
sendto(fwd_sock, tx_buf, tx_pos, 0, (struct sockaddr *)&entry->addr, sizeof(entry->addr));
2006-09-30 20:27:56 +02:00
2006-10-11 16:47:48 +02:00
tx_pos = 0;
}
2006-09-30 20:27:56 +02:00
2007-04-01 00:17:50 +02:00
static int net_receive(int socket, void *privdata)
2006-10-11 16:47:48 +02:00
{
int size = recv(socket, rx_buf, BUFSIZE, 0);
int rx_pos = 0;
char *delim;
while ((delim = memchr(rx_buf + rx_pos, '\n', size - rx_pos))) {
*delim = '\0';
2007-04-01 01:32:59 +02:00
char *data[2];
2006-10-11 16:47:48 +02:00
int ret = strsplit(rx_buf + rx_pos, " ", data, 2);
if (ret != 2) {
2007-04-01 01:32:59 +02:00
log_print(LOG_ERROR, "net_receive(): abort data-split");
2006-10-11 16:47:48 +02:00
continue;
}
2007-04-01 01:32:59 +02:00
char *part[4];
2006-10-11 16:47:48 +02:00
ret = strsplit(data[0], ":", part, 4);
if (ret != 4) {
2007-04-01 01:32:59 +02:00
log_print(LOG_ERROR, "net_receive(): abort header-split");
2006-10-11 16:47:48 +02:00
continue;
}
2007-04-01 01:32:59 +02:00
2007-04-01 13:21:51 +02:00
rrd_submit(part[0], part[1], part[2], atoi(part[3]), data[1]);
2006-10-11 16:47:48 +02:00
rx_pos = (delim - rx_buf) +1;
}
2006-09-30 20:27:56 +02:00
return 0;
}
2007-04-01 00:17:50 +02:00
static int parse_saddr(const char *addr, struct sockaddr_in *sa)
2007-03-31 22:15:00 +02:00
{
2007-04-01 00:17:50 +02:00
char *addr_cpy = strdup(addr);
if (addr_cpy == NULL) {
log_print(LOG_WARN, "parse_saddr(): out of memory");
return -1;
}
2007-03-31 22:15:00 +02:00
2007-04-01 00:17:50 +02:00
char *tmp;
char *ip = strtok_r(addr_cpy, ":", &tmp);
if (ip == NULL) {
free(addr_cpy);
2007-03-31 22:15:00 +02:00
return -1;
2007-04-01 00:17:50 +02:00
}
2007-03-31 22:15:00 +02:00
2007-04-01 00:17:50 +02:00
char *port = strtok_r(NULL, ":", &tmp);
if (port == NULL) {
free(addr_cpy);
2007-03-31 22:15:00 +02:00
return -1;
2007-04-01 00:17:50 +02:00
}
2007-03-31 22:15:00 +02:00
sa->sin_family = AF_INET;
2007-04-01 00:17:50 +02:00
sa->sin_port = htons(atoi(port));
int ret = inet_aton(ip, &sa->sin_addr);
2007-03-31 22:15:00 +02:00
2007-04-01 00:17:50 +02:00
free(addr_cpy);
return (ret != 0) ? 0 : -1;
2007-03-31 22:15:00 +02:00
}
2007-04-01 00:17:50 +02:00
static int net_init_srv_cb(const char *value, void *privdata)
2006-08-03 19:49:07 +02:00
{
2007-04-01 00:17:50 +02:00
struct sockaddr_in addr;
if (parse_saddr(value, &addr) == -1) {
log_print(LOG_WARN, "invalid listen addr: '%s'", value);
2006-09-30 20:27:56 +02:00
return -1;
2007-04-01 00:17:50 +02:00
}
2006-08-03 19:49:07 +02:00
2007-04-01 00:17:50 +02:00
int sock = socket(PF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
log_print(LOG_ERROR, "net_init_srv_cb(): socket()");
2006-10-07 20:48:20 +02:00
return -1;
}
2006-09-30 20:27:56 +02:00
2007-04-01 00:17:50 +02:00
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
log_print(LOG_ERROR, "net_init_srv_cb(): bind()");
close(sock);
2006-10-07 20:48:20 +02:00
return -1;
2006-09-30 20:27:56 +02:00
}
2007-04-01 00:17:50 +02:00
event_add_readfd(NULL, sock, net_receive, NULL);
log_print(LOG_INFO, "listen on %s:%d",
inet_ntoa(addr.sin_addr),
ntohs(addr.sin_port));
2006-10-08 16:33:07 +02:00
return 0;
2006-08-03 19:49:07 +02:00
}
2007-04-01 00:17:50 +02:00
static int net_init_cli_cb(const char *value, void *privdata)
2006-08-03 19:49:07 +02:00
{
2007-04-01 00:17:50 +02:00
struct fwd_addr *entry = malloc(sizeof(struct fwd_addr));
if (entry == NULL) {
log_print(LOG_ERROR, "net_init_cli_cb(): out of memory");
2006-09-30 20:27:56 +02:00
return -1;
2007-04-01 00:17:50 +02:00
}
2006-09-30 20:27:56 +02:00
2007-04-01 00:17:50 +02:00
if (parse_saddr(value, &entry->addr) == -1) {
log_print(LOG_WARN, "invalid listen addr: '%s'", value);
free(entry);
2006-09-30 20:27:56 +02:00
return -1;
}
2007-04-01 00:17:50 +02:00
list_add(&entry->list, &fwd_list);
log_print(LOG_INFO, "forwarding to %s:%d",
inet_ntoa(entry->addr.sin_addr),
ntohs(entry->addr.sin_port));
return 0;
}
int net_init(void)
{
int srv_cnt = config_get_strings("global", "listen", net_init_srv_cb, NULL);
if (srv_cnt > 0) {
rx_buf = malloc(BUFSIZE);
if (rx_buf == NULL) {
log_print(LOG_ERROR, "net_init(): out of memory");
return -1;
}
2006-09-30 20:27:56 +02:00
}
2007-04-01 00:17:50 +02:00
int cli_cnt = config_get_strings("global", "forward", net_init_cli_cb, NULL);
if (cli_cnt > 0) {
tx_buf = malloc(BUFSIZE);
if (tx_buf == NULL) {
log_print(LOG_ERROR, "net_init(): out of memory");
return -1;
}
fwd_sock = socket(PF_INET, SOCK_DGRAM, 0);
if (fwd_sock < 0) {
log_print(LOG_ERROR, "net_init(): socket()");
return -1;
}
2006-09-30 20:27:56 +02:00
}
2006-08-03 19:49:07 +02:00
2007-04-01 00:17:50 +02:00
return 0;
2006-08-03 19:49:07 +02:00
}