utils_vl_lookup: Fixed a race when creating user objects.
[collectd.git] / src / dns.c
index 6e63fe4..00fcff1 100644 (file)
--- a/src/dns.c
+++ b/src/dns.c
@@ -1,6 +1,6 @@
 /**
  * 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
@@ -17,7 +17,7 @@
  * 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>
  **/
 
 
 #include "utils_dns.h"
 #include <pthread.h>
-#include <pcap.h>
 #include <poll.h>
 
+#include <pcap.h>
+#include <pcap-bpf.h>
+
 /*
  * Private data types
  */
@@ -59,8 +61,8 @@ static int select_numeric_qtype = 1;
 #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;
@@ -206,7 +208,7 @@ static void dns_child_callback (const rfc1035_header_t *dns)
        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];
@@ -226,7 +228,7 @@ static void *dns_child_loop (void __attribute__((unused)) *dummy)
        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)
        {
@@ -234,19 +236,24 @@ static void *dns_child_loop (void __attribute__((unused)) *dummy)
                                "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.");
@@ -257,19 +264,65 @@ static void *dns_child_loop (void __attribute__((unused)) *dummy)
        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)
 {
@@ -284,7 +337,7 @@ 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)
        {
@@ -299,13 +352,13 @@ static int dns_init (void)
        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;
@@ -315,15 +368,15 @@ static void submit_counter (const char *type, const char *type_instance,
        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;
@@ -332,7 +385,7 @@ static void submit_octets (counter_t queries, counter_t responses)
        sstrncpy (vl.type, "dns_octets", sizeof (vl.type));
 
        plugin_dispatch_values (&vl);
-} /* void submit_counter */
+} /* void submit_octets */
 
 static int dns_read (void)
 {
@@ -364,7 +417,7 @@ 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);
@@ -380,7 +433,7 @@ static int dns_read (void)
        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);
@@ -396,7 +449,7 @@ static int dns_read (void)
        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);