sammler/network.c

207 lines
4.4 KiB
C
Raw Permalink 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>
2007-04-01 14:09:20 +02:00
#include <sys/ioctl.h>
2006-09-30 20:27:56 +02:00
#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"
2009-05-01 22:45:50 +02:00
#include "sockaddr.h"
2006-08-03 19:49:07 +02:00
2007-04-01 16:51:39 +02:00
#define PKTSIZE 1400
2006-08-03 19:49:07 +02:00
2007-04-01 14:09:20 +02:00
struct net_entry {
2007-04-01 00:17:50 +02:00
struct list_head list;
2007-04-01 14:09:20 +02:00
struct event_fd *event;
2007-04-01 00:17:50 +02:00
struct sockaddr_in addr;
2007-04-01 14:09:20 +02:00
int socket;
2007-04-01 00:17:50 +02:00
};
2007-04-01 14:09:20 +02:00
static LIST_HEAD(srv_list);
static LIST_HEAD(cli_list);
2006-09-30 20:27:56 +02:00
2007-04-01 14:09:20 +02:00
static char *fwd_buf;
static int fwd_buf_len;
void net_submit_flush(void)
{
if (fwd_buf_len == 0)
return;
struct net_entry *entry;
list_for_each_entry(entry, &cli_list, list)
sendto(entry->socket, fwd_buf, fwd_buf_len, 0, (struct sockaddr *)&entry->addr, sizeof(entry->addr));
fwd_buf_len = 0;
}
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 14:09:20 +02:00
if (list_empty(&cli_list))
2007-04-01 00:17:50 +02:00
return 0;
2007-04-01 16:51:39 +02:00
int size = snprintf(fwd_buf + fwd_buf_len, PKTSIZE - fwd_buf_len, "%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
2007-04-01 16:51:39 +02:00
if (size < 0 || size >= PKTSIZE - fwd_buf_len) {
2007-04-01 14:09:20 +02:00
/* the complete buffer is already full */
if (fwd_buf_len == 0) {
log_print(LOG_ERROR, "net_submit(): arguments too long");
return -1;
}
/* flush & retry */
net_submit_flush();
return net_submit(hostname, pluginname, filename, ds_id, data);
2006-09-30 20:27:56 +02:00
}
2007-04-01 14:09:20 +02:00
fwd_buf_len += size;
2006-10-07 20:48:20 +02:00
return 0;
2006-09-30 20:27:56 +02:00
}
2007-04-01 14:09:20 +02:00
static int net_receive(int socket, void *privdata)
2006-09-30 20:27:56 +02:00
{
2007-04-01 14:09:20 +02:00
int recvsize;
if (ioctl(socket, FIONREAD, &recvsize) == -1) {
log_print(LOG_WARN, "net_receive(): ioctl(FIONREAD)");
return 0;
}
2006-09-30 20:27:56 +02:00
2007-04-01 14:09:20 +02:00
char *buf = malloc(recvsize);
if (buf == NULL) {
log_print(LOG_WARN, "net_receive(): out of memory");
return 0;
}
2006-09-30 20:27:56 +02:00
2007-04-01 14:09:20 +02:00
int size = recv(socket, buf, recvsize, 0);
if (size <= 0) {
log_print(LOG_WARN, "net_receive(): recv()");
free(buf);
return 0;
}
2006-10-11 16:47:48 +02:00
2007-04-01 16:51:39 +02:00
char *delim;
int pos = 0;
while ((delim = memchr(buf + pos, '\n', size - pos)) != NULL) {
*delim = '\0';
char *data[2];
int ret = strsplit(buf + pos, " ", data, 2);
pos = (delim - buf) +1;
if (ret != 2) {
log_print(LOG_ERROR, "net_receive(): abort data-split");
continue;
}
2007-04-01 01:32:59 +02:00
2007-04-01 16:51:39 +02:00
char *part[4];
ret = strsplit(data[0], ":", part, 4);
if (ret != 4) {
log_print(LOG_ERROR, "net_receive(): abort header-split");
continue;
}
2006-10-11 16:47:48 +02:00
2007-04-01 16:51:39 +02:00
rrd_submit(part[0], part[1], part[2], atoi(part[3]), data[1]);
2006-10-11 16:47:48 +02:00
}
2007-04-01 14:09:20 +02:00
free(buf);
2006-09-30 20:27:56 +02:00
return 0;
}
2007-04-01 14:09:20 +02:00
static struct net_entry * create_net_entry(const char *value)
2006-08-03 19:49:07 +02:00
{
2007-04-01 14:09:20 +02:00
struct net_entry *entry = malloc(sizeof(struct net_entry));
if (entry == NULL)
return NULL;
2009-05-01 22:45:50 +02:00
if (parse_sockaddr(value, &entry->addr) < 0) {
2007-04-01 14:09:20 +02:00
free(entry);
return NULL;
}
entry->socket = socket(PF_INET, SOCK_DGRAM, 0);
if (entry->socket < 0) {
free(entry);
return NULL;
2007-04-01 00:17:50 +02:00
}
2006-08-03 19:49:07 +02:00
2007-04-01 14:09:20 +02:00
return entry;
}
static int net_init_srv_cb(const char *value, void *privdata)
{
struct net_entry *entry = create_net_entry(value);
if (entry == NULL) {
log_print(LOG_ERROR, "net_init_srv_cb(): can not create net_entry");
2006-10-07 20:48:20 +02:00
return -1;
}
2006-09-30 20:27:56 +02:00
2007-04-01 14:09:20 +02:00
if (bind(entry->socket, (struct sockaddr *)&entry->addr, sizeof(entry->addr)) < 0) {
2007-04-01 00:17:50 +02:00
log_print(LOG_ERROR, "net_init_srv_cb(): bind()");
2007-04-01 14:09:20 +02:00
close(entry->socket);
free(entry);
2006-10-07 20:48:20 +02:00
return -1;
2006-09-30 20:27:56 +02:00
}
2007-04-01 14:09:20 +02:00
entry->event = event_add_readfd(NULL, entry->socket, net_receive, NULL);
2007-04-07 19:49:04 +02:00
list_add(&entry->list, &srv_list);
2009-05-01 22:45:50 +02:00
log_print(LOG_INFO, "listen on %s", get_sockaddr_buf(&entry->addr));
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 14:09:20 +02:00
struct net_entry *entry = create_net_entry(value);
2007-04-01 00:17:50 +02:00
if (entry == NULL) {
2007-04-01 14:09:20 +02:00
log_print(LOG_ERROR, "net_init_cli_cb(): can not create net_entry");
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 14:09:20 +02:00
list_add(&entry->list, &cli_list);
2009-05-01 22:45:50 +02:00
log_print(LOG_INFO, "forwarding to %s", get_sockaddr_buf(&entry->addr));
2007-04-01 00:17:50 +02:00
return 0;
}
int net_init(void)
{
2007-04-01 14:09:20 +02:00
config_get_strings("global", "listen", net_init_srv_cb, NULL);
config_get_strings("global", "forward", net_init_cli_cb, NULL);
2009-05-01 23:19:29 +02:00
fwd_buf = malloc(PKTSIZE);
if (fwd_buf == NULL) {
log_print(LOG_ERROR, "net_submit(): out of memory");
return -1;
}
2007-04-01 14:09:20 +02:00
return 0;
}
2006-09-30 20:27:56 +02:00
2007-04-01 14:09:20 +02:00
void net_close(void) {
struct net_entry *entry, *tmp;
list_for_each_entry_safe(entry, tmp, &cli_list, list) {
list_del(&entry->list);
close(entry->socket);
free(entry);
}
2007-04-01 00:17:50 +02:00
2007-04-01 14:09:20 +02:00
list_for_each_entry_safe(entry, tmp, &srv_list, list) {
list_del(&entry->list);
event_remove_fd(entry->event);
close(entry->socket);
free(entry);
2006-09-30 20:27:56 +02:00
}
2006-08-03 19:49:07 +02:00
2009-05-02 15:32:33 +02:00
fwd_buf_len = 0;
2007-04-01 14:09:20 +02:00
if (fwd_buf != NULL)
free(fwd_buf);
2006-08-03 19:49:07 +02:00
}