network plugin: Fix error message for GCRYCTL_INIT_SECMEM failure.
[collectd.git] / src / snmp.c
index e265ae0..8ab2bf8 100644 (file)
@@ -123,7 +123,7 @@ static int csnmp_oid_suffix (oid_t *dst, oid_t const *src,
     oid_t const *root)
 {
   /* Make sure "src" is in "root"s subtree. */
-  if (src->oid_len >= root->oid_len)
+  if (src->oid_len <= root->oid_len)
     return (EINVAL);
   if (snmp_oid_ncompare (root->oid, root->oid_len,
         src->oid, src->oid_len,
@@ -1050,6 +1050,7 @@ static int csnmp_instance_list_add (csnmp_list_instances_t **head,
   csnmp_list_instances_t *il;
   struct variable_list *vb;
   oid_t vb_name;
+  int status;
 
   /* Set vb on the last variable */
   for (vb = res->variables;
@@ -1067,9 +1068,16 @@ static int csnmp_instance_list_add (csnmp_list_instances_t **head,
     ERROR ("snmp plugin: malloc failed.");
     return (-1);
   }
-  csnmp_oid_suffix (&il->suffix, &vb_name, root);
+  memset (il, 0, sizeof (*il));
   il->next = NULL;
 
+  status = csnmp_oid_suffix (&il->suffix, &vb_name, root);
+  if (status != 0)
+  {
+    sfree (il);
+    return (status);
+  }
+
   /* Get instance name */
   if ((vb->type == ASN_OCTET_STR) || (vb->type == ASN_BIT_STR))
   {
@@ -1128,15 +1136,14 @@ static int csnmp_dispatch_table (host_definition_t *host, data_definition_t *dat
 
   instance_list_ptr = instance_list;
 
-  value_table_ptr = (csnmp_table_values_t **) malloc (sizeof (csnmp_table_values_t *)
-      * data->values_len);
+  value_table_ptr = malloc (sizeof (*value_table_ptr) * data->values_len);
   if (value_table_ptr == NULL)
     return (-1);
   for (i = 0; i < data->values_len; i++)
     value_table_ptr[i] = value_table[i];
 
   vl.values_len = ds->ds_num;
-  vl.values = (value_t *) malloc (sizeof (value_t) * vl.values_len);
+  vl.values = malloc (sizeof (*vl.values) * vl.values_len);
   if (vl.values == NULL)
   {
     ERROR ("snmp plugin: malloc failed.");
@@ -1158,7 +1165,6 @@ static int csnmp_dispatch_table (host_definition_t *host, data_definition_t *dat
     /* Determine next suffix to handle. */
     if (instance_list != NULL)
     {
-      instance_list_ptr = instance_list_ptr->next;
       if (instance_list_ptr == NULL)
       {
         have_more = 0;
@@ -1170,7 +1176,6 @@ static int csnmp_dispatch_table (host_definition_t *host, data_definition_t *dat
     else /* no instance configured */
     {
       csnmp_table_values_t *ptr = value_table_ptr[0];
-      ptr = ptr->next;
       if (ptr == NULL)
       {
         have_more = 0;
@@ -1202,9 +1207,19 @@ static int csnmp_dispatch_table (host_definition_t *host, data_definition_t *dat
       }
     } /* for (i = 0; i < columns; i++) */
 
+    if (!have_more)
+      break;
+
     /* Matching the values failed. Start from the beginning again. */
-    if (!have_more || suffix_skipped)
+    if (suffix_skipped)
+    {
+      if (instance_list != NULL)
+        instance_list_ptr = instance_list_ptr->next;
+      else
+        value_table_ptr[0] = value_table_ptr[0]->next;
+
       continue;
+    }
 
     /* if we reach this line, all value_table_ptr[i] are non-NULL and are set
      * to the same subid. instance_list_ptr is either NULL or points to the
@@ -1243,6 +1258,11 @@ static int csnmp_dispatch_table (host_definition_t *host, data_definition_t *dat
 
     /* If we get here `vl.type_instance' and all `vl.values' have been set */
     plugin_dispatch_values (&vl);
+
+    if (instance_list != NULL)
+      instance_list_ptr = instance_list_ptr->next;
+    else
+      value_table_ptr[0] = value_table_ptr[0]->next;
   } /* while (have_more) */
 
   sfree (vl.values);
@@ -1357,6 +1377,8 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data)
         snmp_free_pdu (res);
       res = NULL;
 
+      /* snmp_synch_response already freed our PDU */
+      req = NULL;
       sfree (errstr);
       csnmp_host_close_session (host);
 
@@ -1423,16 +1445,17 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data)
     {
       csnmp_table_values_t *vt;
       oid_t vb_name;
+      oid_t suffix;
 
       csnmp_oid_init (&vb_name, vb->name, vb->name_length);
 
-      /* Check if we left the subtree */
-      if (snmp_oid_ncompare (data->values[i].oid,
-            data->values[i].oid_len,
-            vb->name, vb->name_length,
-            data->values[i].oid_len) != 0)
+      /* Calculate the current suffix. This is later used to check that the
+       * suffix is increasing. This also checks if we left the subtree */
+      status = csnmp_oid_suffix (&suffix, &vb_name, data->values + i);
+      if (status != 0)
       {
-        DEBUG ("snmp plugin: host = %s; data = %s; Value %i left its subtree.",
+        DEBUG ("snmp plugin: host = %s; data = %s; Value %i failed. "
+            "It probably left its subtree.",
             host->name, data->name, i);
         continue;
       }
@@ -1440,10 +1463,10 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data)
       /* Make sure the OIDs returned by the agent are increasing. Otherwise our
        * table matching algorithm will get confused. */
       if ((value_list_tail[i] != NULL)
-          && (csnmp_oid_compare (&vb_name, &value_list_tail[i]->suffix) <= 0))
+          && (csnmp_oid_compare (&suffix, &value_list_tail[i]->suffix) <= 0))
       {
         DEBUG ("snmp plugin: host = %s; data = %s; i = %i; "
-            "SUBID is not increasing.",
+            "Suffix is not increasing.",
             host->name, data->name, i);
         continue;
       }
@@ -1457,9 +1480,9 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data)
       }
       memset (vt, 0, sizeof (*vt));
 
-      csnmp_oid_suffix (&vt->suffix, &vb_name, data->values + i);
       vt->value = csnmp_value_list_to_value (vb, ds->ds[i].type,
           data->scale, data->shift);
+      memcpy (&vt->suffix, &suffix, sizeof (vt->suffix));
       vt->next = NULL;
 
       if (value_list_tail[i] == NULL)
@@ -1482,6 +1505,10 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data)
     snmp_free_pdu (res);
   res = NULL;
 
+  if (req != NULL)
+    snmp_free_pdu (req);
+  req = NULL;
+
   if (status == 0)
     csnmp_dispatch_table (host, data, instance_list_head, value_list_head);