Merge pull request #3329 from efuss/fix-3311
[collectd.git] / src / curl.c
index 35ec1f8..7eb4805 100644 (file)
 
 #include "collectd.h"
 
-#include "common.h"
 #include "plugin.h"
-#include "utils_curl_stats.h"
-#include "utils_match.h"
+#include "utils/common/common.h"
+#include "utils/curl_stats/curl_stats.h"
+#include "utils/match/match.h"
 #include "utils_time.h"
 
 #include <curl/curl.h>
@@ -57,17 +57,18 @@ struct web_page_s /* {{{ */
   char *instance;
 
   char *url;
+  int address_family;
   char *user;
   char *pass;
   char *credentials;
-  _Bool digest;
-  _Bool verify_peer;
-  _Bool verify_host;
+  bool digest;
+  bool verify_peer;
+  bool verify_host;
   char *cacert;
   struct curl_slist *headers;
   char *post_body;
-  _Bool response_time;
-  _Bool response_code;
+  bool response_time;
+  bool response_code;
   int timeout;
   curl_stats_t *stats;
 
@@ -78,19 +79,13 @@ struct web_page_s /* {{{ */
   size_t buffer_fill;
 
   web_match_t *matches;
-
-  web_page_t *next;
 }; /* }}} */
 
 /*
- * Global variables;
- */
-/* static CURLM *curl = NULL; */
-static web_page_t *pages_g = NULL;
-
-/*
  * Private functions
  */
+static int cc_read_page(user_data_t *ud);
+
 static size_t cc_curl_callback(void *buf, /* {{{ */
                                size_t size, size_t nmemb, void *user_data) {
   web_page_t *wp;
@@ -138,8 +133,9 @@ static void cc_web_match_free(web_match_t *wm) /* {{{ */
   sfree(wm);
 } /* }}} void cc_web_match_free */
 
-static void cc_web_page_free(web_page_t *wp) /* {{{ */
+static void cc_web_page_free(void *arg) /* {{{ */
 {
+  web_page_t *wp = (web_page_t *)arg;
   if (wp == NULL)
     return;
 
@@ -162,7 +158,6 @@ static void cc_web_page_free(web_page_t *wp) /* {{{ */
   sfree(wp->buffer);
 
   cc_web_match_free(wp->matches);
-  cc_web_page_free(wp->next);
   sfree(wp);
 } /* }}} void cc_web_page_free */
 
@@ -351,6 +346,7 @@ static int cc_page_init_curl(web_page_t *wp) /* {{{ */
   curl_easy_setopt(wp->curl, CURLOPT_ERRORBUFFER, wp->curl_errbuf);
   curl_easy_setopt(wp->curl, CURLOPT_FOLLOWLOCATION, 1L);
   curl_easy_setopt(wp->curl, CURLOPT_MAXREDIRS, 50L);
+  curl_easy_setopt(wp->curl, CURLOPT_IPRESOLVE, wp->address_family);
 
   if (wp->user != NULL) {
 #ifdef HAVE_CURLOPT_USERNAME
@@ -401,6 +397,7 @@ static int cc_page_init_curl(web_page_t *wp) /* {{{ */
 
 static int cc_config_add_page(oconfig_item_t *ci) /* {{{ */
 {
+  cdtime_t interval = 0;
   web_page_t *page;
   int status;
 
@@ -416,13 +413,14 @@ static int cc_config_add_page(oconfig_item_t *ci) /* {{{ */
   }
   page->plugin_name = NULL;
   page->url = NULL;
+  page->address_family = CURL_IPRESOLVE_WHATEVER;
   page->user = NULL;
   page->pass = NULL;
-  page->digest = 0;
-  page->verify_peer = 1;
-  page->verify_host = 1;
-  page->response_time = 0;
-  page->response_code = 0;
+  page->digest = false;
+  page->verify_peer = true;
+  page->verify_host = true;
+  page->response_time = false;
+  page->response_code = false;
   page->timeout = -1;
   page->stats = NULL;
 
@@ -442,7 +440,34 @@ static int cc_config_add_page(oconfig_item_t *ci) /* {{{ */
       status = cf_util_get_string(child, &page->plugin_name);
     else if (strcasecmp("URL", child->key) == 0)
       status = cf_util_get_string(child, &page->url);
-    else if (strcasecmp("User", child->key) == 0)
+    else if (strcasecmp("AddressFamily", child->key) == 0) {
+      char *af = NULL;
+      status = cf_util_get_string(child, &af);
+      if (status != 0 || af == NULL) {
+        WARNING("curl plugin: Cannot parse value of `%s' "
+                "for instance `%s'.",
+                child->key, page->instance);
+      } else if (strcasecmp("any", af) == 0) {
+        page->address_family = CURL_IPRESOLVE_WHATEVER;
+      } else if (strcasecmp("ipv4", af) == 0) {
+        page->address_family = CURL_IPRESOLVE_V4;
+      } else if (strcasecmp("ipv6", af) == 0) {
+        /* If curl supports ipv6, use it. If not, log a warning and
+         * fall back to default - don't set status to non-zero.
+         */
+        curl_version_info_data *curl_info = curl_version_info(CURLVERSION_NOW);
+        if (curl_info->features & CURL_VERSION_IPV6)
+          page->address_family = CURL_IPRESOLVE_V6;
+        else
+          WARNING("curl plugin: IPv6 not supported by this libCURL. "
+                  "Using fallback `any'.");
+      } else {
+        WARNING("curl plugin: Unsupported value of `%s' "
+                "for instance `%s'.",
+                child->key, page->instance);
+        status = -1;
+      }
+    } else if (strcasecmp("User", child->key) == 0)
       status = cf_util_get_string(child, &page->user);
     else if (strcasecmp("Password", child->key) == 0)
       status = cf_util_get_string(child, &page->pass);
@@ -465,6 +490,8 @@ static int cc_config_add_page(oconfig_item_t *ci) /* {{{ */
       status = cc_config_append_string("Header", &page->headers, child);
     else if (strcasecmp("Post", child->key) == 0)
       status = cf_util_get_string(child, &page->post_body);
+    else if (strcasecmp("Interval", child->key) == 0)
+      status = cf_util_get_cdtime(child, &interval);
     else if (strcasecmp("Timeout", child->key) == 0)
       status = cf_util_get_int(child, &page->timeout);
     else if (strcasecmp("Statistics", child->key) == 0) {
@@ -508,17 +535,16 @@ static int cc_config_add_page(oconfig_item_t *ci) /* {{{ */
     return status;
   }
 
-  /* Add the new page to the linked list */
-  if (pages_g == NULL)
-    pages_g = page;
-  else {
-    web_page_t *prev;
+  /* If all went well, register this page for reading */
+  char *cb_name = ssnprintf_alloc("curl-%s-%s", page->instance, page->url);
 
-    prev = pages_g;
-    while (prev->next != NULL)
-      prev = prev->next;
-    prev->next = page;
-  }
+  plugin_register_complex_read(/* group = */ NULL, cb_name, cc_read_page,
+                               interval,
+                               &(user_data_t){
+                                   .data = page,
+                                   .free_func = cc_web_page_free,
+                               });
+  sfree(cb_name);
 
   return 0;
 } /* }}} int cc_config_add_page */
@@ -557,10 +583,6 @@ static int cc_config(oconfig_item_t *ci) /* {{{ */
 
 static int cc_init(void) /* {{{ */
 {
-  if (pages_g == NULL) {
-    INFO("curl plugin: No pages have been defined.");
-    return -1;
-  }
   curl_global_init(CURL_GLOBAL_SSL);
   return 0;
 } /* }}} int cc_init */
@@ -609,8 +631,16 @@ static void cc_submit_response_time(const web_page_t *wp, /* {{{ */
   plugin_dispatch_values(&vl);
 } /* }}} void cc_submit_response_time */
 
-static int cc_read_page(web_page_t *wp) /* {{{ */
+static int cc_read_page(user_data_t *ud) /* {{{ */
 {
+
+  if ((ud == NULL) || (ud->data == NULL)) {
+    ERROR("curl plugin: cc_read_page: Invalid user data.");
+    return -1;
+  }
+
+  web_page_t *wp = (web_page_t *)ud->data;
+
   int status;
   cdtime_t start = 0;
 
@@ -667,25 +697,7 @@ static int cc_read_page(web_page_t *wp) /* {{{ */
   return 0;
 } /* }}} int cc_read_page */
 
-static int cc_read(void) /* {{{ */
-{
-  for (web_page_t *wp = pages_g; wp != NULL; wp = wp->next)
-    cc_read_page(wp);
-
-  return 0;
-} /* }}} int cc_read */
-
-static int cc_shutdown(void) /* {{{ */
-{
-  cc_web_page_free(pages_g);
-  pages_g = NULL;
-
-  return 0;
-} /* }}} int cc_shutdown */
-
 void module_register(void) {
   plugin_register_complex_config("curl", cc_config);
   plugin_register_init("curl", cc_init);
-  plugin_register_read("curl", cc_read);
-  plugin_register_shutdown("curl", cc_shutdown);
 } /* void module_register */