/**
* collectd - src/network.c
- * Copyright (C) 2005-2007 Florian octo Forster
+ * Copyright (C) 2005-2008 Florian octo Forster
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
static c_avl_tree_t *cache_tree = NULL;
static pthread_mutex_t cache_lock = PTHREAD_MUTEX_INITIALIZER;
-static time_t cache_flush_last;
+static time_t cache_flush_last = 0;
static int cache_flush_interval = 1800;
/*
return (0);
} /* int cache_flush */
-static int cache_check (const char *type, const value_list_t *vl)
+static int cache_check (const value_list_t *vl)
{
char key[1024];
time_t *value = NULL;
return (-1);
if (format_name (key, sizeof (key), vl->host, vl->plugin,
- vl->plugin_instance, type, vl->type_instance))
+ vl->plugin_instance, vl->type, vl->type_instance))
return (-1);
pthread_mutex_lock (&cache_lock);
static int write_part_string (char **ret_buffer, int *ret_buffer_len,
int type, const char *str, int str_len)
{
- char *packet_ptr;
- int packet_len;
+ char *buffer;
+ int buffer_len;
- part_header_t pkg_head;
+ uint16_t pkg_type;
+ uint16_t pkg_length;
int offset;
- packet_len = sizeof (pkg_head) + str_len + 1;
- if (*ret_buffer_len < packet_len)
+ buffer_len = 2 * sizeof (uint16_t) + str_len + 1;
+ if (*ret_buffer_len < buffer_len)
return (-1);
- pkg_head.type = htons (type);
- pkg_head.length = htons (packet_len);
+ pkg_type = htons (type);
+ pkg_length = htons (buffer_len);
- packet_ptr = *ret_buffer;
+ buffer = *ret_buffer;
offset = 0;
- memcpy (packet_ptr + offset, &pkg_head, sizeof (pkg_head));
- offset += sizeof (pkg_head);
- memcpy (packet_ptr + offset, str, str_len);
+ memcpy (buffer + offset, (void *) &pkg_type, sizeof (pkg_type));
+ offset += sizeof (pkg_type);
+ memcpy (buffer + offset, (void *) &pkg_length, sizeof (pkg_length));
+ offset += sizeof (pkg_length);
+ memcpy (buffer + offset, str, str_len);
offset += str_len;
- memset (packet_ptr + offset, '\0', 1);
+ memset (buffer + offset, '\0', 1);
offset += 1;
- assert (offset == packet_len);
+ assert (offset == buffer_len);
- *ret_buffer = packet_ptr + packet_len;
- *ret_buffer_len -= packet_len;
+ *ret_buffer = buffer + buffer_len;
+ *ret_buffer_len -= buffer_len;
return (0);
} /* int write_part_string */
memcpy ((void *) &tmp16, buffer, sizeof (tmp16));
buffer += sizeof (tmp16);
- pkg_length = ntohs (tmp16);
+ pkg_type = ntohs (tmp16);
memcpy ((void *) &tmp16, buffer, sizeof (tmp16));
buffer += sizeof (tmp16);
- pkg_type = ntohs (tmp16);
+ pkg_length = ntohs (tmp16);
memcpy ((void *) &tmp16, buffer, sizeof (tmp16));
buffer += sizeof (tmp16);
memcpy ((void *) &tmp16, buffer, sizeof (tmp16));
buffer += sizeof (tmp16);
- pkg_length = ntohs (tmp16);
+ pkg_type = ntohs (tmp16);
memcpy ((void *) &tmp16, buffer, sizeof (tmp16));
buffer += sizeof (tmp16);
- pkg_type = ntohs (tmp16);
+ pkg_length = ntohs (tmp16);
memcpy ((void *) &tmp64, buffer, sizeof (tmp64));
buffer += sizeof (tmp64);
memcpy ((void *) &tmp16, buffer, sizeof (tmp16));
buffer += sizeof (tmp16);
- pkg_length = ntohs (tmp16);
+ pkg_type = ntohs (tmp16);
memcpy ((void *) &tmp16, buffer, sizeof (tmp16));
buffer += sizeof (tmp16);
- pkg_type = ntohs (tmp16);
+ pkg_length = ntohs (tmp16);
/* Check that packet fits in the input buffer */
if (pkg_length > buffer_len)
memcpy ((void *) output, (void *) buffer, output_len);
buffer += output_len;
- if (output[output_len - 1] != '\0');
+ /* For some very weird reason '\0' doesn't do the trick on SPARC in
+ * this statement. */
+ if (output[output_len - 1] != 0)
{
WARNING ("network plugin: parse_part_string: "
"Received string does not end "
int status;
value_list_t vl = VALUE_LIST_INIT;
- char type[DATA_MAX_NAME_LEN];
+ notification_t n;
DEBUG ("network plugin: parse_packet: buffer = %p; buffer_len = %i;",
buffer, buffer_len);
memset (&vl, '\0', sizeof (vl));
- memset (&type, '\0', sizeof (type));
+ memset (&n, '\0', sizeof (n));
status = 0;
- while ((status == 0) && (buffer_len > sizeof (part_header_t)))
+ while ((status == 0) && (0 < buffer_len)
+ && ((unsigned int) buffer_len > sizeof (part_header_t)))
{
uint16_t pkg_length;
uint16_t pkg_type;
- memcpy ((void *) &pkg_length,
- (void *) buffer,
- sizeof (pkg_length));
memcpy ((void *) &pkg_type,
- (void *) buffer + sizeof (pkg_length),
+ (void *) buffer,
sizeof (pkg_type));
+ memcpy ((void *) &pkg_length,
+ (void *) (buffer + sizeof (pkg_type)),
+ sizeof (pkg_length));
pkg_length = ntohs (pkg_length);
pkg_type = ntohs (pkg_type);
if ((vl.time > 0)
&& (strlen (vl.host) > 0)
&& (strlen (vl.plugin) > 0)
- && (strlen (type) > 0)
- && (cache_check (type, &vl) == 0))
+ && (strlen (vl.type) > 0)
+ && (cache_check (&vl) == 0))
{
- plugin_dispatch_values (type, &vl);
+ plugin_dispatch_values (&vl);
}
else
{
else if (pkg_type == TYPE_TIME)
{
uint64_t tmp = 0;
- status = parse_part_number (&buffer, &buffer_len, &tmp);
+ status = parse_part_number (&buffer, &buffer_len,
+ &tmp);
if (status == 0)
+ {
vl.time = (time_t) tmp;
+ n.time = (time_t) tmp;
+ }
}
else if (pkg_type == TYPE_INTERVAL)
{
uint64_t tmp = 0;
- status = parse_part_number (&buffer, &buffer_len, &tmp);
+ status = parse_part_number (&buffer, &buffer_len,
+ &tmp);
if (status == 0)
vl.interval = (int) tmp;
}
{
status = parse_part_string (&buffer, &buffer_len,
vl.host, sizeof (vl.host));
- DEBUG ("network plugin: parse_packet: vl.host = %s", vl.host);
+ if (status == 0)
+ sstrncpy (n.host, vl.host, sizeof (n.host));
}
else if (pkg_type == TYPE_PLUGIN)
{
status = parse_part_string (&buffer, &buffer_len,
vl.plugin, sizeof (vl.plugin));
- DEBUG ("network plugin: parse_packet: vl.plugin = %s", vl.plugin);
+ if (status == 0)
+ sstrncpy (n.plugin, vl.plugin,
+ sizeof (n.plugin));
}
else if (pkg_type == TYPE_PLUGIN_INSTANCE)
{
status = parse_part_string (&buffer, &buffer_len,
- vl.plugin_instance, sizeof (vl.plugin_instance));
- DEBUG ("network plugin: parse_packet: vl.plugin_instance = %s", vl.plugin_instance);
+ vl.plugin_instance,
+ sizeof (vl.plugin_instance));
+ if (status == 0)
+ sstrncpy (n.plugin_instance,
+ vl.plugin_instance,
+ sizeof (n.plugin_instance));
}
else if (pkg_type == TYPE_TYPE)
{
status = parse_part_string (&buffer, &buffer_len,
- type, sizeof (type));
- DEBUG ("network plugin: parse_packet: type = %s", type);
+ vl.type, sizeof (vl.type));
+ if (status == 0)
+ sstrncpy (n.type, vl.type, sizeof (n.type));
}
else if (pkg_type == TYPE_TYPE_INSTANCE)
{
status = parse_part_string (&buffer, &buffer_len,
- vl.type_instance, sizeof (vl.type_instance));
- DEBUG ("network plugin: parse_packet: vl.type_instance = %s", vl.type_instance);
+ vl.type_instance,
+ sizeof (vl.type_instance));
+ if (status == 0)
+ sstrncpy (n.type_instance, vl.type_instance,
+ sizeof (n.type_instance));
+ }
+ else if (pkg_type == TYPE_MESSAGE)
+ {
+ status = parse_part_string (&buffer, &buffer_len,
+ n.message, sizeof (n.message));
+
+ if (status != 0)
+ {
+ /* do nothing */
+ }
+ else if ((n.severity != NOTIF_FAILURE)
+ && (n.severity != NOTIF_WARNING)
+ && (n.severity != NOTIF_OKAY))
+ {
+ INFO ("network plugin: "
+ "Ignoring notification with "
+ "unknown severity %i.",
+ n.severity);
+ }
+ else if (n.time <= 0)
+ {
+ INFO ("network plugin: "
+ "Ignoring notification with "
+ "time == 0.");
+ }
+ else if (strlen (n.message) <= 0)
+ {
+ INFO ("network plugin: "
+ "Ignoring notification with "
+ "an empty message.");
+ }
+ else
+ {
+ plugin_dispatch_notification (&n);
+ }
+ }
+ else if (pkg_type == TYPE_SEVERITY)
+ {
+ uint64_t tmp = 0;
+ status = parse_part_number (&buffer, &buffer_len,
+ &tmp);
+ if (status == 0)
+ n.severity = (int) tmp;
}
else
{
static int network_bind_socket (const sockent_t *se, const struct addrinfo *ai)
{
int loop = 0;
+ int yes = 1;
+
+ /* allow multiple sockets to use the same PORT number */
+ if (setsockopt(se->fd, SOL_SOCKET, SO_REUSEADDR,
+ &yes, sizeof(yes)) == -1) {
+ char errbuf[1024];
+ ERROR ("setsockopt: %s",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ return (-1);
+ }
DEBUG ("fd = %i; calling `bind'", se->fd);
if (write_part_string (&buffer, &buffer_size, TYPE_HOST,
vl->host, strlen (vl->host)) != 0)
return (-1);
- strcpy (vl_def->host, vl->host);
+ sstrncpy (vl_def->host, vl->host, sizeof (vl_def->host));
}
if (vl_def->time != vl->time)
if (write_part_string (&buffer, &buffer_size, TYPE_PLUGIN,
vl->plugin, strlen (vl->plugin)) != 0)
return (-1);
- strcpy (vl_def->plugin, vl->plugin);
+ sstrncpy (vl_def->plugin, vl->plugin, sizeof (vl_def->plugin));
}
if (strcmp (vl_def->plugin_instance, vl->plugin_instance) != 0)
vl->plugin_instance,
strlen (vl->plugin_instance)) != 0)
return (-1);
- strcpy (vl_def->plugin_instance, vl->plugin_instance);
+ sstrncpy (vl_def->plugin_instance, vl->plugin_instance, sizeof (vl_def->plugin_instance));
}
- if (strcmp (type_def, ds->type) != 0)
+ if (strcmp (type_def, vl->type) != 0)
{
if (write_part_string (&buffer, &buffer_size, TYPE_TYPE,
- ds->type, strlen (ds->type)) != 0)
+ vl->type, strlen (vl->type)) != 0)
return (-1);
- strcpy (type_def, ds->type);
+ sstrncpy (type_def, vl->type, sizeof (type_def));
}
if (strcmp (vl_def->type_instance, vl->type_instance) != 0)
vl->type_instance,
strlen (vl->type_instance)) != 0)
return (-1);
- strcpy (vl_def->type_instance, vl->type_instance);
+ sstrncpy (vl_def->type_instance, vl->type_instance, sizeof (vl_def->type_instance));
}
if (write_part_values (&buffer, &buffer_size, ds, vl) != 0)
/* If the value is already in the cache, we have received it via the
* network. We write it again if forwarding is activated. It's then in
* the cache and should we receive it again we will ignore it. */
- status = cache_check (ds->type, vl);
+ status = cache_check (vl);
if ((network_config_forward == 0)
&& (status != 0))
return (0);
return (0);
} /* int network_config */
+static int network_notification (const notification_t *n)
+{
+ char buffer[BUFF_SIZE];
+ char *buffer_ptr = buffer;
+ int buffer_free = sizeof (buffer);
+ int status;
+
+ memset (buffer, '\0', sizeof (buffer));
+
+
+ status = write_part_number (&buffer_ptr, &buffer_free, TYPE_TIME,
+ (uint64_t) n->time);
+ if (status != 0)
+ return (-1);
+
+ status = write_part_number (&buffer_ptr, &buffer_free, TYPE_SEVERITY,
+ (uint64_t) n->severity);
+ if (status != 0)
+ return (-1);
+
+ if (strlen (n->host) > 0)
+ {
+ status = write_part_string (&buffer_ptr, &buffer_free, TYPE_HOST,
+ n->host, strlen (n->host));
+ if (status != 0)
+ return (-1);
+ }
+
+ if (strlen (n->plugin) > 0)
+ {
+ status = write_part_string (&buffer_ptr, &buffer_free, TYPE_PLUGIN,
+ n->plugin, strlen (n->plugin));
+ if (status != 0)
+ return (-1);
+ }
+
+ if (strlen (n->plugin_instance) > 0)
+ {
+ status = write_part_string (&buffer_ptr, &buffer_free,
+ TYPE_PLUGIN_INSTANCE,
+ n->plugin_instance, strlen (n->plugin_instance));
+ if (status != 0)
+ return (-1);
+ }
+
+ if (strlen (n->type) > 0)
+ {
+ status = write_part_string (&buffer_ptr, &buffer_free, TYPE_TYPE,
+ n->type, strlen (n->type));
+ if (status != 0)
+ return (-1);
+ }
+
+ if (strlen (n->type_instance) > 0)
+ {
+ status = write_part_string (&buffer_ptr, &buffer_free, TYPE_TYPE_INSTANCE,
+ n->type_instance, strlen (n->type_instance));
+ if (status != 0)
+ return (-1);
+ }
+
+ status = write_part_string (&buffer_ptr, &buffer_free, TYPE_MESSAGE,
+ n->message, strlen (n->message));
+ if (status != 0)
+ return (-1);
+
+ network_send_buffer (buffer, sizeof (buffer) - buffer_free);
+
+ return (0);
+} /* int network_notification */
+
static int network_shutdown (void)
{
listen_loop++;
plugin_unregister_write ("network");
plugin_unregister_shutdown ("network");
+ /* Let the init function do it's move again ;) */
+ cache_flush_last = 0;
+
return (0);
} /* int network_shutdown */
static int network_init (void)
{
+ /* Check if we were already initialized. If so, just return - there's
+ * nothing more to do (for now, that is). */
+ if (cache_flush_last != 0)
+ return (0);
+
plugin_register_shutdown ("network", network_shutdown);
send_buffer_ptr = send_buffer;
/* setup socket(s) and so on */
if (sending_sockets != NULL)
+ {
plugin_register_write ("network", network_write);
+ plugin_register_notification ("network", network_notification);
+ }
if ((listen_sockets_num != 0) && (receive_thread_id == 0))
{
return (0);
} /* int network_init */
+/*
+ * The flush option of the network plugin cannot flush individual identifiers.
+ * All the values are added to a buffer and sent when the buffer is full, the
+ * requested value may or may not be in there, it's not worth finding out. We
+ * just send the buffer if `flush' is called - if the requested value was in
+ * there, good. If not, well, then there is nothing to flush.. -octo
+ */
+static int network_flush (int timeout, const char *identifier)
+{
+ pthread_mutex_lock (&send_buffer_lock);
+
+ if (((time (NULL) - cache_flush_last) >= timeout)
+ && (send_buffer_fill > 0))
+ {
+ flush_buffer ();
+ }
+
+ pthread_mutex_unlock (&send_buffer_lock);
+
+ return (0);
+} /* int network_flush */
+
void module_register (void)
{
plugin_register_config ("network", network_config,
config_keys, config_keys_num);
plugin_register_init ("network", network_init);
+ plugin_register_flush ("network", network_flush);
} /* void module_register */