X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fsnmp.c;h=352075f26ded8ef75802d020c069de9d53836c0a;hb=6d86a97190a193863aadc252f20f6b9dba61c263;hp=8673df199e9ffe135993986a24f5cc1e1607b50e;hpb=b7d4060cacd04d4bd0e174e85f91ca5afcacf01d;p=collectd.git diff --git a/src/snmp.c b/src/snmp.c index 8673df19..352075f2 100644 --- a/src/snmp.c +++ b/src/snmp.c @@ -22,6 +22,7 @@ #include "collectd.h" #include "common.h" #include "plugin.h" +#include "utils_complain.h" #include @@ -67,6 +68,7 @@ struct host_definition_s char *community; int version; void *sess_handle; + c_complain_t complaint; uint32_t interval; time_t next_update; data_definition_t **data_list; @@ -116,6 +118,7 @@ static pthread_cond_t host_cond = PTHREAD_COND_INITIALIZER; /* * Private functions */ +/* Many functions to handle the configuration. {{{ */ /* First there are many functions which do configuration stuff. It's a big * bloated and messy, I'm afraid. */ @@ -198,7 +201,8 @@ static int csnmp_config_add_data_instance (data_definition_t *dd, oconfig_item_t else { /* Instance is a simple string */ - strncpy (dd->instance.string, ci->values[0].value.string, DATA_MAX_NAME_LEN - 1); + sstrncpy (dd->instance.string, ci->values[0].value.string, + sizeof (dd->instance.string)); } return (0); @@ -526,9 +530,9 @@ static int csnmp_config_add_host_interval (host_definition_t *hd, oconfig_item_t return (-1); } - hd->interval = (int) ci->values[0].value.number; - if (hd->interval < 0) - hd->interval = 0; + hd->interval = ci->values[0].value.number >= 0 + ? (uint32_t) ci->values[0].value.number + : 0; return (0); } /* int csnmp_config_add_host_interval */ @@ -550,6 +554,7 @@ static int csnmp_config_add_host (oconfig_item_t *ci) return (-1); memset (hd, '\0', sizeof (host_definition_t)); hd->version = 2; + C_COMPLAIN_INIT (&hd->complaint); hd->name = strdup (ci->values[0].value.string); if (hd->name == NULL) @@ -652,28 +657,14 @@ static int csnmp_config (oconfig_item_t *ci) return (0); } /* int csnmp_config */ -/* End of the config stuff. Now the interesting part begins */ +/* }}} End of the config stuff. Now the interesting part begins */ static void csnmp_host_close_session (host_definition_t *host) { - int status; - if (host->sess_handle == NULL) return; - status = snmp_sess_close (host->sess_handle); - - if (status != 0) - { - char *errstr = NULL; - - snmp_sess_error (host->sess_handle, NULL, NULL, &errstr); - - ERROR ("snmp plugin: host %s: snmp_sess_close failed: %s", - host->name, (errstr == NULL) ? "Unknown problem" : errstr); - sfree (errstr); - } - + snmp_sess_close (host->sess_handle); host->sess_handle = NULL; } /* void csnmp_host_close_session */ @@ -705,6 +696,7 @@ static void csnmp_host_open_session (host_definition_t *host) } } /* void csnmp_host_open_session */ +/* TODO: Check if negative values wrap around. Problem: negative temperatures. */ static value_t csnmp_value_list_to_value (struct variable_list *vl, int type, double scale, double shift) { @@ -721,14 +713,18 @@ static value_t csnmp_value_list_to_value (struct variable_list *vl, int type, || (vl->type == ASN_GAUGE)) { temp = (uint32_t) *vl->val.integer; - DEBUG ("snmp plugin: Parsed int32 value is %llu.", temp); + DEBUG ("snmp plugin: Parsed int32 value is %"PRIu64".", temp); } else if (vl->type == ASN_COUNTER64) { temp = (uint32_t) vl->val.counter64->high; temp = temp << 32; temp += (uint32_t) vl->val.counter64->low; - DEBUG ("snmp plugin: Parsed int64 value is %llu.", temp); + DEBUG ("snmp plugin: Parsed int64 value is %"PRIu64".", temp); + } + else if (vl->type == ASN_OCTET_STR) + { + /* We'll handle this later.. */ } else { @@ -736,7 +732,51 @@ static value_t csnmp_value_list_to_value (struct variable_list *vl, int type, defined = 0; } - if (type == DS_TYPE_COUNTER) + if (vl->type == ASN_OCTET_STR) + { + char *endptr; + + endptr = NULL; + if (vl->val.string != NULL) + { + char string[64]; + size_t string_length; + + string_length = sizeof (string) - 1; + if (vl->val_len < string_length) + string_length = vl->val_len; + + /* The strings we get from the Net-SNMP library may not be null + * terminated. That is why we're using `membpy' here and not `strcpy'. + * `string_length' is set to `vl->val_len' which holds the length of the + * string. -octo */ + memcpy (string, vl->val.string, string_length); + string[string_length] = 0; + + if (type == DS_TYPE_COUNTER) + { + ret.counter = (counter_t) strtoll (string, &endptr, /* base = */ 0); + DEBUG ("snmp plugin: csnmp_value_list_to_value: String to counter: %s -> %llu", + string, (unsigned long long) ret.counter); + } + else if (type == DS_TYPE_GAUGE) + { + ret.gauge = (gauge_t) strtod (string, &endptr); + DEBUG ("snmp plugin: csnmp_value_list_to_value: String to gauge: %s -> %g", + string, (double) ret.gauge); + } + } + + /* Check if an error occurred */ + if ((vl->val.string == NULL) || (endptr == (char *) vl->val.string)) + { + if (type == DS_TYPE_COUNTER) + ret.counter = 0; + else if (type == DS_TYPE_GAUGE) + ret.gauge = NAN; + } + } + else if (type == DS_TYPE_COUNTER) { ret.counter = temp; } @@ -793,7 +833,7 @@ static int csnmp_check_res_left_subtree (const host_definition_t *host, if (vb == NULL) { ERROR ("snmp plugin: host %s: Expected one more variable for " - "the instance.."); + "the instance..", host->name); return (-1); } @@ -843,15 +883,15 @@ static int csnmp_instance_list_add (csnmp_list_instances_t **head, char *ptr; size_t instance_len; + memset (il->instance, 0, sizeof (il->instance)); instance_len = sizeof (il->instance) - 1; if (instance_len > vb->val_len) instance_len = vb->val_len; - strncpy (il->instance, (char *) ((vb->type == ASN_OCTET_STR) + sstrncpy (il->instance, (char *) ((vb->type == ASN_OCTET_STR) ? vb->val.string : vb->val.bitstring), - instance_len); - il->instance[instance_len] = '\0'; + instance_len + 1); for (ptr = il->instance; *ptr != '\0'; ptr++) { @@ -865,10 +905,9 @@ static int csnmp_instance_list_add (csnmp_list_instances_t **head, else { value_t val = csnmp_value_list_to_value (vb, DS_TYPE_COUNTER, 1.0, 0.0); - snprintf (il->instance, sizeof (il->instance), + ssnprintf (il->instance, sizeof (il->instance), "%llu", val.counter); } - il->instance[sizeof (il->instance) - 1] = '\0'; /* TODO: Debugging output */ @@ -921,12 +960,10 @@ static int csnmp_dispatch_table (host_definition_t *host, data_definition_t *dat return (-1); } - strncpy (vl.host, host->name, sizeof (vl.host)); - vl.host[sizeof (vl.host) - 1] = '\0'; - strcpy (vl.plugin, "snmp"); + sstrncpy (vl.host, host->name, sizeof (vl.host)); + sstrncpy (vl.plugin, "snmp", sizeof (vl.plugin)); vl.interval = host->interval; - vl.time = time (NULL); subid = 0; have_more = 1; @@ -986,30 +1023,28 @@ static int csnmp_dispatch_table (host_definition_t *host, data_definition_t *dat || (instance_list_ptr->subid == value_table_ptr[0]->subid)); #endif + sstrncpy (vl.type, data->type, sizeof (vl.type)); + { char temp[DATA_MAX_NAME_LEN]; if (instance_list_ptr == NULL) - snprintf (temp, sizeof (temp), "%u", - (uint32_t) subid); + ssnprintf (temp, sizeof (temp), "%u", (uint32_t) subid); else - strncpy (temp, instance_list_ptr->instance, - sizeof (temp)); - temp[sizeof (temp) - 1] = '\0'; + sstrncpy (temp, instance_list_ptr->instance, sizeof (temp)); if (data->instance_prefix == NULL) - strncpy (vl.type_instance, temp, sizeof (vl.type_instance)); + sstrncpy (vl.type_instance, temp, sizeof (vl.type_instance)); else - snprintf (vl.type_instance, sizeof (vl.type_instance), "%s%s", + ssnprintf (vl.type_instance, sizeof (vl.type_instance), "%s%s", data->instance_prefix, temp); - vl.type_instance[sizeof (vl.type_instance) - 1] = '\0'; } for (i = 0; i < data->values_len; i++) vl.values[i] = value_table_ptr[i]->value; /* If we get here `vl.type_instance' and all `vl.values' have been set */ - plugin_dispatch_values (data->type, &vl); + plugin_dispatch_values (&vl); subid++; } /* while (have_more != 0) */ @@ -1104,18 +1139,27 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data) break; } - for (i = 0; i < oid_list_len; i++) + for (i = 0; (uint32_t) i < oid_list_len; i++) snmp_add_null_var (req, oid_list[i].oid, oid_list[i].oid_len); + res = NULL; status = snmp_sess_synch_response (host->sess_handle, req, &res); - if (status != STAT_SUCCESS) + if ((status != STAT_SUCCESS) || (res == NULL)) { char *errstr = NULL; snmp_sess_error (host->sess_handle, NULL, NULL, &errstr); - ERROR ("snmp plugin: host %s: snmp_sess_synch_response failed: %s", + + c_complain (LOG_ERR, &host->complaint, + "snmp plugin: host %s: snmp_sess_synch_response failed: %s", host->name, (errstr == NULL) ? "Unknown problem" : errstr); + + if (res != NULL) + snmp_free_pdu (res); + res = NULL; + + sfree (errstr); csnmp_host_close_session (host); status = -1; @@ -1123,6 +1167,9 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data) } status = 0; assert (res != NULL); + c_release (LOG_INFO, &host->complaint, + "snmp plugin: host %s: snmp_sess_synch_response successful.", + host->name); vb = res->variables; if (vb == NULL) @@ -1134,7 +1181,10 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data) /* Check if all values (and possibly the instance) have left their * subtree */ if (csnmp_check_res_left_subtree (host, data, res) != 0) + { + status = 0; break; + } /* if an instance-OID is configured.. */ if (data->instance.oid.oid_len > 0) @@ -1154,11 +1204,7 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data) (vb != NULL) && (vb->next_variable != NULL); vb = vb->next_variable) /* do nothing */; - if (vb == NULL) - { - status = -1; - break; - } + assert (vb != NULL); /* Copy OID to oid_list[data->values_len] */ memcpy (oid_list[data->values_len].oid, vb->name, @@ -1221,6 +1267,10 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data) res = NULL; } /* while (status == 0) */ + if (res != NULL) + snmp_free_pdu (res); + res = NULL; + if (status == 0) csnmp_dispatch_table (host, data, instance_list, value_table); @@ -1296,11 +1346,10 @@ static int csnmp_read_value (host_definition_t *host, data_definition_t *data) vl.values[i].gauge = NAN; } - strncpy (vl.host, host->name, sizeof (vl.host)); - vl.host[sizeof (vl.host) - 1] = '\0'; - strcpy (vl.plugin, "snmp"); - strncpy (vl.type_instance, data->instance.string, sizeof (vl.type_instance)); - vl.type_instance[sizeof (vl.type_instance) - 1] = '\0'; + sstrncpy (vl.host, host->name, sizeof (vl.host)); + sstrncpy (vl.plugin, "snmp", sizeof (vl.plugin)); + sstrncpy (vl.type, data->type, sizeof (vl.type)); + sstrncpy (vl.type_instance, data->instance.string, sizeof (vl.type_instance)); vl.interval = host->interval; @@ -1314,22 +1363,28 @@ static int csnmp_read_value (host_definition_t *host, data_definition_t *data) for (i = 0; i < data->values_len; i++) snmp_add_null_var (req, data->values[i].oid, data->values[i].oid_len); + + res = NULL; status = snmp_sess_synch_response (host->sess_handle, req, &res); - if (status != STAT_SUCCESS) + if ((status != STAT_SUCCESS) || (res == NULL)) { char *errstr = NULL; snmp_sess_error (host->sess_handle, NULL, NULL, &errstr); ERROR ("snmp plugin: host %s: snmp_sess_synch_response failed: %s", host->name, (errstr == NULL) ? "Unknown problem" : errstr); - csnmp_host_close_session (host); + + if (res != NULL) + snmp_free_pdu (res); + res = NULL; + sfree (errstr); + csnmp_host_close_session (host); return (-1); } - vl.time = time (NULL); for (vb = res->variables; vb != NULL; vb = vb->next_variable) { @@ -1347,10 +1402,12 @@ static int csnmp_read_value (host_definition_t *host, data_definition_t *data) data->scale, data->shift); } /* for (res->variables) */ - snmp_free_pdu (res); + if (res != NULL) + snmp_free_pdu (res); + res = NULL; - DEBUG ("snmp plugin: -> plugin_dispatch_values (%s, &vl);", data->type); - plugin_dispatch_values (data->type, &vl); + DEBUG ("snmp plugin: -> plugin_dispatch_values (&vl);"); + plugin_dispatch_values (&vl); sfree (vl.values); return (0); @@ -1385,17 +1442,17 @@ static int csnmp_read_host (host_definition_t *host) time_end = time (NULL); DEBUG ("snmp plugin: csnmp_read_host (%s) finished at %u;", host->name, (unsigned int) time_end); - if ((time_end - time_start) > host->interval) + if ((uint32_t) (time_end - time_start) > host->interval) { WARNING ("snmp plugin: Host `%s' should be queried every %i seconds, " - "but reading all values takes %i seconds.", - host->name, host->interval, time_end - time_start); + "but reading all values takes %u seconds.", + host->name, host->interval, (unsigned int) (time_end - time_start)); } return (0); } /* int csnmp_read_host */ -static void *csnmp_read_thread (void *data) +static void *csnmp_read_thread (void __attribute__((unused)) *data) { host_definition_t *host; @@ -1448,7 +1505,7 @@ static int csnmp_init (void) { host->interval = interval_g; } - else if (host->interval < interval_g) + else if (host->interval < (uint32_t) interval_g) { host->interval = interval_g; WARNING ("snmp plugin: Data for host `%s' will be collected every %i seconds.", @@ -1577,5 +1634,5 @@ void module_register (void) } /* void module_register */ /* - * vim: shiftwidth=2 softtabstop=2 tabstop=8 + * vim: shiftwidth=2 softtabstop=2 tabstop=8 fdm=marker */