sensor: force fake anomaly
[oweals/gnunet.git] / src / sensor / sensor_api.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/sensor_api.c
23  * @brief API for sensor service
24  * @author Omar Tarabai
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "sensor.h"
29
30 #define LOG(kind,...) GNUNET_log_from (kind, "sensor-api",__VA_ARGS__)
31
32 /**
33  * Handle to the sensor service.
34  */
35 struct GNUNET_SENSOR_Handle
36 {
37
38   /**
39    * Our configuration.
40    */
41   const struct GNUNET_CONFIGURATION_Handle *cfg;
42
43   /**
44    * Connection to the service.
45    */
46   struct GNUNET_CLIENT_Connection *client;
47
48   /**
49    * Head of iterator DLL.
50    */
51   struct GNUNET_SENSOR_IterateContext *ic_head;
52
53   /**
54    * Tail of iterator DLL.
55    */
56   struct GNUNET_SENSOR_IterateContext *ic_tail;
57
58   /**
59    * Message queue used to send data to service
60    */
61   struct GNUNET_MQ_Handle *mq;
62
63 };
64
65 /**
66  * Context for an iteration request.
67  */
68 struct GNUNET_SENSOR_IterateContext
69 {
70
71   /**
72    * Kept in a DLL.
73    */
74   struct GNUNET_SENSOR_IterateContext *next;
75
76   /**
77    * Kept in a DLL.
78    */
79   struct GNUNET_SENSOR_IterateContext *prev;
80
81   /**
82    * Handle to the SENSOR service.
83    */
84   struct GNUNET_SENSOR_Handle *h;
85
86   /**
87    * Function to call with the results.
88    */
89   GNUNET_SENSOR_SensorIterateCB callback;
90
91   /**
92    * Closure for 'callback'.
93    */
94   void *callback_cls;
95
96   /**
97    * Envelope containing iterate request.
98    */
99   struct GNUNET_MQ_Envelope *ev;
100
101   /**
102    * Is the request already sent? If yes, cannot be canceled.
103    */
104   int request_sent;
105
106   /**
107    * Are we expecting records from service?
108    */
109   int receiving;
110
111   /**
112    * Task responsible for timeout.
113    */
114   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
115
116 };
117
118
119 /**
120  * Notifier of an error encountered by MQ.
121  *
122  * @param cls Closure, service handle
123  * @param error MQ error type
124  */
125 static void
126 mq_error_handler (void *cls, enum GNUNET_MQ_Error error)
127 {
128   struct GNUNET_SENSOR_Handle *h = cls;
129
130   LOG (GNUNET_ERROR_TYPE_ERROR,
131        _("Received an error notification from MQ of type: %d\n"), error);
132   GNUNET_SENSOR_disconnect (h); //TODO: try to reconnect
133 }
134
135
136 /**
137  * Handler to a message of type: #GNUNET_MESSAGE_TYPE_SENSOR_END
138  *
139  * @param cls Closure, service handle
140  * @param msg Message received
141  */
142 static void
143 handle_end (void *cls, const struct GNUNET_MessageHeader *msg)
144 {
145   struct GNUNET_SENSOR_Handle *h = cls;
146   struct GNUNET_SENSOR_IterateContext *ic;
147   GNUNET_SENSOR_SensorIterateCB cb;
148   void *cb_cls;
149
150   if (NULL == h->ic_head)
151   {
152     GNUNET_break_op (0);
153     //TODO: reconnect
154     return;
155   }
156   ic = h->ic_head;
157   cb = ic->callback;
158   cb_cls = ic->callback_cls;
159   ic->receiving = GNUNET_NO;
160   GNUNET_SENSOR_iterate_cancel (ic);
161   if (NULL != cb)
162     cb (cb_cls, NULL, NULL);
163 }
164
165
166 /**
167  * Handler to a message of type: #GNUNET_MESSAGE_TYPE_SENSOR_INFO
168  *
169  * @param cls Closure, service handle
170  * @param msg Message received
171  */
172 static void
173 handle_sensor_info (void *cls, const struct GNUNET_MessageHeader *msg)
174 {
175   struct GNUNET_SENSOR_Handle *h = cls;
176   struct GNUNET_SENSOR_IterateContext *ic;
177   uint16_t msg_size;
178   struct SensorInfoMessage *sensor_msg;
179   uint16_t sensor_name_len;
180   uint16_t sensor_desc_len;
181   struct SensorInfoShort *sensor;
182   void *dummy;
183
184   if (NULL == h->ic_head)
185   {
186     GNUNET_break_op (0);
187     //TODO: reconnect
188     return;
189   }
190   ic = h->ic_head;
191   if (NULL == ic->callback)     /* no need to parse message */
192     return;
193   msg_size = ntohs (msg->size);
194   if (msg_size < sizeof (struct SensorInfoMessage))
195   {
196     GNUNET_break_op (0);
197     //TODO: reconnect
198     return;
199   }
200   sensor_msg = (struct SensorInfoMessage *) msg;
201   sensor_name_len = ntohs (sensor_msg->name_len);
202   sensor_desc_len = ntohs (sensor_msg->description_len);
203   if (msg_size !=
204       sizeof (struct SensorInfoMessage) + sensor_name_len + sensor_desc_len)
205   {
206     GNUNET_break_op (0);
207     //TODO: reconnect
208     return;
209   }
210   sensor = GNUNET_new (struct SensorInfoShort);
211   sensor->version_major = ntohs (sensor_msg->version_major);
212   sensor->version_minor = ntohs (sensor_msg->version_minor);
213   dummy = &sensor_msg[1];
214   sensor->name = GNUNET_strndup (dummy, sensor_name_len);
215   dummy += sensor_name_len;
216   sensor->description = GNUNET_strndup (dummy, sensor_desc_len);
217   ic->callback (ic->callback_cls, sensor, NULL);
218   GNUNET_free (sensor->name);
219   GNUNET_free (sensor->description);
220   GNUNET_free (sensor);
221 }
222
223
224 /**
225  * Disconnect from the sensor service
226  *
227  * @param h handle to disconnect
228  */
229 void
230 GNUNET_SENSOR_disconnect (struct GNUNET_SENSOR_Handle *h)
231 {
232   struct GNUNET_SENSOR_IterateContext *ic;
233
234   ic = h->ic_head;
235   while (NULL != ic)
236   {
237     if (NULL != ic->callback)
238       ic->callback (ic->callback_cls, NULL,
239                     _("Iterate request canceled due to disconnection.\n"));
240     GNUNET_SENSOR_iterate_cancel (ic);
241     ic = h->ic_head;
242   }
243   if (NULL != h->mq)
244   {
245     GNUNET_MQ_destroy (h->mq);
246     h->mq = NULL;
247   }
248   if (NULL != h->client)
249   {
250     GNUNET_CLIENT_disconnect (h->client);
251     h->client = NULL;
252   }
253   GNUNET_free (h);
254 }
255
256
257 /**
258  * Connect to the sensor service.
259  *
260  * @return NULL on error
261  */
262 struct GNUNET_SENSOR_Handle *
263 GNUNET_SENSOR_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
264 {
265   struct GNUNET_CLIENT_Connection *client;
266   struct GNUNET_SENSOR_Handle *h;
267
268   static const struct GNUNET_MQ_MessageHandler mq_handlers[] = {
269     {&handle_sensor_info, GNUNET_MESSAGE_TYPE_SENSOR_INFO, 0},
270     {&handle_end, GNUNET_MESSAGE_TYPE_SENSOR_END, 0},
271     GNUNET_MQ_HANDLERS_END
272   };
273
274   client = GNUNET_CLIENT_connect ("sensor", cfg);
275   if (NULL == client)
276     return NULL;
277   h = GNUNET_new (struct GNUNET_SENSOR_Handle);
278   h->client = client;
279   h->cfg = cfg;
280   h->mq =
281       GNUNET_MQ_queue_for_connection_client (h->client, mq_handlers,
282                                              &mq_error_handler, h);
283   return h;
284 }
285
286
287 /**
288  * Iteration request has timed out.
289  *
290  * @param cls the 'struct GNUNET_SENSOR_SensorIteratorContext*'
291  * @param tc scheduler context
292  */
293 static void
294 signal_sensor_iteration_timeout (void *cls,
295                                  const struct GNUNET_SCHEDULER_TaskContext *tc)
296 {
297   struct GNUNET_SENSOR_IterateContext *ic = cls;
298   GNUNET_SENSOR_SensorIterateCB cb;
299   void *cb_cls;
300
301   ic->timeout_task = GNUNET_SCHEDULER_NO_TASK;
302   cb = ic->callback;
303   cb_cls = ic->callback_cls;
304   GNUNET_SENSOR_iterate_cancel (ic);
305   if (NULL != cb)
306     cb (cb_cls, NULL,
307         _("Timeout transmitting iteration request to `SENSOR' service."));
308 }
309
310
311 /**
312  * Callback from MQ when the request has already been sent to the service.
313  * Now it can not be canelled.
314  *
315  * @param cls closure
316  */
317 static void
318 iterate_request_sent (void *cls)
319 {
320   struct GNUNET_SENSOR_IterateContext *ic = cls;
321
322   ic->request_sent = GNUNET_YES;
323   ic->ev = NULL;
324   ic->receiving = GNUNET_YES;
325 }
326
327
328 /**
329  * Cancel an iteration request.
330  * This should be called before the iterate callback is called with a NULL value.
331  *
332  * @param ic context of the iterator to cancel
333  */
334 void
335 GNUNET_SENSOR_iterate_cancel (struct GNUNET_SENSOR_IterateContext *ic)
336 {
337   struct GNUNET_SENSOR_Handle *h;
338
339   h = ic->h;
340   if (GNUNET_NO == ic->request_sent)
341   {
342     GNUNET_MQ_send_cancel (ic->ev);
343     ic->ev = NULL;
344     ic->request_sent = GNUNET_YES;
345   }
346   if (GNUNET_YES == ic->receiving)
347   {
348     /* don't remove since we are still expecting records */
349     ic->callback = NULL;
350     ic->callback_cls = NULL;
351     return;
352   }
353   if (GNUNET_SCHEDULER_NO_TASK != ic->timeout_task)
354   {
355     GNUNET_SCHEDULER_cancel (ic->timeout_task);
356     ic->timeout_task = GNUNET_SCHEDULER_NO_TASK;
357   }
358   GNUNET_CONTAINER_DLL_remove (h->ic_head, h->ic_tail, ic);
359   GNUNET_free (ic);
360 }
361
362
363 /**
364  * Get one or all sensors loaded by the sensor service.
365  * The callback will be called with each sensor received and once with a NULL
366  * value to signal end of iteration.
367  *
368  * @param h Handle to SENSOR service
369  * @param timeout how long to wait until timing out
370  * @param sensorname Name of the required sensor, NULL to get all
371  * @param callback the function to call for each sensor
372  * @param callback_cls closure for callback
373  * @return iterator context
374  */
375 struct GNUNET_SENSOR_IterateContext *
376 GNUNET_SENSOR_iterate (struct GNUNET_SENSOR_Handle *h,
377                        struct GNUNET_TIME_Relative timeout,
378                        const char *sensor_name,
379                        GNUNET_SENSOR_SensorIterateCB callback,
380                        void *callback_cls)
381 {
382   struct GNUNET_SENSOR_IterateContext *ic;
383   struct GNUNET_MessageHeader *msg;
384   struct GNUNET_MQ_Envelope *ev;
385   size_t sensor_name_len;
386
387   if (NULL == sensor_name)
388   {
389     ev = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SENSOR_GETALL);
390   }
391   else
392   {
393     sensor_name_len = strlen (sensor_name) + 1;
394     ev = GNUNET_MQ_msg_extra (msg, sensor_name_len,
395                               GNUNET_MESSAGE_TYPE_SENSOR_GET);
396     memcpy (&msg[1], sensor_name, sensor_name_len);
397   }
398   GNUNET_MQ_send (h->mq, ev);
399   ic = GNUNET_new (struct GNUNET_SENSOR_IterateContext);
400
401   ic->h = h;
402   ic->ev = ev;
403   ic->request_sent = GNUNET_NO;
404   ic->receiving = GNUNET_NO;
405   ic->callback = callback;
406   ic->callback_cls = callback_cls;
407   ic->timeout_task =
408       GNUNET_SCHEDULER_add_delayed (timeout, &signal_sensor_iteration_timeout,
409                                     ic);
410   GNUNET_MQ_notify_sent (ev, &iterate_request_sent, ic);
411   GNUNET_CONTAINER_DLL_insert_tail (h->ic_head, h->ic_tail, ic);
412   return ic;
413 }
414
415
416 /**
417  * Force an anomaly status change on a given sensor. If the sensor reporting
418  * module is running, this will trigger the usual reporting logic, therefore,
419  * please only use this in a test environment.
420  *
421  * Also, if the sensor analysis module is running, it might conflict and cause
422  * undefined behaviour if it detects a real anomaly.
423  *
424  * @param h Service handle
425  * @param sensor_name Sensor name to set the anomaly status
426  * @param anomalous The desired status: #GNUNET_YES / #GNUNET_NO
427  */
428 void
429 GNUNET_SENSOR_force_anomaly (struct GNUNET_SENSOR_Handle *h, char *sensor_name,
430                              int anomalous)
431 {
432   struct ForceAnomalyMessage *msg;
433   struct GNUNET_MQ_Envelope *ev;
434
435   ev = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SENSOR_ANOMALY_FORCE);
436   GNUNET_CRYPTO_hash (sensor_name, strlen (sensor_name) + 1,
437                       &msg->sensor_name_hash);
438   msg->anomalous = htons (anomalous);
439   GNUNET_MQ_send (h->mq, ev);
440 }
441
442
443 /* end of sensor_api.c */