-fix ftbfs
[oweals/gnunet.git] / src / sensor / sensor_api.c
1 /*
2      This file is part of GNUnet.
3      Copyright (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 iteration requests DLL.
50    */
51   struct GNUNET_SENSOR_IterateContext *ic_head;
52
53   /**
54    * Tail of iteration requests DLL.
55    */
56   struct GNUNET_SENSOR_IterateContext *ic_tail;
57
58   /**
59    * Head of force anomaly requests
60    */
61   struct GNUNET_SENSOR_ForceAnomalyContext *fa_head;
62
63   /**
64    * Tail of force anomaly requests
65    */
66   struct GNUNET_SENSOR_ForceAnomalyContext *fa_tail;
67
68   /**
69    * Message queue used to send data to service
70    */
71   struct GNUNET_MQ_Handle *mq;
72
73 };
74
75 /**
76  * Context for an iteration request.
77  */
78 struct GNUNET_SENSOR_IterateContext
79 {
80
81   /**
82    * Kept in a DLL.
83    */
84   struct GNUNET_SENSOR_IterateContext *next;
85
86   /**
87    * Kept in a DLL.
88    */
89   struct GNUNET_SENSOR_IterateContext *prev;
90
91   /**
92    * Handle to the SENSOR service.
93    */
94   struct GNUNET_SENSOR_Handle *h;
95
96   /**
97    * Function to call with the results.
98    */
99   GNUNET_SENSOR_SensorIterateCB callback;
100
101   /**
102    * Closure for 'callback'.
103    */
104   void *callback_cls;
105
106   /**
107    * Envelope containing iterate request.
108    */
109   struct GNUNET_MQ_Envelope *ev;
110
111   /**
112    * Is the request already sent? If yes, cannot be canceled.
113    */
114   int request_sent;
115
116   /**
117    * Are we expecting records from service?
118    */
119   int receiving;
120
121   /**
122    * Task responsible for timeout.
123    */
124   struct GNUNET_SCHEDULER_Task * timeout_task;
125
126 };
127
128 /**
129  * Context of a force anomaly request
130  */
131 struct GNUNET_SENSOR_ForceAnomalyContext
132 {
133
134   /**
135    * DLL
136    */
137   struct GNUNET_SENSOR_ForceAnomalyContext *next;
138
139   /**
140    * DLL
141    */
142   struct GNUNET_SENSOR_ForceAnomalyContext *prev;
143
144   /**
145    * Handle to the SENSOR service.
146    */
147   struct GNUNET_SENSOR_Handle *h;
148
149   /**
150    * Envelope containing iterate request.
151    */
152   struct GNUNET_MQ_Envelope *ev;
153
154   /**
155    * User continuation function
156    */
157   GNUNET_SENSOR_Continuation cont;
158
159   /**
160    * Closure for cont
161    */
162   void *cont_cls;
163
164 };
165
166
167 /**
168  * Notifier of an error encountered by MQ.
169  *
170  * @param cls Closure, service handle
171  * @param error MQ error type
172  */
173 static void
174 mq_error_handler (void *cls, enum GNUNET_MQ_Error error)
175 {
176   struct GNUNET_SENSOR_Handle *h = cls;
177
178   LOG (GNUNET_ERROR_TYPE_ERROR,
179        _("Received an error notification from MQ of type: %d\n"), error);
180   GNUNET_SENSOR_disconnect (h); //TODO: try to reconnect
181 }
182
183
184 /**
185  * Handler to a message of type: #GNUNET_MESSAGE_TYPE_SENSOR_END
186  *
187  * @param cls Closure, service handle
188  * @param msg Message received
189  */
190 static void
191 handle_end (void *cls, const struct GNUNET_MessageHeader *msg)
192 {
193   struct GNUNET_SENSOR_Handle *h = cls;
194   struct GNUNET_SENSOR_IterateContext *ic;
195   GNUNET_SENSOR_SensorIterateCB cb;
196   void *cb_cls;
197
198   if (NULL == h->ic_head)
199   {
200     GNUNET_break_op (0);
201     //TODO: reconnect
202     return;
203   }
204   ic = h->ic_head;
205   cb = ic->callback;
206   cb_cls = ic->callback_cls;
207   ic->receiving = GNUNET_NO;
208   GNUNET_SENSOR_iterate_cancel (ic);
209   if (NULL != cb)
210     cb (cb_cls, NULL, NULL);
211 }
212
213
214 /**
215  * Handler to a message of type: #GNUNET_MESSAGE_TYPE_SENSOR_INFO
216  *
217  * @param cls Closure, service handle
218  * @param msg Message received
219  */
220 static void
221 handle_sensor_info (void *cls, const struct GNUNET_MessageHeader *msg)
222 {
223   struct GNUNET_SENSOR_Handle *h = cls;
224   struct GNUNET_SENSOR_IterateContext *ic;
225   uint16_t msg_size;
226   struct SensorInfoMessage *sensor_msg;
227   uint16_t sensor_name_len;
228   uint16_t sensor_desc_len;
229   struct SensorInfoShort *sensor;
230   void *dummy;
231
232   if (NULL == h->ic_head)
233   {
234     GNUNET_break_op (0);
235     //TODO: reconnect
236     return;
237   }
238   ic = h->ic_head;
239   if (NULL == ic->callback)     /* no need to parse message */
240     return;
241   msg_size = ntohs (msg->size);
242   if (msg_size < sizeof (struct SensorInfoMessage))
243   {
244     GNUNET_break_op (0);
245     //TODO: reconnect
246     return;
247   }
248   sensor_msg = (struct SensorInfoMessage *) msg;
249   sensor_name_len = ntohs (sensor_msg->name_len);
250   sensor_desc_len = ntohs (sensor_msg->description_len);
251   if (msg_size !=
252       sizeof (struct SensorInfoMessage) + sensor_name_len + sensor_desc_len)
253   {
254     GNUNET_break_op (0);
255     //TODO: reconnect
256     return;
257   }
258   sensor = GNUNET_new (struct SensorInfoShort);
259   sensor->version_major = ntohs (sensor_msg->version_major);
260   sensor->version_minor = ntohs (sensor_msg->version_minor);
261   dummy = &sensor_msg[1];
262   sensor->name = GNUNET_strndup (dummy, sensor_name_len);
263   dummy += sensor_name_len;
264   sensor->description = GNUNET_strndup (dummy, sensor_desc_len);
265   ic->callback (ic->callback_cls, sensor, NULL);
266   GNUNET_free (sensor->name);
267   GNUNET_free (sensor->description);
268   GNUNET_free (sensor);
269 }
270
271
272 /**
273  * Disconnect from the sensor service.
274  * Please disconnect only when all requests sent are complete or canceled.
275  *
276  * @param h handle to disconnect
277  */
278 void
279 GNUNET_SENSOR_disconnect (struct GNUNET_SENSOR_Handle *h)
280 {
281   struct GNUNET_SENSOR_IterateContext *ic;
282   GNUNET_SENSOR_SensorIterateCB ic_callback;
283   void *ic_callback_cls;
284   struct GNUNET_SENSOR_ForceAnomalyContext *fa;
285   GNUNET_SENSOR_Continuation fa_cont;
286   void *fa_cont_cls;
287
288   ic = h->ic_head;
289   while (NULL != ic)
290   {
291     ic_callback = ic->callback;
292     ic_callback_cls = ic->callback_cls;
293     GNUNET_SENSOR_iterate_cancel (ic);
294     if (NULL != ic_callback)
295       ic_callback (ic_callback_cls, NULL,
296                    _("Iterate request canceled due to disconnection.\n"));
297     ic = h->ic_head;
298   }
299   fa = h->fa_head;
300   while (NULL != fa)
301   {
302     fa_cont = fa->cont;
303     fa_cont_cls = fa->cont_cls;
304     GNUNET_SENSOR_force_anomaly_cancel (fa);
305     if (NULL != fa_cont)
306       fa_cont (fa_cont_cls,
307                _("Force anomaly request canceled due to disconnection.\n"));
308     fa = h->fa_head;
309   }
310   if (NULL != h->mq)
311   {
312     GNUNET_MQ_destroy (h->mq);
313     h->mq = NULL;
314   }
315   if (NULL != h->client)
316   {
317     GNUNET_CLIENT_disconnect (h->client);
318     h->client = NULL;
319   }
320   GNUNET_free (h);
321 }
322
323
324 /**
325  * Connect to the sensor service.
326  *
327  * @return NULL on error
328  */
329 struct GNUNET_SENSOR_Handle *
330 GNUNET_SENSOR_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
331 {
332   struct GNUNET_CLIENT_Connection *client;
333   struct GNUNET_SENSOR_Handle *h;
334
335   static const struct GNUNET_MQ_MessageHandler mq_handlers[] = {
336     {&handle_sensor_info, GNUNET_MESSAGE_TYPE_SENSOR_INFO, 0},
337     {&handle_end, GNUNET_MESSAGE_TYPE_SENSOR_END, 0},
338     GNUNET_MQ_HANDLERS_END
339   };
340
341   client = GNUNET_CLIENT_connect ("sensor", cfg);
342   if (NULL == client)
343     return NULL;
344   h = GNUNET_new (struct GNUNET_SENSOR_Handle);
345   h->client = client;
346   h->cfg = cfg;
347   h->mq =
348       GNUNET_MQ_queue_for_connection_client (h->client, mq_handlers,
349                                              &mq_error_handler, h);
350   return h;
351 }
352
353
354 /**
355  * Iteration request has timed out.
356  *
357  * @param cls the 'struct GNUNET_SENSOR_SensorIteratorContext*'
358  * @param tc scheduler context
359  */
360 static void
361 signal_sensor_iteration_timeout (void *cls,
362                                  const struct GNUNET_SCHEDULER_TaskContext *tc)
363 {
364   struct GNUNET_SENSOR_IterateContext *ic = cls;
365   GNUNET_SENSOR_SensorIterateCB cb;
366   void *cb_cls;
367
368   ic->timeout_task = NULL;
369   cb = ic->callback;
370   cb_cls = ic->callback_cls;
371   GNUNET_SENSOR_iterate_cancel (ic);
372   if (NULL != cb)
373     cb (cb_cls, NULL,
374         _("Timeout transmitting iteration request to `SENSOR' service."));
375 }
376
377
378 /**
379  * Callback from MQ when the request has already been sent to the service.
380  * Now it can not be canelled.
381  *
382  * @param cls closure
383  */
384 static void
385 iterate_request_sent (void *cls)
386 {
387   struct GNUNET_SENSOR_IterateContext *ic = cls;
388
389   ic->request_sent = GNUNET_YES;
390   ic->ev = NULL;
391   ic->receiving = GNUNET_YES;
392 }
393
394
395 /**
396  * Cancel an iteration request.
397  * This should be called before the iterate callback is called with a NULL value.
398  *
399  * @param ic context of the iterator to cancel
400  */
401 void
402 GNUNET_SENSOR_iterate_cancel (struct GNUNET_SENSOR_IterateContext *ic)
403 {
404   struct GNUNET_SENSOR_Handle *h;
405
406   h = ic->h;
407   if (GNUNET_NO == ic->request_sent)
408   {
409     GNUNET_MQ_send_cancel (ic->ev);
410     ic->ev = NULL;
411     ic->request_sent = GNUNET_YES;
412   }
413   if (GNUNET_YES == ic->receiving)
414   {
415     /* don't remove since we are still expecting records */
416     ic->callback = NULL;
417     ic->callback_cls = NULL;
418     return;
419   }
420   if (NULL != ic->timeout_task)
421   {
422     GNUNET_SCHEDULER_cancel (ic->timeout_task);
423     ic->timeout_task = NULL;
424   }
425   GNUNET_CONTAINER_DLL_remove (h->ic_head, h->ic_tail, ic);
426   GNUNET_free (ic);
427 }
428
429
430 /**
431  * Get one or all sensors loaded by the sensor service.
432  * The callback will be called with each sensor received and once with a NULL
433  * value to signal end of iteration.
434  *
435  * @param h Handle to SENSOR service
436  * @param timeout how long to wait until timing out
437  * @param sensorname Name of the required sensor, NULL to get all
438  * @param callback the function to call for each sensor
439  * @param callback_cls closure for callback
440  * @return iterator context
441  */
442 struct GNUNET_SENSOR_IterateContext *
443 GNUNET_SENSOR_iterate (struct GNUNET_SENSOR_Handle *h,
444                        struct GNUNET_TIME_Relative timeout,
445                        const char *sensor_name,
446                        GNUNET_SENSOR_SensorIterateCB callback,
447                        void *callback_cls)
448 {
449   struct GNUNET_SENSOR_IterateContext *ic;
450   struct GNUNET_MessageHeader *msg;
451   struct GNUNET_MQ_Envelope *ev;
452   size_t sensor_name_len;
453
454   if (NULL == sensor_name)
455   {
456     ev = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SENSOR_GETALL);
457   }
458   else
459   {
460     sensor_name_len = strlen (sensor_name) + 1;
461     ev = GNUNET_MQ_msg_extra (msg, sensor_name_len,
462                               GNUNET_MESSAGE_TYPE_SENSOR_GET);
463     memcpy (&msg[1], sensor_name, sensor_name_len);
464   }
465   GNUNET_MQ_send (h->mq, ev);
466   ic = GNUNET_new (struct GNUNET_SENSOR_IterateContext);
467
468   ic->h = h;
469   ic->ev = ev;
470   ic->request_sent = GNUNET_NO;
471   ic->receiving = GNUNET_NO;
472   ic->callback = callback;
473   ic->callback_cls = callback_cls;
474   ic->timeout_task =
475       GNUNET_SCHEDULER_add_delayed (timeout, &signal_sensor_iteration_timeout,
476                                     ic);
477   GNUNET_MQ_notify_sent (ev, &iterate_request_sent, ic);
478   GNUNET_CONTAINER_DLL_insert_tail (h->ic_head, h->ic_tail, ic);
479   return ic;
480 }
481
482
483 /**
484  * Callback from MQ when the request has already been sent to the service.
485  * Now it can not be canelled.
486  *
487  * @param cls closure
488  */
489 static void
490 force_anomaly_sent (void *cls)
491 {
492   struct GNUNET_SENSOR_ForceAnomalyContext *fa = cls;
493   GNUNET_SENSOR_Continuation cont;
494   void *cont_cls;
495
496   fa->ev = NULL;
497   cont = fa->cont;
498   cont_cls = fa->cont_cls;
499   GNUNET_SENSOR_force_anomaly_cancel (fa);
500   if (NULL != cont)
501     cont (cont_cls, NULL);
502 }
503
504
505 /**
506  * Cancel a force anomaly request.
507  *
508  * @param fa Force anomaly context returned by GNUNET_SENSOR_force_anomaly()
509  */
510 void
511 GNUNET_SENSOR_force_anomaly_cancel (struct GNUNET_SENSOR_ForceAnomalyContext
512                                     *fa)
513 {
514   struct GNUNET_SENSOR_Handle *h = fa->h;
515
516   if (NULL != fa->ev)
517   {
518     GNUNET_MQ_send_cancel (fa->ev);
519     fa->ev = NULL;
520   }
521   GNUNET_CONTAINER_DLL_remove (h->fa_head, h->fa_tail, fa);
522   GNUNET_free (fa);
523 }
524
525
526 /**
527  * Force an anomaly status change on a given sensor. If the sensor reporting
528  * module is running, this will trigger the usual reporting logic, therefore,
529  * please only use this in a test environment.
530  *
531  * Also, if the sensor analysis module is running, it might conflict and cause
532  * undefined behaviour if it detects a real anomaly.
533  *
534  * @param h Service handle
535  * @param sensor_name Sensor name to set the anomaly status
536  * @param anomalous The desired status: #GNUNET_YES / #GNUNET_NO
537  * @param cont Continuation function to be called after the request is sent
538  * @param cont_cls Closure for cont
539  */
540 struct GNUNET_SENSOR_ForceAnomalyContext *
541 GNUNET_SENSOR_force_anomaly (struct GNUNET_SENSOR_Handle *h, char *sensor_name,
542                              int anomalous, GNUNET_SENSOR_Continuation cont,
543                              void *cont_cls)
544 {
545   struct ForceAnomalyMessage *msg;
546   struct GNUNET_MQ_Envelope *ev;
547   struct GNUNET_SENSOR_ForceAnomalyContext *fa;
548
549   ev = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SENSOR_ANOMALY_FORCE);
550   GNUNET_CRYPTO_hash (sensor_name, strlen (sensor_name) + 1,
551                       &msg->sensor_name_hash);
552   msg->anomalous = htons (anomalous);
553   GNUNET_MQ_send (h->mq, ev);
554   fa = GNUNET_new (struct GNUNET_SENSOR_ForceAnomalyContext);
555
556   fa->h = h;
557   fa->cont = cont;
558   fa->cont_cls = cont_cls;
559   fa->ev = ev;
560   GNUNET_CONTAINER_DLL_insert_tail (h->fa_head, h->fa_tail, fa);
561   GNUNET_MQ_notify_sent (ev, &force_anomaly_sent, fa);
562   return fa;
563 }
564
565
566 /* end of sensor_api.c */