/**
* collectd - src/dns.c
- * Copyright (C) 2006,2007 Florian octo Forster
+ * Copyright (C) 2006-2011 Florian octo Forster
* Copyright (C) 2009 Mirko Buffoni
*
* This program is free software; you can redistribute it and/or modify it
* 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>
* Mirko Buffoni <briareos at eswat.org>
**/
+#define _DEFAULT_SOURCE
#define _BSD_SOURCE
#include "collectd.h"
#include "configfile.h"
#include "utils_dns.h"
-#include <pthread.h>
-#include <pcap.h>
#include <poll.h>
+#include <pcap.h>
+
/*
* Private data types
*/
#define PCAP_SNAPLEN 1460
static char *pcap_device = NULL;
-static counter_t tr_queries;
-static counter_t tr_responses;
+static derive_t tr_queries;
+static derive_t tr_responses;
static counter_list_t *qtype_list;
static counter_list_t *opcode_list;
static counter_list_t *rcode_list;
{
counter_list_t *entry;
- entry = (counter_list_t *) malloc (sizeof (counter_list_t));
+ entry = calloc (1, sizeof (*entry));
if (entry == NULL)
return (NULL);
- memset (entry, 0, sizeof (counter_list_t));
entry->key = key;
entry->value = value;
pthread_mutex_unlock (&opcode_mutex);
}
-static void *dns_child_loop (void __attribute__((unused)) *dummy)
+static int dns_run_pcap_loop (void)
{
pcap_t *pcap_obj;
char pcap_error[PCAP_ERRBUF_SIZE];
pcap_obj = pcap_open_live ((pcap_device != NULL) ? pcap_device : "any",
PCAP_SNAPLEN,
0 /* Not promiscuous */,
- interval_g,
+ (int) CDTIME_T_TO_MS (plugin_get_interval () / 2),
pcap_error);
if (pcap_obj == NULL)
{
"failed: %s",
(pcap_device != NULL) ? pcap_device : "any",
pcap_error);
- return (NULL);
+ return (PCAP_ERROR);
}
memset (&fp, 0, sizeof (fp));
- if (pcap_compile (pcap_obj, &fp, "udp port 53", 1, 0) < 0)
+ status = pcap_compile (pcap_obj, &fp, "udp port 53", 1, 0);
+ if (status < 0)
{
- ERROR ("dns plugin: pcap_compile failed");
- return (NULL);
+ ERROR ("dns plugin: pcap_compile failed: %s",
+ pcap_statustostr (status));
+ return (status);
}
- if (pcap_setfilter (pcap_obj, &fp) < 0)
+
+ status = pcap_setfilter (pcap_obj, &fp);
+ if (status < 0)
{
- ERROR ("dns plugin: pcap_setfilter failed");
- return (NULL);
+ ERROR ("dns plugin: pcap_setfilter failed: %s",
+ pcap_statustostr (status));
+ return (status);
}
DEBUG ("dns plugin: PCAP object created.");
status = pcap_loop (pcap_obj,
-1 /* loop forever */,
handle_pcap /* callback */,
- NULL /* Whatever this means.. */);
- if (status < 0)
- ERROR ("dns plugin: Listener thread is exiting "
- "abnormally: %s", pcap_geterr (pcap_obj));
-
- DEBUG ("dns plugin: Child is exiting.");
+ NULL /* user data */);
+ INFO ("dns plugin: pcap_loop exited with status %i.", status);
+ /* We need to handle "PCAP_ERROR" specially because libpcap currently
+ * doesn't return PCAP_ERROR_IFACE_NOT_UP for compatibility reasons. */
+ if (status == PCAP_ERROR)
+ status = PCAP_ERROR_IFACE_NOT_UP;
pcap_close (pcap_obj);
- listen_thread_init = 0;
- pthread_exit (NULL);
+ return (status);
+} /* int dns_run_pcap_loop */
+
+static int dns_sleep_one_interval (void) /* {{{ */
+{
+ cdtime_t interval;
+ struct timespec ts = { 0, 0 };
+ int status = 0;
+ interval = plugin_get_interval ();
+ CDTIME_T_TO_TIMESPEC (interval, &ts);
+
+ while (42)
+ {
+ struct timespec rem = { 0, 0 };
+
+ status = nanosleep (&ts, &rem);
+ if (status == 0)
+ break;
+ else if ((errno == EINTR) || (errno == EAGAIN))
+ {
+ ts = rem;
+ continue;
+ }
+ else
+ break;
+ }
+
+ return (status);
+} /* }}} int dns_sleep_one_interval */
+
+static void *dns_child_loop (__attribute__((unused)) void *dummy) /* {{{ */
+{
+ int status;
+
+ while (42)
+ {
+ status = dns_run_pcap_loop ();
+ if (status != PCAP_ERROR_IFACE_NOT_UP)
+ break;
+
+ dns_sleep_one_interval ();
+ }
+
+ if (status != PCAP_ERROR_BREAK)
+ ERROR ("dns plugin: PCAP returned error %s.",
+ pcap_statustostr (status));
+
+ listen_thread_init = 0;
return (NULL);
-} /* static void dns_child_loop (void) */
+} /* }}} void *dns_child_loop */
static int dns_init (void)
{
if (listen_thread_init != 0)
return (-1);
- status = pthread_create (&listen_thread, NULL, dns_child_loop,
+ status = plugin_thread_create (&listen_thread, NULL, dns_child_loop,
(void *) 0);
if (status != 0)
{
return (0);
} /* int dns_init */
-static void submit_counter (const char *type, const char *type_instance,
- counter_t value)
+static void submit_derive (const char *type, const char *type_instance,
+ derive_t value)
{
value_t values[1];
value_list_t vl = VALUE_LIST_INIT;
- values[0].counter = value;
+ values[0].derive = value;
vl.values = values;
vl.values_len = 1;
sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
plugin_dispatch_values (&vl);
-} /* void submit_counter */
+} /* void submit_derive */
-static void submit_octets (counter_t queries, counter_t responses)
+static void submit_octets (derive_t queries, derive_t responses)
{
value_t values[2];
value_list_t vl = VALUE_LIST_INIT;
- values[0].counter = queries;
- values[1].counter = responses;
+ values[0].derive = queries;
+ values[1].derive = responses;
vl.values = values;
vl.values_len = 2;
sstrncpy (vl.type, "dns_octets", sizeof (vl.type));
plugin_dispatch_values (&vl);
-} /* void submit_counter */
+} /* void submit_octets */
static int dns_read (void)
{
for (i = 0; i < len; i++)
{
DEBUG ("dns plugin: qtype = %u; counter = %u;", keys[i], values[i]);
- submit_counter ("dns_qtype", qtype_str (keys[i]), values[i]);
+ submit_derive ("dns_qtype", qtype_str (keys[i]), values[i]);
}
pthread_mutex_lock (&opcode_mutex);
for (i = 0; i < len; i++)
{
DEBUG ("dns plugin: opcode = %u; counter = %u;", keys[i], values[i]);
- submit_counter ("dns_opcode", opcode_str (keys[i]), values[i]);
+ submit_derive ("dns_opcode", opcode_str (keys[i]), values[i]);
}
pthread_mutex_lock (&rcode_mutex);
for (i = 0; i < len; i++)
{
DEBUG ("dns plugin: rcode = %u; counter = %u;", keys[i], values[i]);
- submit_counter ("dns_rcode", rcode_str (keys[i]), values[i]);
+ submit_derive ("dns_rcode", rcode_str (keys[i]), values[i]);
}
return (0);