Merge branch 'pr/1649'
[collectd.git] / src / bind.c
index 59eb249..09de4a3 100644 (file)
@@ -36,9 +36,9 @@
 #endif /* STRPTIME_NEEDS_STANDARDS */
 
 #include "collectd.h"
+
 #include "common.h"
 #include "plugin.h"
-#include "configfile.h"
 
 /* Some versions of libcurl don't include this themselves and then don't have
  * fd_set available. */
@@ -54,7 +54,7 @@
 # define BIND_DEFAULT_URL "http://localhost:8053/"
 #endif
 
-/* 
+/*
  * Some types used for the callback functions. `translation_table_ptr_t' and
  * `list_info_ptr_t' are passed to the callbacks in the `void *user_data'
  * pointer.
@@ -109,6 +109,7 @@ static int global_server_stats     = 1;
 static int global_zone_maint_stats = 1;
 static int global_resolver_stats   = 0;
 static int global_memory_stats     = 1;
+static int timeout                 = -1;
 
 static cb_view_t *views = NULL;
 static size_t     views_num = 0;
@@ -246,12 +247,9 @@ static int memsummary_translation_table_length =
 static void submit (time_t ts, const char *plugin_instance, /* {{{ */
     const char *type, const char *type_instance, value_t value)
 {
-  value_t values[1];
   value_list_t vl = VALUE_LIST_INIT;
 
-  values[0] = value;
-
-  vl.values = values;
+  vl.values = &value;
   vl.values_len = 1;
   if (config_parse_time)
     vl.time = TIME_T_TO_CDTIME_T (ts);
@@ -266,7 +264,7 @@ static void submit (time_t ts, const char *plugin_instance, /* {{{ */
   if (type_instance) {
     sstrncpy(vl.type_instance, type_instance,
         sizeof(vl.type_instance));
-    replace_special (vl.plugin_instance, sizeof (vl.plugin_instance));
+    replace_special (vl.type_instance, sizeof (vl.type_instance));
   }
   plugin_dispatch_values(&vl);
 } /* }}} void submit */
@@ -276,14 +274,14 @@ static size_t bind_curl_callback (void *buf, size_t size, /* {{{ */
 {
   size_t len = size * nmemb;
 
-  if (len <= 0)
+  if (len == 0)
     return (len);
 
   if ((bind_buffer_fill + len) >= bind_buffer_size)
   {
     char *temp;
 
-    temp = realloc(bind_buffer, bind_buffer_fill + len + 1);
+    temp = realloc (bind_buffer, bind_buffer_fill + len + 1);
     if (temp == NULL)
     {
       ERROR ("bind plugin: realloc failed.");
@@ -308,12 +306,11 @@ static int bind_xml_table_callback (const char *name, value_t value, /* {{{ */
     time_t current_time, void *user_data)
 {
   translation_table_ptr_t *table = (translation_table_ptr_t *) user_data;
-  size_t i;
 
   if (table == NULL)
     return (-1);
 
-  for (i = 0; i < table->table_length; i++)
+  for (size_t i = 0; i < table->table_length; i++)
   {
     if (strcmp (table->table[i].xml_name, name) != 0)
       continue;
@@ -369,9 +366,11 @@ static int bind_xml_read_derive (xmlDoc *doc, xmlNode *node, /* {{{ */
   {
     ERROR ("bind plugin: Parsing string \"%s\" to derive value failed.",
         str_ptr);
+    xmlFree(str_ptr);
     return (-1);
   }
 
+  xmlFree(str_ptr);
   *ret_value = value.derive;
   return (0);
 } /* }}} int bind_xml_read_derive */
@@ -414,7 +413,7 @@ static int bind_xml_read_timestamp (const char *xpath_expression, /* {{{ */
   xmlNode *node;
   char *str_ptr;
   char *tmp;
-  struct tm tm;
+  struct tm tm = { 0 };
 
   xpathObj = xmlXPathEvalExpression (BAD_CAST xpath_expression, xpathCtx);
   if (xpathObj == NULL)
@@ -455,7 +454,6 @@ static int bind_xml_read_timestamp (const char *xpath_expression, /* {{{ */
     return (-1);
   }
 
-  memset (&tm, 0, sizeof(tm));
   tmp = strptime (str_ptr, "%Y-%m-%dT%T", &tm);
   xmlFree(str_ptr);
   if (tmp == NULL)
@@ -471,7 +469,7 @@ static int bind_xml_read_timestamp (const char *xpath_expression, /* {{{ */
   return (0);
 } /* }}} int bind_xml_read_timestamp */
 
-/* 
+/*
  * bind_parse_generic_name_value
  *
  * Reads statistics in the form:
@@ -488,7 +486,6 @@ static int bind_parse_generic_name_value (const char *xpath_expression, /* {{{ *
 {
   xmlXPathObject *xpathObj = NULL;
   int num_entries;
-  int i;
 
   xpathObj = xmlXPathEvalExpression(BAD_CAST xpath_expression, xpathCtx);
   if (xpathObj == NULL)
@@ -500,19 +497,18 @@ static int bind_parse_generic_name_value (const char *xpath_expression, /* {{{ *
 
   num_entries = 0;
   /* Iterate over all matching nodes. */
-  for (i = 0; xpathObj->nodesetval && (i < xpathObj->nodesetval->nodeNr); i++)
+  for (int i = 0; xpathObj->nodesetval && (i < xpathObj->nodesetval->nodeNr); i++)
   {
     xmlNode *name_node = NULL;
     xmlNode *counter = NULL;
     xmlNode *parent;
-    xmlNode *child;
 
     parent = xpathObj->nodesetval->nodeTab[i];
     DEBUG ("bind plugin: bind_parse_generic_name_value: parent->name = %s;",
         (char *) parent->name);
 
     /* Iterate over all child nodes. */
-    for (child = parent->xmlChildrenNode;
+    for (xmlNode *child = parent->xmlChildrenNode;
         child != NULL;
         child = child->next)
     {
@@ -556,7 +552,7 @@ static int bind_parse_generic_name_value (const char *xpath_expression, /* {{{ *
   return (0);
 } /* }}} int bind_parse_generic_name_value */
 
-/* 
+/*
  * bind_parse_generic_value_list
  *
  * Reads statistics in the form:
@@ -575,7 +571,6 @@ static int bind_parse_generic_value_list (const char *xpath_expression, /* {{{ *
 {
   xmlXPathObject *xpathObj = NULL;
   int num_entries;
-  int i;
 
   xpathObj = xmlXPathEvalExpression(BAD_CAST xpath_expression, xpathCtx);
   if (xpathObj == NULL)
@@ -587,12 +582,10 @@ static int bind_parse_generic_value_list (const char *xpath_expression, /* {{{ *
 
   num_entries = 0;
   /* Iterate over all matching nodes. */
-  for (i = 0; xpathObj->nodesetval && (i < xpathObj->nodesetval->nodeNr); i++)
+  for (int i = 0; xpathObj->nodesetval && (i < xpathObj->nodesetval->nodeNr); i++)
   {
-    xmlNode *child;
-
     /* Iterate over all child nodes. */
-    for (child = xpathObj->nodesetval->nodeTab[i]->xmlChildrenNode;
+    for (xmlNode *child = xpathObj->nodesetval->nodeTab[i]->xmlChildrenNode;
         child != NULL;
         child = child->next)
     {
@@ -646,7 +639,6 @@ static int bind_parse_generic_name_attr_value_list (const char *xpath_expression
 {
   xmlXPathObject *xpathObj = NULL;
   int num_entries;
-  int i;
 
   xpathObj = xmlXPathEvalExpression(BAD_CAST xpath_expression, xpathCtx);
   if (xpathObj == NULL)
@@ -658,12 +650,10 @@ static int bind_parse_generic_name_attr_value_list (const char *xpath_expression
 
   num_entries = 0;
   /* Iterate over all matching nodes. */
-  for (i = 0; xpathObj->nodesetval && (i < xpathObj->nodesetval->nodeNr); i++)
+  for (int i = 0; xpathObj->nodesetval && (i < xpathObj->nodesetval->nodeNr); i++)
   {
-    xmlNode *child;
-
     /* Iterate over all child nodes. */
-    for (child = xpathObj->nodesetval->nodeTab[i]->xmlChildrenNode;
+    for (xmlNode *child = xpathObj->nodesetval->nodeTab[i]->xmlChildrenNode;
         child != NULL;
         child = child->next)
     {
@@ -711,28 +701,42 @@ static int bind_xml_stats_handle_zone (int version, xmlDoc *doc, /* {{{ */
 {
   xmlXPathObject *path_obj;
   char *zone_name = NULL;
-  int i;
   size_t j;
 
-  path_obj = xmlXPathEvalExpression (BAD_CAST "name", path_ctx);
-  if (path_obj == NULL)
+  if (version >= 3)
   {
-    ERROR ("bind plugin: xmlXPathEvalExpression failed.");
-    return (-1);
+    char *n = (char *) xmlGetProp (node, BAD_CAST "name");
+    char *c = (char *) xmlGetProp (node, BAD_CAST "rdataclass");
+    if (n && c)
+    {
+      zone_name = (char *) xmlMalloc(strlen(n) + strlen(c) + 2);
+      snprintf(zone_name, strlen(n) + strlen(c) + 2, "%s/%s", n, c);
+    }
+    xmlFree(n);
+    xmlFree(c);
   }
-
-  for (i = 0; path_obj->nodesetval && (i < path_obj->nodesetval->nodeNr); i++)
+  else
   {
-    zone_name = (char *) xmlNodeListGetString (doc,
-        path_obj->nodesetval->nodeTab[i]->xmlChildrenNode, 1);
-    if (zone_name != NULL)
-      break;
+    path_obj = xmlXPathEvalExpression (BAD_CAST "name", path_ctx);
+    if (path_obj == NULL)
+    {
+      ERROR ("bind plugin: xmlXPathEvalExpression failed.");
+      return (-1);
+    }
+
+    for (int i = 0; path_obj->nodesetval && (i < path_obj->nodesetval->nodeNr); i++)
+    {
+      zone_name = (char *) xmlNodeListGetString (doc,
+          path_obj->nodesetval->nodeTab[i]->xmlChildrenNode, 1);
+      if (zone_name != NULL)
+        break;
+    }
+    xmlXPathFreeObject (path_obj);
   }
 
   if (zone_name == NULL)
   {
     ERROR ("bind plugin: Could not determine zone name.");
-    xmlXPathFreeObject (path_obj);
     return (-1);
   }
 
@@ -745,11 +749,8 @@ static int bind_xml_stats_handle_zone (int version, xmlDoc *doc, /* {{{ */
   xmlFree (zone_name);
   zone_name = NULL;
 
-  if (j >= views->zones_num)
-  {
-    xmlXPathFreeObject (path_obj);
+  if (j >= view->zones_num)
     return (0);
-  }
 
   zone_name = view->zones[j];
 
@@ -759,7 +760,7 @@ static int bind_xml_stats_handle_zone (int version, xmlDoc *doc, /* {{{ */
   { /* Parse the <counters> tag {{{ */
     char plugin_instance[DATA_MAX_NAME_LEN];
     translation_table_ptr_t table_ptr =
-    { 
+    {
       nsstats_translation_table,
       nsstats_translation_table_length,
       plugin_instance
@@ -768,14 +769,31 @@ static int bind_xml_stats_handle_zone (int version, xmlDoc *doc, /* {{{ */
     ssnprintf (plugin_instance, sizeof (plugin_instance), "%s-zone-%s",
         view->name, zone_name);
 
-    bind_parse_generic_value_list (/* xpath = */ "counters",
+    if (version == 3)
+    {
+      list_info_ptr_t list_info =
+      {
+        plugin_instance,
+        /* type = */ "dns_qtype"
+      };
+      bind_parse_generic_name_attr_value_list (/* xpath = */ "counters[@type='rcode']",
         /* callback = */ bind_xml_table_callback,
         /* user_data = */ &table_ptr,
         doc, path_ctx, current_time, DS_TYPE_COUNTER);
+      bind_parse_generic_name_attr_value_list (/* xpath = */ "counters[@type='qtype']",
+        /* callback = */ bind_xml_list_callback,
+        /* user_data = */ &list_info,
+        doc, path_ctx, current_time, DS_TYPE_COUNTER);
+    }
+    else
+    {
+      bind_parse_generic_value_list (/* xpath = */ "counters",
+          /* callback = */ bind_xml_table_callback,
+          /* user_data = */ &table_ptr,
+          doc, path_ctx, current_time, DS_TYPE_COUNTER);
+    }
   } /* }}} */
 
-  xmlXPathFreeObject (path_obj);
-
   return (0);
 } /* }}} int bind_xml_stats_handle_zone */
 
@@ -785,7 +803,6 @@ static int bind_xml_stats_search_zones (int version, xmlDoc *doc, /* {{{ */
 {
   xmlXPathObject *zone_nodes = NULL;
   xmlXPathContext *zone_path_context;
-  int i;
 
   zone_path_context = xmlXPathNewContext (doc);
   if (zone_path_context == NULL)
@@ -802,10 +819,8 @@ static int bind_xml_stats_search_zones (int version, xmlDoc *doc, /* {{{ */
     return (-1);
   }
 
-  for (i = 0; i < zone_nodes->nodesetval->nodeNr; i++)
+  for (int i = 0; i < zone_nodes->nodesetval->nodeNr; i++)
   {
-    xmlNode *node;
-
     node = zone_nodes->nodesetval->nodeTab[i];
     assert (node != NULL);
 
@@ -825,7 +840,6 @@ static int bind_xml_stats_handle_view (int version, xmlDoc *doc, /* {{{ */
 {
   char *view_name = NULL;
   cb_view_t *view;
-  int i;
   size_t j;
 
   if (version == 3)
@@ -857,7 +871,7 @@ static int bind_xml_stats_handle_view (int version, xmlDoc *doc, /* {{{ */
       return (-1);
     }
 
-    for (i = 0; path_obj->nodesetval && (i < path_obj->nodesetval->nodeNr); i++)
+    for (int i = 0; path_obj->nodesetval && (i < path_obj->nodesetval->nodeNr); i++)
     {
       view_name = (char *) xmlNodeListGetString (doc,
           path_obj->nodesetval->nodeTab[i]->xmlChildrenNode, 1);
@@ -925,7 +939,7 @@ static int bind_xml_stats_handle_view (int version, xmlDoc *doc, /* {{{ */
   {
     char plugin_instance[DATA_MAX_NAME_LEN];
     translation_table_ptr_t table_ptr =
-    { 
+    {
       resstats_translation_table,
       resstats_translation_table_length,
       plugin_instance
@@ -968,8 +982,7 @@ static int bind_xml_stats_handle_view (int version, xmlDoc *doc, /* {{{ */
         doc, path_ctx, current_time, DS_TYPE_GAUGE);
   } /* }}} */
 
-  // v3 does not provide per-zone stats any more
-  if (version < 3 && view->zones_num > 0)
+  if (view->zones_num > 0)
     bind_xml_stats_search_zones (version, doc, path_ctx, node, view,
         current_time);
 
@@ -981,7 +994,6 @@ static int bind_xml_stats_search_views (int version, xmlDoc *doc, /* {{{ */
 {
   xmlXPathObject *view_nodes = NULL;
   xmlXPathContext *view_path_context;
-  int i;
 
   view_path_context = xmlXPathNewContext (doc);
   if (view_path_context == NULL)
@@ -998,7 +1010,7 @@ static int bind_xml_stats_search_views (int version, xmlDoc *doc, /* {{{ */
     return (-1);
   }
 
-  for (i = 0; i < view_nodes->nodesetval->nodeNr; i++)
+  for (int i = 0; i < view_nodes->nodesetval->nodeNr; i++)
   {
     xmlNode *node;
 
@@ -1412,7 +1424,6 @@ static int bind_xml (const char *data) /* {{{ */
   xmlXPathContext *xpathCtx = NULL;
   xmlXPathObject *xpathObj = NULL;
   int ret = -1;
-  int i;
 
   doc = xmlParseMemory (data, strlen (data));
   if (doc == NULL)
@@ -1442,7 +1453,7 @@ static int bind_xml (const char *data) /* {{{ */
   }
   else
   {
-    for (i = 0; i < xpathObj->nodesetval->nodeNr; i++)
+    for (int i = 0; i < xpathObj->nodesetval->nodeNr; i++)
     {
       xmlNode *node;
       char *attr_version;
@@ -1504,7 +1515,7 @@ static int bind_xml (const char *data) /* {{{ */
     return (-1);
   }
 
-  for (i = 0; i < xpathObj->nodesetval->nodeNr; i++)
+  for (int i = 0; i < xpathObj->nodesetval->nodeNr; i++)
   {
     xmlNode *node;
     char *attr_version;
@@ -1584,7 +1595,7 @@ static int bind_config_add_view_zone (cb_view_t *view, /* {{{ */
     return (-1);
   }
 
-  tmp = (char **) realloc (view->zones,
+  tmp = realloc (view->zones,
       sizeof (char *) * (view->zones_num + 1));
   if (tmp == NULL)
   {
@@ -1607,7 +1618,6 @@ static int bind_config_add_view_zone (cb_view_t *view, /* {{{ */
 static int bind_config_add_view (oconfig_item_t *ci) /* {{{ */
 {
   cb_view_t *tmp;
-  int i;
 
   if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
   {
@@ -1615,7 +1625,7 @@ static int bind_config_add_view (oconfig_item_t *ci) /* {{{ */
     return (-1);
   }
 
-  tmp = (cb_view_t *) realloc (views, sizeof (*views) * (views_num + 1));
+  tmp = realloc (views, sizeof (*views) * (views_num + 1));
   if (tmp == NULL)
   {
     ERROR ("bind plugin: realloc failed.");
@@ -1635,11 +1645,11 @@ static int bind_config_add_view (oconfig_item_t *ci) /* {{{ */
   if (tmp->name == NULL)
   {
     ERROR ("bind plugin: strdup failed.");
-    free (tmp);
+    sfree (views);
     return (-1);
   }
 
-  for (i = 0; i < ci->children_num; i++)
+  for (int i = 0; i < ci->children_num; i++)
   {
     oconfig_item_t *child = ci->children + i;
 
@@ -1664,9 +1674,7 @@ static int bind_config_add_view (oconfig_item_t *ci) /* {{{ */
 
 static int bind_config (oconfig_item_t *ci) /* {{{ */
 {
-  int i;
-
-  for (i = 0; i < ci->children_num; i++)
+  for (int i = 0; i < ci->children_num; i++)
   {
     oconfig_item_t *child = ci->children + i;
 
@@ -1678,6 +1686,7 @@ static int bind_config (oconfig_item_t *ci) /* {{{ */
         return (-1);
       }
 
+      sfree (url);
       url = strdup (child->values[0].value.string);
     } else if (strcasecmp ("OpCodes", child->key) == 0)
       bind_config_set_bool ("OpCodes", &global_opcodes, child);
@@ -1695,6 +1704,8 @@ static int bind_config (oconfig_item_t *ci) /* {{{ */
       bind_config_add_view (child);
     else if (strcasecmp ("ParseTime", child->key) == 0)
       cf_util_get_boolean (child, &config_parse_time);
+    else if (strcasecmp ("Timeout", child->key) == 0)
+      cf_util_get_int (child, &timeout);
     else
     {
       WARNING ("bind plugin: Unknown configuration option "
@@ -1724,6 +1735,11 @@ static int bind_init (void) /* {{{ */
   curl_easy_setopt (curl, CURLOPT_URL, (url != NULL) ? url : BIND_DEFAULT_URL);
   curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION, 1L);
   curl_easy_setopt (curl, CURLOPT_MAXREDIRS, 50L);
+#ifdef HAVE_CURLOPT_TIMEOUT_MS
+  curl_easy_setopt (curl, CURLOPT_TIMEOUT_MS, (timeout >= 0) ?
+      (long) timeout : (long) CDTIME_T_TO_MS(plugin_get_interval()));
+#endif
+
 
   return (0);
 } /* }}} int bind_init */