#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>
typedef struct web_page_s web_page_t;
struct web_page_s /* {{{ */
{
+ char *plugin_name;
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;
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;
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;
curl_easy_cleanup(wp->curl);
wp->curl = NULL;
+ sfree(wp->plugin_name);
sfree(wp->instance);
sfree(wp->url);
sfree(wp->buffer);
cc_web_match_free(wp->matches);
- cc_web_page_free(wp->next);
sfree(wp);
} /* }}} void cc_web_page_free */
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
static int cc_config_add_page(oconfig_item_t *ci) /* {{{ */
{
+ cdtime_t interval = 0;
web_page_t *page;
int status;
ERROR("curl plugin: calloc failed.");
return -1;
}
+ 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;
for (int i = 0; i < ci->children_num; i++) {
oconfig_item_t *child = ci->children + i;
- if (strcasecmp("URL", child->key) == 0)
+ if (strcasecmp("Plugin", child->key) == 0)
+ 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);
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) {
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 */
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 */
vl.values = &value;
vl.values_len = 1;
- sstrncpy(vl.plugin, "curl", sizeof(vl.plugin));
+ sstrncpy(vl.plugin, (wp->plugin_name != NULL) ? wp->plugin_name : "curl",
+ sizeof(vl.plugin));
sstrncpy(vl.plugin_instance, wp->instance, sizeof(vl.plugin_instance));
sstrncpy(vl.type, wm->type, sizeof(vl.type));
if (wm->instance != NULL)
vl.values = &(value_t){.gauge = (gauge_t)code};
vl.values_len = 1;
- sstrncpy(vl.plugin, "curl", sizeof(vl.plugin));
+ sstrncpy(vl.plugin, (wp->plugin_name != NULL) ? wp->plugin_name : "curl",
+ sizeof(vl.plugin));
sstrncpy(vl.plugin_instance, wp->instance, sizeof(vl.plugin_instance));
sstrncpy(vl.type, "response_code", sizeof(vl.type));
vl.values = &(value_t){.gauge = response_time};
vl.values_len = 1;
- sstrncpy(vl.plugin, "curl", sizeof(vl.plugin));
+ sstrncpy(vl.plugin, (wp->plugin_name != NULL) ? wp->plugin_name : "curl",
+ sizeof(vl.plugin));
sstrncpy(vl.plugin_instance, wp->instance, sizeof(vl.plugin_instance));
sstrncpy(vl.type, "response_time", sizeof(vl.type));
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;
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 */