logging more verbose
[oweals/gnunet.git] / src / sensor / gnunet-service-sensor-analysis.c
index 8ab4860945aadc54ead62f47649b7f175af6f0f2..f6beacf695312476402ca211ae552efb08005aac 100644 (file)
@@ -27,6 +27,7 @@
 #include "gnunet_util_lib.h"
 #include "sensor.h"
 #include "gnunet_peerstore_service.h"
+#include "gnunet_sensor_model_plugin.h"
 
 #define LOG(kind,...) GNUNET_log_from (kind, "sensor-analysis",__VA_ARGS__)
 
 struct SensorModel
 {
 
+  /*
+   * DLL
+   */
+  struct SensorModel *prev;
+
+  /*
+   * DLL
+   */
+  struct SensorModel *next;
+
   /*
    * Pointer to sensor info structure
    */
@@ -47,6 +58,11 @@ struct SensorModel
    */
   struct GNUNET_PEERSTORE_WatchContext *wc;
 
+  /*
+   * Closure for model plugin
+   */
+  void *cls;
+
 };
 
 /**
@@ -62,12 +78,7 @@ static char *model_lib_name;
 /*
  * Model handle
  */
-static struct GNUNET_SENSOR_ModelFunctions *model;
-
-/**
- * Hashmap of loaded sensor definitions
- */
-static struct GNUNET_CONTAINER_MultiHashMap *sensors;
+static struct GNUNET_SENSOR_ModelFunctions *model_api;
 
 /*
  * Handle to peerstore service
@@ -75,54 +86,112 @@ static struct GNUNET_CONTAINER_MultiHashMap *sensors;
 static struct GNUNET_PEERSTORE_Handle *peerstore;
 
 /*
- * Datatypes supported by the analysis component
+ * Head of DLL of created models
  */
-static const char *analysis_datatypes[] = { "uint64", "double", NULL };
+static struct SensorModel *models_head;
 
 /*
- * MultiHashmap of all sensor models
+ * Tail of DLL of created models
+ */
+static struct SensorModel *models_tail;
+
+/**
+ * My peer id
  */
-static struct GNUNET_CONTAINER_MultiHashMap *sensor_models;
+struct GNUNET_PeerIdentity peerid;
+
+/*
+ * Destroy a created model
+ */
+static void
+destroy_sensor_model (struct SensorModel *sensor_model)
+{
+  GNUNET_assert (NULL != sensor_model);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+        "Destroying sensor model for `%s'.\n",
+        sensor_model->sensor->name);
+  if (NULL != sensor_model->wc)
+  {
+    GNUNET_PEERSTORE_watch_cancel(sensor_model->wc);
+    sensor_model->wc = NULL;
+  }
+  if (NULL != sensor_model->cls)
+  {
+    model_api->destroy_model (sensor_model->cls);
+    sensor_model->cls = NULL;
+  }
+  GNUNET_free(sensor_model);
+  sensor_model = NULL;
+}
 
 /*
- * TODO: document
+ * Stop the sensor analysis module
  */
 void SENSOR_analysis_stop()
 {
-  if (NULL != model)
+  struct SensorModel *sm;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "Stopping sensor analysis module.\n");
+  while (NULL != models_head)
   {
-    GNUNET_break (NULL == GNUNET_PLUGIN_unload (model_lib_name, model));
-    GNUNET_free (model_lib_name);
-    model_lib_name = NULL;
+    sm = models_head;
+    GNUNET_CONTAINER_DLL_remove(models_head, models_tail, sm);
+    destroy_sensor_model(sm);
   }
   if (NULL != peerstore)
   {
     GNUNET_PEERSTORE_disconnect(peerstore);
     peerstore = NULL;
   }
-  if (NULL != sensor_models)
+  if (NULL != model_api)
   {
-    /* TODO: iterate over sensor models and destroy */
-    GNUNET_CONTAINER_multihashmap_destroy(sensor_models);
-    sensor_models = NULL;
+    GNUNET_break (NULL == GNUNET_PLUGIN_unload (model_lib_name, model_api));
+    GNUNET_free (model_lib_name);
+    model_lib_name = NULL;
   }
 }
 
 /*
- * TODO: document
+ * Sensor value watch callback
  */
 static int
 sensor_watcher (void *cls,
     struct GNUNET_PEERSTORE_Record *record,
     char *emsg)
 {
+  struct SensorModel *sensor_model = cls;
+  double *val;
+  int anomalous;
+
   LOG (GNUNET_ERROR_TYPE_DEBUG,
       "Received a sensor value, will feed to sensor model.\n");
+  if (sizeof(double) != record->value_size)
+  {
+    LOG (GNUNET_ERROR_TYPE_ERROR,
+        _("Received an invalid sensor value."));
+    return GNUNET_YES;
+  }
+  val = (double *)(record->value);
+  anomalous = model_api->feed_model (sensor_model->cls, *val);
+  if (GNUNET_YES == anomalous)
+  {
+    LOG (GNUNET_ERROR_TYPE_WARNING,
+        "Anomaly detected in sensor `%s', value: %f.\n",
+        sensor_model->sensor->name, *val);
+  }
+  else
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "Value non-anomalous.\n");
   return GNUNET_YES;
 }
 
 /*
- * TODO: document
+ * Iterator for defined sensors
+ * Creates sensor model for numeric sensors
+ *
+ * @param cls unused
+ * @param key unused
+ * @param value a 'struct SensorInfo *' with sensor information
+ * @return #GNUNET_YES to continue iterations
  */
 static int
 init_sensor_model (void *cls,
@@ -131,40 +200,35 @@ init_sensor_model (void *cls,
 {
   struct SensorInfo *sensor = value;
   struct SensorModel *sensor_model;
-  int is_numeric;
-  int i;
 
-  is_numeric = GNUNET_NO;
-  for (i = 0; NULL != analysis_datatypes[i]; i++)
-  {
-    if (0 == strcasecmp (analysis_datatypes[i], sensor->expected_datatype))
-    {
-      is_numeric = GNUNET_YES;
-      break;
-    }
-  }
-  if (GNUNET_NO == is_numeric)
+  if (0 != strcmp("numeric", sensor->expected_datatype))
     return GNUNET_YES;
   sensor_model = GNUNET_new(struct SensorModel);
+  sensor_model->sensor = sensor;
   sensor_model->wc = GNUNET_PEERSTORE_watch(peerstore,
-          "sensor", NULL, sensor->name,
+          "sensor", &peerid, sensor->name,
           &sensor_watcher, sensor_model);
-  GNUNET_CONTAINER_multihashmap_put(sensor_models, key,
-      sensor_model, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
+  sensor_model->cls = model_api->create_model(model_api->cls);
+  GNUNET_CONTAINER_DLL_insert(models_head, models_tail, sensor_model);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+      "Created sensor model for `%s'.\n", sensor->name);
   return GNUNET_YES;
 }
 
 /*
- * TODO: document
+ * Start the sensor analysis module
  *
+ * @param c our service configuration
+ * @param sensors multihashmap of loaded sensors
  * @return #GNUNET_OK if started successfully, #GNUNET_SYSERR otherwise
  */
 int
 SENSOR_analysis_start(const struct GNUNET_CONFIGURATION_Handle *c,
-    struct GNUNET_CONTAINER_MultiHashMap *sensors_mhm)
+    struct GNUNET_CONTAINER_MultiHashMap *sensors)
 {
   char *model_name;
 
+  GNUNET_assert(NULL != sensors);
   cfg = c;
   if (GNUNET_OK !=
       GNUNET_CONFIGURATION_get_value_string (cfg, "sensor-analysis", "MODEL",
@@ -174,20 +238,13 @@ SENSOR_analysis_start(const struct GNUNET_CONFIGURATION_Handle *c,
     return GNUNET_SYSERR;
   }
   GNUNET_asprintf (&model_lib_name, "libgnunet_plugin_sensor_model_%s", model_name);
-  model = GNUNET_PLUGIN_load(model_lib_name, (void *) cfg);
+  model_api = GNUNET_PLUGIN_load(model_lib_name, (void *) cfg);
   GNUNET_free(model_name);
-  if(NULL == model)
+  if(NULL == model_api)
   {
     LOG (GNUNET_ERROR_TYPE_ERROR, _("Could not load analysis model `%s'.\n"), model_lib_name);
     return GNUNET_SYSERR;
   }
-  sensors = sensors_mhm;
-  if (NULL == sensors)
-  {
-    LOG (GNUNET_ERROR_TYPE_ERROR, _("Tried to start analysis before loading sensors.\n"));
-    SENSOR_analysis_stop();
-    return GNUNET_SYSERR;
-  }
   peerstore = GNUNET_PEERSTORE_connect(cfg);
   if (NULL == peerstore)
   {
@@ -195,7 +252,7 @@ SENSOR_analysis_start(const struct GNUNET_CONFIGURATION_Handle *c,
     SENSOR_analysis_stop();
     return GNUNET_SYSERR;
   }
-  sensor_models = GNUNET_CONTAINER_multihashmap_create(10, GNUNET_NO);
+  GNUNET_CRYPTO_get_peer_identity(cfg, &peerid);
   GNUNET_CONTAINER_multihashmap_iterate(sensors, &init_sensor_model, NULL);
 
   return GNUNET_OK;