/* This file is part of GNUnet. (C) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file sensor/gnunet-service-sensor-analysis.c * @brief sensor service analysis functionality * @author Omar Tarabai */ #include "platform.h" #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__) /* * Carries information about the analysis model * corresponding to one sensor */ struct SensorModel { /* * DLL */ struct SensorModel *prev; /* * DLL */ struct SensorModel *next; /* * Pointer to sensor info structure */ struct SensorInfo *sensor; /* * Watcher of sensor values */ struct GNUNET_PEERSTORE_WatchContext *wc; /* * Closure for model plugin */ void *cls; }; /** * Our configuration. */ static const struct GNUNET_CONFIGURATION_Handle *cfg; /* * Model library name */ static char *model_lib_name; /* * Model handle */ static struct GNUNET_SENSOR_ModelFunctions *model_api; /* * Handle to peerstore service */ static struct GNUNET_PEERSTORE_Handle *peerstore; /* * Head of DLL of created models */ static struct SensorModel *models_head; /* * Tail of DLL of created models */ static struct SensorModel *models_tail; /** * My peer id */ 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; } /* * Stop the sensor analysis module */ void SENSOR_analysis_stop() { struct SensorModel *sm; LOG (GNUNET_ERROR_TYPE_DEBUG, "Stopping sensor analysis module.\n"); while (NULL != models_head) { sm = models_head; GNUNET_CONTAINER_DLL_remove(models_head, models_tail, sm); destroy_sensor_model(sm); } if (NULL != peerstore) { GNUNET_PEERSTORE_disconnect(peerstore, GNUNET_YES); peerstore = NULL; } if (NULL != model_api) { GNUNET_break (NULL == GNUNET_PLUGIN_unload (model_lib_name, model_api)); GNUNET_free (model_lib_name); model_lib_name = NULL; } } /* * 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; } /* * 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, const struct GNUNET_HashCode *key, void *value) { struct SensorInfo *sensor = value; struct SensorModel *sensor_model; 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", &peerid, sensor->name, &sensor_watcher, sensor_model); 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; } /* * 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) { char *model_name; GNUNET_assert(NULL != sensors); cfg = c; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "sensor-analysis", "MODEL", &model_name)) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Analysis model not defined in configuration.\n")); return GNUNET_SYSERR; } GNUNET_asprintf (&model_lib_name, "libgnunet_plugin_sensor_model_%s", model_name); model_api = GNUNET_PLUGIN_load(model_lib_name, (void *) cfg); GNUNET_free(model_name); if(NULL == model_api) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Could not load analysis model `%s'.\n"), model_lib_name); return GNUNET_SYSERR; } peerstore = GNUNET_PEERSTORE_connect(cfg); if (NULL == peerstore) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Could not connect to peerstore service.\n")); SENSOR_analysis_stop(); return GNUNET_SYSERR; } GNUNET_CRYPTO_get_peer_identity(cfg, &peerid); GNUNET_CONTAINER_multihashmap_iterate(sensors, &init_sensor_model, NULL); return GNUNET_OK; } /* end of gnunet-service-sensor-analysis.c */