0dcae61b6aa8ccf1191cd0f7f0ab41cc68d9942e
[oweals/gnunet.git] / src / sensor / gnunet-service-sensor-analysis.c
1 /*
2      This file is part of GNUnet.
3      (C)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file sensor/gnunet-service-sensor-analysis.c
23  * @brief sensor service analysis functionality
24  * @author Omar Tarabai
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "sensor.h"
29 #include "gnunet_peerstore_service.h"
30 #include "gnunet_sensor_model_plugin.h"
31
32 #define LOG(kind,...) GNUNET_log_from (kind, "sensor-analysis",__VA_ARGS__)
33
34 /*
35  * Carries information about the analysis model
36  * corresponding to one sensor
37  */
38 struct SensorModel
39 {
40
41   /*
42    * DLL
43    */
44   struct SensorModel *prev;
45
46   /*
47    * DLL
48    */
49   struct SensorModel *next;
50
51   /*
52    * Pointer to sensor info structure
53    */
54   struct SensorInfo *sensor;
55
56   /*
57    * Watcher of sensor values
58    */
59   struct GNUNET_PEERSTORE_WatchContext *wc;
60
61   /*
62    * Closure for model plugin
63    */
64   void *cls;
65
66 };
67
68 /**
69  * Our configuration.
70  */
71 static const struct GNUNET_CONFIGURATION_Handle *cfg;
72
73 /*
74  * Model library name
75  */
76 static char *model_lib_name;
77
78 /*
79  * Model handle
80  */
81 static struct GNUNET_SENSOR_ModelFunctions *model_api;
82
83 /*
84  * Handle to peerstore service
85  */
86 static struct GNUNET_PEERSTORE_Handle *peerstore;
87
88 /*
89  * Head of DLL of created models
90  */
91 static struct SensorModel *models_head;
92
93 /*
94  * Tail of DLL of created models
95  */
96 static struct SensorModel *models_tail;
97
98 /**
99  * My peer id
100  */
101 struct GNUNET_PeerIdentity peerid;
102
103 /*
104  * Destroy a created model
105  */
106 static void
107 destroy_sensor_model (struct SensorModel *sensor_model)
108 {
109   GNUNET_assert (NULL != sensor_model);
110   LOG (GNUNET_ERROR_TYPE_DEBUG,
111         "Destroying sensor model for `%s'.\n",
112         sensor_model->sensor->name);
113   if (NULL != sensor_model->wc)
114   {
115     GNUNET_PEERSTORE_watch_cancel(sensor_model->wc);
116     sensor_model->wc = NULL;
117   }
118   if (NULL != sensor_model->cls)
119   {
120     model_api->destroy_model (sensor_model->cls);
121     sensor_model->cls = NULL;
122   }
123   GNUNET_free(sensor_model);
124   sensor_model = NULL;
125 }
126
127 /*
128  * Stop the sensor analysis module
129  */
130 void SENSOR_analysis_stop()
131 {
132   struct SensorModel *sm;
133
134   LOG (GNUNET_ERROR_TYPE_DEBUG, "Stopping sensor analysis module.\n");
135   while (NULL != models_head)
136   {
137     sm = models_head;
138     GNUNET_CONTAINER_DLL_remove(models_head, models_tail, sm);
139     destroy_sensor_model(sm);
140   }
141   if (NULL != peerstore)
142   {
143     GNUNET_PEERSTORE_disconnect(peerstore);
144     peerstore = NULL;
145   }
146   if (NULL != model_api)
147   {
148     GNUNET_break (NULL == GNUNET_PLUGIN_unload (model_lib_name, model_api));
149     GNUNET_free (model_lib_name);
150     model_lib_name = NULL;
151   }
152 }
153
154 /*
155  * Sensor value watch callback
156  */
157 static int
158 sensor_watcher (void *cls,
159     struct GNUNET_PEERSTORE_Record *record,
160     char *emsg)
161 {
162   struct SensorModel *sensor_model = cls;
163   double *val;
164   int anomalous;
165
166   LOG (GNUNET_ERROR_TYPE_DEBUG,
167       "Received a sensor value, will feed to sensor model.\n");
168   if (sizeof(double) != record->value_size)
169   {
170     LOG (GNUNET_ERROR_TYPE_ERROR,
171         _("Received an invalid sensor value."));
172     return GNUNET_YES;
173   }
174   val = (double *)(record->value);
175   anomalous = model_api->feed_model (sensor_model->cls, *val);
176   if (GNUNET_YES == anomalous)
177   {
178     LOG (GNUNET_ERROR_TYPE_WARNING,
179         "Anomaly detected, value: %f.\n",
180         *val);
181   }
182   else
183     LOG (GNUNET_ERROR_TYPE_DEBUG, "Value non-anomalous.\n");
184   return GNUNET_YES;
185 }
186
187 /*
188  * Iterator for defined sensors
189  * Creates sensor model for numeric sensors
190  *
191  * @param cls unused
192  * @param key unused
193  * @param value a 'struct SensorInfo *' with sensor information
194  * @return #GNUNET_YES to continue iterations
195  */
196 static int
197 init_sensor_model (void *cls,
198     const struct GNUNET_HashCode *key,
199     void *value)
200 {
201   struct SensorInfo *sensor = value;
202   struct SensorModel *sensor_model;
203
204   if (0 != strcmp("numeric", sensor->expected_datatype))
205     return GNUNET_YES;
206   sensor_model = GNUNET_new(struct SensorModel);
207   sensor_model->sensor = sensor;
208   sensor_model->wc = GNUNET_PEERSTORE_watch(peerstore,
209           "sensor", &peerid, sensor->name,
210           &sensor_watcher, sensor_model);
211   sensor_model->cls = model_api->create_model(model_api->cls);
212   GNUNET_CONTAINER_DLL_insert(models_head, models_tail, sensor_model);
213   LOG (GNUNET_ERROR_TYPE_DEBUG,
214       "Created sensor model for `%s'.\n", sensor->name);
215   return GNUNET_YES;
216 }
217
218 /*
219  * Start the sensor analysis module
220  *
221  * @param c our service configuration
222  * @param sensors multihashmap of loaded sensors
223  * @return #GNUNET_OK if started successfully, #GNUNET_SYSERR otherwise
224  */
225 int
226 SENSOR_analysis_start(const struct GNUNET_CONFIGURATION_Handle *c,
227     struct GNUNET_CONTAINER_MultiHashMap *sensors)
228 {
229   char *model_name;
230
231   GNUNET_assert(NULL != sensors);
232   cfg = c;
233   if (GNUNET_OK !=
234       GNUNET_CONFIGURATION_get_value_string (cfg, "sensor-analysis", "MODEL",
235                                                  &model_name))
236   {
237     LOG (GNUNET_ERROR_TYPE_ERROR, _("Analysis model not defined in configuration.\n"));
238     return GNUNET_SYSERR;
239   }
240   GNUNET_asprintf (&model_lib_name, "libgnunet_plugin_sensor_model_%s", model_name);
241   model_api = GNUNET_PLUGIN_load(model_lib_name, (void *) cfg);
242   GNUNET_free(model_name);
243   if(NULL == model_api)
244   {
245     LOG (GNUNET_ERROR_TYPE_ERROR, _("Could not load analysis model `%s'.\n"), model_lib_name);
246     return GNUNET_SYSERR;
247   }
248   peerstore = GNUNET_PEERSTORE_connect(cfg);
249   if (NULL == peerstore)
250   {
251     LOG (GNUNET_ERROR_TYPE_ERROR, _("Could not connect to peerstore service.\n"));
252     SENSOR_analysis_stop();
253     return GNUNET_SYSERR;
254   }
255   GNUNET_CRYPTO_get_peer_identity(cfg, &peerid);
256   GNUNET_CONTAINER_multihashmap_iterate(sensors, &init_sensor_model, NULL);
257
258   return GNUNET_OK;
259 }
260
261 /* end of gnunet-service-sensor-analysis.c */