X-Git-Url: https://git.octo.it/?p=collectd.git;a=blobdiff_plain;f=src%2Fcurl_xml.c;h=4524ac33669a80552d7e91b0191fd3e31be47b07;hp=d0b32cdac715a94d246199ebbfd0f3d9212dd1dd;hb=54619dc85fd308b21ed09a0271e5c7383c7921b9;hpb=65e4a089431217b9ef7222352deab31e3201bdaf diff --git a/src/curl_xml.c b/src/curl_xml.c index d0b32cda..4524ac33 100644 --- a/src/curl_xml.c +++ b/src/curl_xml.c @@ -21,9 +21,9 @@ #include "collectd.h" -#include "common.h" #include "plugin.h" -#include "utils_curl_stats.h" +#include "utils/common/common.h" +#include "utils/curl_stats/curl_stats.h" #include "utils_llist.h" #include @@ -76,12 +76,13 @@ struct cx_s /* {{{ */ char *host; 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; char *post_body; int timeout; @@ -157,13 +158,14 @@ static void cx_xpath_list_free(llist_t *list) /* {{{ */ while (le != NULL) { llentry_t *le_next = le->next; + /* this also frees xpath->path used for le->key */ cx_xpath_free(le->value); le = le_next; } llist_destroy(list); -} /* }}} void cx_list_free */ +} /* }}} void cx_xpath_list_free */ static void cx_free(void *arg) /* {{{ */ { @@ -239,8 +241,8 @@ static int cx_check_type(const data_set_t *ds, cx_xpath_t *xpath) /* {{{ */ } if (ds->ds_num != xpath->values_len) { - WARNING("curl_xml plugin: DataSet `%s' requires %zu values, but config " - "talks about %zu", + WARNING("curl_xml plugin: DataSet `%s' requires %" PRIsz + " values, but config talks about %" PRIsz, xpath->type, ds->ds_num, xpath->values_len); return -1; } @@ -275,6 +277,9 @@ static int cx_if_not_text_node(xmlNodePtr node) /* {{{ */ return -1; } /* }}} cx_if_not_text_node */ +/* + * Returned value should be freed with xmlFree(). + */ static char *cx_get_text_node_value(xmlXPathContextPtr xpath_ctx, /* {{{ */ char *expr, const char *from_option) { xmlXPathObjectPtr values_node_obj = cx_evaluate_xpath(xpath_ctx, expr); @@ -286,18 +291,18 @@ static char *cx_get_text_node_value(xmlXPathContextPtr xpath_ctx, /* {{{ */ if (tmp_size == 0) { WARNING("curl_xml plugin: " - "relative xpath expression \"%s\" %sdoesn't match " + "relative xpath expression \"%s\" from '%s' doesn't match " "any of the nodes.", - expr, (from_option == NULL) ? "" : from_option); + expr, from_option); xmlXPathFreeObject(values_node_obj); return NULL; } if (tmp_size > 1) { WARNING("curl_xml plugin: " - "relative xpath expression \"%s\" %sis expected to return " + "relative xpath expression \"%s\" from '%s' is expected to return " "only one text node. Skipping the node.", - expr, (from_option == NULL) ? "" : from_option); + expr, from_option); xmlXPathFreeObject(values_node_obj); return NULL; } @@ -305,10 +310,10 @@ static char *cx_get_text_node_value(xmlXPathContextPtr xpath_ctx, /* {{{ */ /* ignoring the element if other than textnode/attribute*/ if (cx_if_not_text_node(values_node->nodeTab[0])) { WARNING("curl_xml plugin: " - "relative xpath expression \"%s\" %sis expected to return " + "relative xpath expression \"%s\" from '%s' is expected to return " "only text/attribute node which is not the case. " "Skipping the node.", - expr, (from_option == NULL) ? "" : from_option); + expr, from_option); xmlXPathFreeObject(values_node_obj); return NULL; } @@ -326,7 +331,7 @@ static int cx_handle_single_value_xpath(xmlXPathContextPtr xpath_ctx, /* {{{ */ value_list_t *vl, int index) { char *node_value = cx_get_text_node_value( - xpath_ctx, xpath->values[index].path, "from 'ValuesFrom' "); + xpath_ctx, xpath->values[index].path, "ValuesFrom"); if (node_value == NULL) return -1; @@ -352,7 +357,7 @@ static int cx_handle_single_value_xpath(xmlXPathContextPtr xpath_ctx, /* {{{ */ /* endptr = */ NULL); } - sfree(node_value); + xmlFree(node_value); /* We have reached here which means that * we have got something to work */ @@ -385,8 +390,8 @@ static int cx_handle_instance_xpath(xmlXPathContextPtr xpath_ctx, /* {{{ */ /* Handle type instance */ if (xpath->instance != NULL) { - char *node_value = cx_get_text_node_value(xpath_ctx, xpath->instance, - "from 'InstanceFrom' "); + char *node_value = + cx_get_text_node_value(xpath_ctx, xpath->instance, "InstanceFrom"); if (node_value == NULL) return -1; @@ -396,7 +401,7 @@ static int cx_handle_instance_xpath(xmlXPathContextPtr xpath_ctx, /* {{{ */ else sstrncpy(vl->type_instance, node_value, sizeof(vl->type_instance)); - sfree(node_value); + xmlFree(node_value); } else if (xpath->instance_prefix != NULL) sstrncpy(vl->type_instance, xpath->instance_prefix, sizeof(vl->type_instance)); @@ -404,13 +409,13 @@ static int cx_handle_instance_xpath(xmlXPathContextPtr xpath_ctx, /* {{{ */ /* Handle plugin instance */ if (xpath->plugin_instance_from != NULL) { char *node_value = cx_get_text_node_value( - xpath_ctx, xpath->plugin_instance_from, "from 'PluginInstanceFrom' "); + xpath_ctx, xpath->plugin_instance_from, "PluginInstanceFrom"); if (node_value == NULL) return -1; sstrncpy(vl->plugin_instance, node_value, sizeof(vl->plugin_instance)); - sfree(node_value); + xmlFree(node_value); } return 0; @@ -448,6 +453,7 @@ static int cx_handle_xpath(const cx_t *db, /* {{{ */ "since the base xpath expression \"%s\" " "returned multiple results. Skipping the xpath block...", xpath->path); + xmlXPathFreeObject(base_node_obj); return -1; } @@ -664,13 +670,10 @@ static int cx_config_add_xpath(cx_t *db, oconfig_item_t *ci) /* {{{ */ return -1; } - if (db->xpath_list == NULL) { - db->xpath_list = llist_create(); - if (db->xpath_list == NULL) { - ERROR("curl_xml plugin: list creation failed."); - cx_xpath_free(xpath); - return -1; - } + if (xpath->values_len == 0) { + WARNING("curl_xml plugin: `ValuesFrom' missing in `xpath' block."); + cx_xpath_free(xpath); + return -1; } llentry_t *le = llentry_create(xpath->path, xpath); @@ -694,8 +697,8 @@ static int cx_config_add_namespace(cx_t *db, /* {{{ */ return EINVAL; } - cx_namespace_t *ns = realloc( - db->namespaces, sizeof(*db->namespaces) * (db->namespaces_num + 1)); + cx_namespace_t *ns = realloc(db->namespaces, sizeof(*db->namespaces) * + (db->namespaces_num + 1)); if (ns == NULL) { ERROR("curl_xml plugin: realloc failed."); return ENOMEM; @@ -734,6 +737,7 @@ static int cx_init_curl(cx_t *db) /* {{{ */ curl_easy_setopt(db->curl, CURLOPT_ERRORBUFFER, db->curl_errbuf); curl_easy_setopt(db->curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(db->curl, CURLOPT_MAXREDIRS, 50L); + curl_easy_setopt(db->curl, CURLOPT_IPRESOLVE, db->address_family); if (db->user != NULL) { #ifdef HAVE_CURLOPT_USERNAME @@ -784,8 +788,6 @@ static int cx_init_curl(cx_t *db) /* {{{ */ static int cx_config_add_url(oconfig_item_t *ci) /* {{{ */ { - int status = 0; - if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING)) { WARNING("curl_xml plugin: The `URL' block " "needs exactly one string argument."); @@ -798,22 +800,34 @@ static int cx_config_add_url(oconfig_item_t *ci) /* {{{ */ return -1; } - db->timeout = -1; + db->instance = strdup("default"); + if (db->instance == NULL) { + ERROR("curl_xml plugin: strdup failed."); + sfree(db); + return -1; + } - if (strcasecmp("URL", ci->key) == 0) { - status = cf_util_get_string(ci, &db->url); - if (status != 0) { - sfree(db); - return status; - } - } else { - ERROR("curl_xml plugin: cx_config: " - "Invalid key: %s", - ci->key); - cx_free(db); + db->xpath_list = llist_create(); + if (db->xpath_list == NULL) { + ERROR("curl_xml plugin: list creation failed."); + sfree(db->instance); + sfree(db); return -1; } + db->timeout = -1; + db->address_family = CURL_IPRESOLVE_WHATEVER; + + int status = cf_util_get_string(ci, &db->url); + if (status != 0) { + llist_destroy(db->xpath_list); + sfree(db->instance); + sfree(db); + return status; + } + + cdtime_t interval = 0; + /* Fill the `cx_t' structure.. */ for (int i = 0; i < ci->children_num; i++) { oconfig_item_t *child = ci->children + i; @@ -844,12 +858,39 @@ static int cx_config_add_url(oconfig_item_t *ci) /* {{{ */ status = cf_util_get_string(child, &db->post_body); else if (strcasecmp("Namespace", child->key) == 0) status = cx_config_add_namespace(db, child); + 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, &db->timeout); else if (strcasecmp("Statistics", child->key) == 0) { db->stats = curl_stats_from_config(child); if (db->stats == NULL) status = -1; + } else if (strcasecmp("AddressFamily", child->key) == 0) { + char *af = NULL; + status = cf_util_get_string(child, &af); + if (status != 0 || af == NULL) { + WARNING("curl_xml plugin: Cannot parse value of `%s' for URL `%s'.", + child->key, db->url); + } else if (strcasecmp("any", af) == 0) { + db->address_family = CURL_IPRESOLVE_WHATEVER; + } else if (strcasecmp("ipv4", af) == 0) { + db->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) + db->address_family = CURL_IPRESOLVE_V6; + else + WARNING("curl_xml plugin: IPv6 not supported by this libCURL. " + "Using fallback `any'."); + } else { + WARNING("curl_xml plugin: Unsupported value of `%s' for URL `%s'.", + child->key, db->url); + status = -1; + } } else { WARNING("curl_xml plugin: Option `%s' not allowed here.", child->key); status = -1; @@ -859,37 +900,35 @@ static int cx_config_add_url(oconfig_item_t *ci) /* {{{ */ break; } - if (status == 0) { - if (db->xpath_list == NULL) { - WARNING("curl_xml plugin: No (valid) `xpath' block " - "within `URL' block `%s'.", - db->url); - status = -1; - } - if (status == 0) - status = cx_init_curl(db); + if (status != 0) { + cx_free(db); + return status; } - /* If all went well, register this database for reading */ - if (status == 0) { - if (db->instance == NULL) - db->instance = strdup("default"); - - DEBUG("curl_xml plugin: Registering new read callback: %s", db->instance); - - char *cb_name = ssnprintf_alloc("curl_xml-%s-%s", db->instance, db->url); + if (llist_size(db->xpath_list) == 0) { + WARNING("curl_xml plugin: No `xpath' block within `URL' block `%s'.", + db->url); + cx_free(db); + return -1; + } - plugin_register_complex_read(/* group = */ "curl_xml", cb_name, cx_read, - /* interval = */ 0, - &(user_data_t){ - .data = db, .free_func = cx_free, - }); - sfree(cb_name); - } else { + if (cx_init_curl(db) != 0) { cx_free(db); return -1; } + /* If all went well, register this database for reading */ + DEBUG("curl_xml plugin: Registering new read callback: %s", db->instance); + + char *cb_name = ssnprintf_alloc("curl_xml-%s-%s", db->instance, db->url); + + plugin_register_complex_read(/* group = */ "curl_xml", cb_name, cx_read, + /* interval = */ interval, + &(user_data_t){ + .data = db, + .free_func = cx_free, + }); + sfree(cb_name); return 0; } /* }}} int cx_config_add_url */