Merge branch 'collectd-4.10' into collectd-5.0
[collectd.git] / src / snmp.c
index e265ae0..b8bbee4 100644 (file)
@@ -69,7 +69,7 @@ struct host_definition_s
   int version;
   void *sess_handle;
   c_complain_t complaint;
-  uint32_t interval;
+  cdtime_t interval;
   data_definition_t **data_list;
   int data_list_len;
 };
@@ -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,
@@ -207,7 +207,6 @@ static void csnmp_host_definition_destroy (void *arg) /* {{{ */
  *      +-> csnmp_config_add_host_community
  *      +-> csnmp_config_add_host_version
  *      +-> csnmp_config_add_host_collect
- *      +-> csnmp_config_add_host_interval
  */
 static void call_snmp_init_once (void)
 {
@@ -591,22 +590,6 @@ static int csnmp_config_add_host_collect (host_definition_t *host,
   return (0);
 } /* int csnmp_config_add_host_collect */
 
-static int csnmp_config_add_host_interval (host_definition_t *hd, oconfig_item_t *ci)
-{
-  if ((ci->values_num != 1)
-      || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
-  {
-    WARNING ("snmp plugin: The `Interval' config option needs exactly one number argument.");
-    return (-1);
-  }
-
-  hd->interval = ci->values[0].value.number >= 0
-    ? (uint32_t) ci->values[0].value.number
-    : 0;
-
-  return (0);
-} /* int csnmp_config_add_host_interval */
-
 static int csnmp_config_add_host (oconfig_item_t *ci)
 {
   host_definition_t *hd;
@@ -655,7 +638,7 @@ static int csnmp_config_add_host (oconfig_item_t *ci)
     else if (strcasecmp ("Collect", option->key) == 0)
       csnmp_config_add_host_collect (hd, option);
     else if (strcasecmp ("Interval", option->key) == 0)
-      csnmp_config_add_host_interval (hd, option);
+      cf_util_get_cdtime (option, &hd->interval);
     else
     {
       WARNING ("snmp plugin: csnmp_config_add_host: Option `%s' not allowed here.", option->key);
@@ -699,9 +682,7 @@ static int csnmp_config_add_host (oconfig_item_t *ci)
   cb_data.data = hd;
   cb_data.free_func = csnmp_host_definition_destroy;
 
-  memset (&cb_interval, 0, sizeof (cb_interval));
-  if (hd->interval != 0)
-    cb_interval.tv_sec = (time_t) hd->interval;
+  CDTIME_T_TO_TIMESPEC (hd->interval, &cb_interval);
 
   status = plugin_register_complex_read (/* group = */ NULL, cb_name,
       csnmp_read_host, /* interval = */ &cb_interval,
@@ -1050,6 +1031,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 +1049,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 +1117,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 +1146,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 +1157,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 +1188,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 +1239,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);
@@ -1423,16 +1424,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 +1442,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 +1459,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)
@@ -1627,8 +1629,8 @@ static int csnmp_read_value (host_definition_t *host, data_definition_t *data)
 static int csnmp_read_host (user_data_t *ud)
 {
   host_definition_t *host;
-  time_t time_start;
-  time_t time_end;
+  cdtime_t time_start;
+  cdtime_t time_end;
   int status;
   int success;
   int i;
@@ -1638,9 +1640,7 @@ static int csnmp_read_host (user_data_t *ud)
   if (host->interval == 0)
     host->interval = interval_g;
 
-  time_start = time (NULL);
-  DEBUG ("snmp plugin: csnmp_read_host (%s) started at %u;", host->name,
-      (unsigned int) time_start);
+  time_start = cdtime ();
 
   if (host->sess_handle == NULL)
     csnmp_host_open_session (host);
@@ -1662,14 +1662,14 @@ static int csnmp_read_host (user_data_t *ud)
       success++;
   }
 
-  time_end = time (NULL);
-  DEBUG ("snmp plugin: csnmp_read_host (%s) finished at %u;", host->name,
-      (unsigned int) time_end);
-  if ((uint32_t) (time_end - time_start) > host->interval)
+  time_end = cdtime ();
+  if ((time_end - time_start) > host->interval)
   {
-    WARNING ("snmp plugin: Host `%s' should be queried every %"PRIu32
-        " seconds, but reading all values takes %u seconds.",
-        host->name, host->interval, (unsigned int) (time_end - time_start));
+    WARNING ("snmp plugin: Host `%s' should be queried every %.3f "
+       "seconds, but reading all values takes %.3f seconds.",
+       host->name,
+       CDTIME_T_TO_DOUBLE (host->interval),
+       CDTIME_T_TO_DOUBLE (time_end - time_start));
   }
 
   if (success == 0)