/**
* collectd - src/network.c
- * Copyright (C) 2005-2009 Florian octo Forster
+ * Copyright (C) 2005-2013 Florian octo Forster
* Copyright (C) 2009 Aman Gupta
*
* This program is free software; you can redistribute it and/or modify it
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Authors:
- * Florian octo Forster <octo at verplant.org>
+ * Florian octo Forster <octo at collectd.org>
* Aman Gupta <aman at tmm1.net>
**/
#endif
#if HAVE_LIBGCRYPT
+# include <pthread.h>
+# if defined __APPLE__
+/* default xcode compiler throws warnings even when deprecated functionality
+ * is not used. -Werror breaks the build because of erroneous warnings.
+ * http://stackoverflow.com/questions/10556299/compiler-warnings-with-libgcrypt-v1-5-0/12830209#12830209
+ */
+# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+# endif
+/* FreeBSD's copy of libgcrypt extends the existing GCRYPT_NO_DEPRECATED
+ * to properly hide all deprecated functionality.
+ * http://svnweb.freebsd.org/ports/head/security/libgcrypt/files/patch-src__gcrypt.h.in
+ */
+# define GCRYPT_NO_DEPRECATED
# include <gcrypt.h>
+# if defined __APPLE__
+/* Re enable deprecation warnings */
+# pragma GCC diagnostic warning "-Wdeprecated-declarations"
+# endif
GCRY_THREAD_OPTION_PTHREAD_IMPL;
#endif
* Private variables
*/
static int network_config_ttl = 0;
-static size_t network_config_packet_size = 1024;
+/* Ethernet - (IPv6 + UDP) = 1500 - (40 + 8) = 1452 */
+static size_t network_config_packet_size = 1452;
static int network_config_forward = 0;
static int network_config_stats = 0;
* example). Only if neither is true, the stats_lock is acquired. The counters
* are always read without holding a lock in the hope that writing 8 bytes to
* memory is an atomic operation. */
-static uint64_t stats_octets_rx = 0;
-static uint64_t stats_octets_tx = 0;
-static uint64_t stats_packets_rx = 0;
-static uint64_t stats_packets_tx = 0;
-static uint64_t stats_values_dispatched = 0;
-static uint64_t stats_values_not_dispatched = 0;
-static uint64_t stats_values_sent = 0;
-static uint64_t stats_values_not_sent = 0;
+static derive_t stats_octets_rx = 0;
+static derive_t stats_octets_tx = 0;
+static derive_t stats_packets_rx = 0;
+static derive_t stats_packets_tx = 0;
+static derive_t stats_values_dispatched = 0;
+static derive_t stats_values_not_dispatched = 0;
+static derive_t stats_values_sent = 0;
+static derive_t stats_values_not_sent = 0;
static pthread_mutex_t stats_lock = PTHREAD_MUTEX_INITIALIZER;
/*
/* This is a value we already sent. Don't allow it to be received again in
* order to avoid looping. */
if ((status == 0) && (time_sent >= ((uint64_t) vl->time)))
- return (false);
+ return (0);
- return (true);
+ return (1);
} /* }}} _Bool check_receive_okay */
static _Bool check_send_okay (const value_list_t *vl) /* {{{ */
{
- _Bool received = false;
+ _Bool received = 0;
int status;
if (network_config_forward != 0)
- return (true);
+ return (1);
if (vl->meta == NULL)
- return (true);
+ return (1);
status = meta_data_get_boolean (vl->meta, "network:received", &received);
if (status == -ENOENT)
- return (true);
+ return (1);
else if (status != 0)
{
ERROR ("network plugin: check_send_okay: meta_data_get_boolean failed "
"with status %i.", status);
- return (true);
+ return (1);
}
/* By default, only *send* value lists that were not *received* by the
return (!received);
} /* }}} _Bool check_send_okay */
+static _Bool check_notify_received (const notification_t *n) /* {{{ */
+{
+ notification_meta_t *ptr;
+
+ for (ptr = n->meta; ptr != NULL; ptr = ptr->next)
+ if ((strcmp ("network:received", ptr->name) == 0)
+ && (ptr->type == NM_TYPE_BOOLEAN))
+ return ((_Bool) ptr->nm_value.nm_boolean);
+
+ return (0);
+} /* }}} _Bool check_notify_received */
+
+static _Bool check_send_notify_okay (const notification_t *n) /* {{{ */
+{
+ static c_complain_t complain_forwarding = C_COMPLAIN_INIT_STATIC;
+ _Bool received = 0;
+
+ if (n->meta == NULL)
+ return (1);
+
+ received = check_notify_received (n);
+
+ if (network_config_forward && received)
+ {
+ c_complain_once (LOG_ERR, &complain_forwarding,
+ "network plugin: A notification has been received via the network "
+ "forwarding if enabled. Forwarding of notifications is currently "
+ "not supported, because there is not loop-deteciton available. "
+ "Please contact the collectd mailing list if you need this "
+ "feature.");
+ }
+
+ /* By default, only *send* value lists that were not *received* by the
+ * network plugin. */
+ return (!received);
+} /* }}} _Bool check_send_notify_okay */
+
static int network_dispatch_values (value_list_t *vl, /* {{{ */
const char *username)
{
return (-ENOMEM);
}
- status = meta_data_add_boolean (vl->meta, "network:received", true);
+ status = meta_data_add_boolean (vl->meta, "network:received", 1);
if (status != 0)
{
ERROR ("network plugin: meta_data_add_boolean failed.");
}
}
- plugin_dispatch_values_secure (vl);
+ plugin_dispatch_values (vl);
stats_values_dispatched++;
meta_data_destroy (vl->meta);
return (0);
} /* }}} int network_dispatch_values */
+static int network_dispatch_notification (notification_t *n) /* {{{ */
+{
+ int status;
+
+ assert (n->meta == NULL);
+
+ status = plugin_notification_meta_add_boolean (n, "network:received", 1);
+ if (status != 0)
+ {
+ ERROR ("network plugin: plugin_notification_meta_add_boolean failed.");
+ plugin_notification_meta_free (n->meta);
+ n->meta = NULL;
+ return (status);
+ }
+
+ status = plugin_dispatch_notification (n);
+
+ plugin_notification_meta_free (n->meta);
+ n->meta = NULL;
+
+ return (status);
+} /* }}} int network_dispatch_notification */
+
#if HAVE_LIBGCRYPT
+static void network_init_gcrypt (void) /* {{{ */
+{
+ /* http://lists.gnupg.org/pipermail/gcrypt-devel/2003-August/000458.html
+ * Because you can't know in a library whether another library has
+ * already initialized the library */
+ if (gcry_control (GCRYCTL_ANY_INITIALIZATION_P))
+ return;
+
+ gcry_check_version (NULL); /* before calling any other functions */
+ gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
+ gcry_control (GCRYCTL_INIT_SECMEM, 32768);
+ gcry_control (GCRYCTL_INITIALIZATION_FINISHED);
+} /* }}} void network_init_gcrypt */
+
static gcry_cipher_hd_t network_get_aes256_cypher (sockent_t *se, /* {{{ */
const void *iv, size_t iv_size, const char *username)
{
part_header_t pkg_head;
uint64_t pkg_value;
-
+
int offset;
packet_len = sizeof (pkg_head) + sizeof (pkg_value);
exp_size = 3 * sizeof (uint16_t)
+ pkg_numval * (sizeof (uint8_t) + sizeof (value_t));
- if ((buffer_len < 0) || (buffer_len < exp_size))
+ if (buffer_len < exp_size)
{
WARNING ("network plugin: parse_part_values: "
"Packet too short: "
uint16_t pkg_length;
- if ((buffer_len < 0) || ((size_t) buffer_len < exp_size))
+ if (buffer_len < exp_size)
{
WARNING ("network plugin: parse_part_number: "
"Packet too short: "
uint16_t pkg_length;
- if ((buffer_len < 0) || (buffer_len < header_size))
+ if (buffer_len < header_size)
{
WARNING ("network plugin: parse_part_string: "
"Packet too short: "
&tmp);
if (status == 0)
{
- vl.time = (time_t) tmp;
- n.time = (time_t) tmp;
+ vl.time = TIME_T_TO_CDTIME_T (tmp);
+ n.time = TIME_T_TO_CDTIME_T (tmp);
+ }
+ }
+ else if (pkg_type == TYPE_TIME_HR)
+ {
+ uint64_t tmp = 0;
+ status = parse_part_number (&buffer, &buffer_size,
+ &tmp);
+ if (status == 0)
+ {
+ vl.time = (cdtime_t) tmp;
+ n.time = (cdtime_t) tmp;
}
}
else if (pkg_type == TYPE_INTERVAL)
status = parse_part_number (&buffer, &buffer_size,
&tmp);
if (status == 0)
- vl.interval = (int) tmp;
+ vl.interval = TIME_T_TO_CDTIME_T (tmp);
+ }
+ else if (pkg_type == TYPE_INTERVAL_HR)
+ {
+ uint64_t tmp = 0;
+ status = parse_part_number (&buffer, &buffer_size,
+ &tmp);
+ if (status == 0)
+ vl.interval = (cdtime_t) tmp;
}
else if (pkg_type == TYPE_HOST)
{
}
else
{
- plugin_dispatch_notification (&n);
+ network_dispatch_notification (&n);
}
}
else if (pkg_type == TYPE_SEVERITY)
sizeof (network_config_ttl)) != 0)
{
char errbuf[1024];
- ERROR ("setsockopt: %s",
+ ERROR ("network plugin: setsockopt (ipv4-ttl): %s",
sstrerror (errno, errbuf, sizeof (errbuf)));
return (-1);
}
sizeof (network_config_ttl)) != 0)
{
char errbuf[1024];
- ERROR ("setsockopt: %s",
+ ERROR ("network plugin: setsockopt(ipv6-ttl): %s",
sstrerror (errno, errbuf,
sizeof (errbuf)));
return (-1);
&mreq, sizeof (mreq)) != 0)
{
char errbuf[1024];
- ERROR ("setsockopt: %s",
+ ERROR ("network plugin: setsockopt (ipv4-multicast-if): %s",
sstrerror (errno, errbuf, sizeof (errbuf)));
return (-1);
}
sizeof (se->interface)) != 0)
{
char errbuf[1024];
- ERROR ("setsockopt: %s",
+ ERROR ("network plugin: setsockopt (ipv6-multicast-if): %s",
sstrerror (errno, errbuf,
sizeof (errbuf)));
return (-1);
sizeof(interface_name)) == -1 )
{
char errbuf[1024];
- ERROR ("setsockopt: %s",
+ ERROR ("network plugin: setsockopt (bind-if): %s",
sstrerror (errno, errbuf, sizeof (errbuf)));
return (-1);
}
static int network_bind_socket (int fd, const struct addrinfo *ai, const int interface_idx)
{
+#if KERNEL_SOLARIS
+ char loop = 0;
+#else
int loop = 0;
+#endif
int yes = 1;
/* allow multiple sockets to use the same PORT number */
if (setsockopt (fd, SOL_SOCKET, SO_REUSEADDR,
&yes, sizeof(yes)) == -1) {
char errbuf[1024];
- ERROR ("setsockopt: %s",
+ ERROR ("network plugin: setsockopt (reuseaddr): %s",
sstrerror (errno, errbuf, sizeof (errbuf)));
return (-1);
}
&loop, sizeof (loop)) == -1)
{
char errbuf[1024];
- ERROR ("setsockopt: %s",
+ ERROR ("network plugin: setsockopt (multicast-loop): %s",
sstrerror (errno, errbuf,
sizeof (errbuf)));
return (-1);
&mreq, sizeof (mreq)) == -1)
{
char errbuf[1024];
- ERROR ("setsockopt: %s",
+ ERROR ("network plugin: setsockopt (add-membership): %s",
sstrerror (errno, errbuf,
sizeof (errbuf)));
return (-1);
&loop, sizeof (loop)) == -1)
{
char errbuf[1024];
- ERROR ("setsockopt: %s",
+ ERROR ("network plugin: setsockopt (ipv6-multicast-loop): %s",
sstrerror (errno, errbuf,
sizeof (errbuf)));
return (-1);
&mreq, sizeof (mreq)) == -1)
{
char errbuf[1024];
- ERROR ("setsockopt: %s",
+ ERROR ("network plugin: setsockopt (ipv6-add-membership): %s",
sstrerror (errno, errbuf,
sizeof (errbuf)));
return (-1);
sizeof(interface_name)) == -1 )
{
char errbuf[1024];
- ERROR ("setsockopt: %s",
+ ERROR ("network plugin: setsockopt (bind-if): %s",
sstrerror (errno, errbuf, sizeof (errbuf)));
return (-1);
}
{
if (se->data.client.security_level > SECURITY_LEVEL_NONE)
{
+ network_init_gcrypt ();
+
if ((se->data.client.username == NULL)
|| (se->data.client.password == NULL))
{
{
if (se->data.server.security_level > SECURITY_LEVEL_NONE)
{
+ network_init_gcrypt ();
+
if (se->data.server.auth_file == NULL)
{
ERROR ("network plugin: Server socket with "
if (vl_def->time != vl->time)
{
- if (write_part_number (&buffer, &buffer_size, TYPE_TIME,
+ if (write_part_number (&buffer, &buffer_size, TYPE_TIME_HR,
(uint64_t) vl->time))
return (-1);
vl_def->time = vl->time;
if (vl_def->interval != vl->interval)
{
- if (write_part_number (&buffer, &buffer_size, TYPE_INTERVAL,
+ if (write_part_number (&buffer, &buffer_size, TYPE_INTERVAL_HR,
(uint64_t) vl->interval))
return (-1);
vl_def->interval = vl->interval;
return (-1);
sstrncpy (vl_def->type_instance, vl->type_instance, sizeof (vl_def->type_instance));
}
-
+
if (write_part_values (&buffer, &buffer_size, ds, vl) != 0)
return (-1);
network_config_set_boolean (child, &network_config_forward);
else if (strcasecmp ("ReportStats", child->key) == 0)
network_config_set_boolean (child, &network_config_stats);
- else if (strcasecmp ("CacheFlush", child->key) == 0)
- /* no op for backwards compatibility only */;
else
{
WARNING ("network plugin: Option `%s' is not allowed here.",
} /* }}} int network_config */
static int network_notification (const notification_t *n,
- user_data_t __attribute__((unused)) *user_data)
+ user_data_t __attribute__((unused)) *user_data)
{
char buffer[network_config_packet_size];
char *buffer_ptr = buffer;
int buffer_free = sizeof (buffer);
int status;
- memset (buffer, '\0', sizeof (buffer));
+ if (!check_send_notify_okay (n))
+ return (0);
+ memset (buffer, 0, sizeof (buffer));
- status = write_part_number (&buffer_ptr, &buffer_free, TYPE_TIME,
+ status = write_part_number (&buffer_ptr, &buffer_free, TYPE_TIME_HR,
(uint64_t) n->time);
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));
+ 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));
+ 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));
+ 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));
+ 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));
+ n->type_instance, strlen (n->type_instance));
if (status != 0)
return (-1);
}
static int network_stats_read (void) /* {{{ */
{
- uint64_t copy_octets_rx;
- uint64_t copy_octets_tx;
- uint64_t copy_packets_rx;
- uint64_t copy_packets_tx;
- uint64_t copy_values_dispatched;
- uint64_t copy_values_not_dispatched;
- uint64_t copy_values_sent;
- uint64_t copy_values_not_sent;
- uint64_t copy_receive_list_length;
+ derive_t copy_octets_rx;
+ derive_t copy_octets_tx;
+ derive_t copy_packets_rx;
+ derive_t copy_packets_tx;
+ derive_t copy_values_dispatched;
+ derive_t copy_values_not_dispatched;
+ derive_t copy_values_sent;
+ derive_t copy_values_not_sent;
+ derive_t copy_receive_list_length;
value_list_t vl = VALUE_LIST_INIT;
value_t values[2];
vl.values = values;
vl.values_len = 2;
vl.time = 0;
- vl.interval = interval_g;
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "network", sizeof (vl.plugin));
/* Octets received / sent */
- vl.values[0].counter = (counter_t) copy_octets_rx;
- vl.values[1].counter = (counter_t) copy_octets_tx;
+ vl.values[0].derive = (derive_t) copy_octets_rx;
+ vl.values[1].derive = (derive_t) copy_octets_tx;
sstrncpy (vl.type, "if_octets", sizeof (vl.type));
- plugin_dispatch_values_secure (&vl);
+ plugin_dispatch_values (&vl);
/* Packets received / send */
- vl.values[0].counter = (counter_t) copy_packets_rx;
- vl.values[1].counter = (counter_t) copy_packets_tx;
+ vl.values[0].derive = (derive_t) copy_packets_rx;
+ vl.values[1].derive = (derive_t) copy_packets_tx;
sstrncpy (vl.type, "if_packets", sizeof (vl.type));
- plugin_dispatch_values_secure (&vl);
+ plugin_dispatch_values (&vl);
/* Values (not) dispatched and (not) send */
sstrncpy (vl.type, "total_values", sizeof (vl.type));
vl.values[0].derive = (derive_t) copy_values_dispatched;
sstrncpy (vl.type_instance, "dispatch-accepted",
sizeof (vl.type_instance));
- plugin_dispatch_values_secure (&vl);
+ plugin_dispatch_values (&vl);
vl.values[0].derive = (derive_t) copy_values_not_dispatched;
sstrncpy (vl.type_instance, "dispatch-rejected",
sizeof (vl.type_instance));
- plugin_dispatch_values_secure (&vl);
+ plugin_dispatch_values (&vl);
vl.values[0].derive = (derive_t) copy_values_sent;
sstrncpy (vl.type_instance, "send-accepted",
sizeof (vl.type_instance));
- plugin_dispatch_values_secure (&vl);
+ plugin_dispatch_values (&vl);
vl.values[0].derive = (derive_t) copy_values_not_sent;
sstrncpy (vl.type_instance, "send-rejected",
sizeof (vl.type_instance));
- plugin_dispatch_values_secure (&vl);
+ plugin_dispatch_values (&vl);
/* Receive queue length */
vl.values[0].gauge = (gauge_t) copy_receive_list_length;
sstrncpy (vl.type, "queue_length", sizeof (vl.type));
vl.type_instance[0] = 0;
- plugin_dispatch_values_secure (&vl);
+ plugin_dispatch_values (&vl);
return (0);
} /* }}} int network_stats_read */
static int network_init (void)
{
- static _Bool have_init = false;
+ static _Bool have_init = 0;
/* Check if we were already initialized. If so, just return - there's
* nothing more to do (for now, that is). */
if (have_init)
return (0);
- have_init = true;
+ have_init = 1;
#if HAVE_LIBGCRYPT
- gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
- gcry_control (GCRYCTL_INIT_SECMEM, 32768, 0);
- gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+ network_init_gcrypt ();
#endif
if (network_config_stats != 0)
if (dispatch_thread_running == 0)
{
int status;
- status = pthread_create (&dispatch_thread_id,
+ status = plugin_thread_create (&dispatch_thread_id,
NULL /* no attributes */,
dispatch_thread,
NULL /* no argument */);
if (receive_thread_running == 0)
{
int status;
- status = pthread_create (&receive_thread_id,
+ status = plugin_thread_create (&receive_thread_id,
NULL /* no attributes */,
receive_thread,
NULL /* no argument */);
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 __attribute__((unused)) *identifier,
- user_data_t __attribute__((unused)) *user_data)
+static int network_flush (__attribute__((unused)) cdtime_t timeout,
+ __attribute__((unused)) const char *identifier,
+ __attribute__((unused)) user_data_t *user_data)
{
pthread_mutex_lock (&send_buffer_lock);