snmp plugin: Added a note about a potential bug that needs fixing.
[collectd.git] / src / snmp.c
index 6f11af0..995f39d 100644 (file)
@@ -692,6 +692,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)
 {
@@ -708,14 +709,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
   {
@@ -723,7 +728,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;
   }
@@ -780,7 +829,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);
     }
 
@@ -830,6 +879,7 @@ 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;
@@ -837,7 +887,7 @@ static int csnmp_instance_list_add (csnmp_list_instances_t **head,
     sstrncpy (il->instance, (char *) ((vb->type == ASN_OCTET_STR)
          ? vb->val.string
          : vb->val.bitstring),
-       instance_len);
+       instance_len + 1);
 
     for (ptr = il->instance; *ptr != '\0'; ptr++)
     {
@@ -907,7 +957,7 @@ static int csnmp_dispatch_table (host_definition_t *host, data_definition_t *dat
   }
 
   sstrncpy (vl.host, host->name, sizeof (vl.host));
-  strcpy (vl.plugin, "snmp");
+  sstrncpy (vl.plugin, "snmp", sizeof (vl.plugin));
 
   vl.interval = host->interval;
   vl.time = time (NULL);
@@ -1116,10 +1166,6 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data)
     vb = res->variables;
     if (vb == NULL)
     {
-      if (res != NULL)
-       snmp_free_pdu (res);
-      res = NULL;
-
       status = -1;
       break;
     }
@@ -1128,10 +1174,7 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data)
      * subtree */
     if (csnmp_check_res_left_subtree (host, data, res) != 0)
     {
-      if (res != NULL)
-       snmp_free_pdu (res);
-      res = NULL;
-
+      status = 0;
       break;
     }
 
@@ -1153,11 +1196,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,
@@ -1220,6 +1259,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,7 +1339,7 @@ static int csnmp_read_value (host_definition_t *host, data_definition_t *data)
   }
 
   sstrncpy (vl.host, host->name, sizeof (vl.host));
-  strcpy (vl.plugin, "snmp");
+  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));
 
@@ -1395,8 +1438,8 @@ static int csnmp_read_host (host_definition_t *host)
   if ((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);