sensor: merged reporting module
[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
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 /************************      DATA STRUCTURES     ****************************/
34 /******************************************************************************/
35
36 /**
37  * Handle to the sensor service.
38  */
39 struct GNUNET_SENSOR_Handle
40 {
41
42   /**
43    * Our configuration.
44    */
45   const struct GNUNET_CONFIGURATION_Handle *cfg;
46
47   /**
48    * Connection to the service.
49    */
50   struct GNUNET_CLIENT_Connection *client;
51
52   /**
53    * Head of transmission queue.
54    */
55   struct GNUNET_SENSOR_RequestContext *rc_head;
56
57   /**
58    * Tail of transmission queue.
59    */
60   struct GNUNET_SENSOR_RequestContext *rc_tail;
61
62   /**
63    * Handle for the current transmission request, or NULL if none is pending.
64    */
65   struct GNUNET_CLIENT_TransmitHandle *th;
66
67   /**
68    * Head of iterator DLL.
69    */
70   struct GNUNET_SENSOR_SensorIteratorContext *ic_head;
71
72   /**
73    * Tail of iterator DLL.
74    */
75   struct GNUNET_SENSOR_SensorIteratorContext *ic_tail;
76
77   /**
78    * ID for a reconnect task.
79    */
80   GNUNET_SCHEDULER_TaskIdentifier r_task;
81
82   /**
83    * Are we now receiving?
84    */
85   int in_receive;
86
87 };
88
89 /**
90  * Entry in the transmission queue to SENSOR service.
91  *
92  */
93 struct GNUNET_SENSOR_RequestContext
94 {
95   /**
96    * This is a linked list.
97    */
98   struct GNUNET_SENSOR_RequestContext *next;
99
100   /**
101    * This is a linked list.
102    */
103   struct GNUNET_SENSOR_RequestContext *prev;
104
105   /**
106    * Handle to the SENSOR service.
107    */
108   struct GNUNET_SENSOR_Handle *h;
109
110   /**
111    * Function to call after request has been transmitted, or NULL.
112    */
113   GNUNET_SENSOR_Continuation cont;
114
115   /**
116    * Closure for 'cont'.
117    */
118   void *cont_cls;
119
120   /**
121    * Number of bytes of the request message (follows after this struct).
122    */
123   size_t size;
124
125 };
126
127 /**
128  * Context for an iteration request.
129  */
130 struct GNUNET_SENSOR_SensorIteratorContext
131 {
132
133   /**
134    * Kept in a DLL.
135    */
136   struct GNUNET_SENSOR_SensorIteratorContext *next;
137
138   /**
139    * Kept in a DLL.
140    */
141   struct GNUNET_SENSOR_SensorIteratorContext *prev;
142
143   /**
144    * Handle to the SENSOR service.
145    */
146   struct GNUNET_SENSOR_Handle *h;
147
148   /**
149    * Function to call with the results.
150    */
151   GNUNET_SENSOR_SensorIteratorCB callback;
152
153   /**
154    * Closure for 'callback'.
155    */
156   void *callback_cls;
157
158   /**
159    * Our entry in the transmission queue.
160    */
161   struct GNUNET_SENSOR_RequestContext *rc;
162
163   /**
164    * Task responsible for timeout.
165    */
166   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
167
168   /**
169    * Timeout for the operation.
170    */
171   struct GNUNET_TIME_Absolute timeout;
172
173   /**
174    * Set to GNUNET_YES if we are currently receiving replies from the
175    * service.
176    */
177   int request_transmitted;
178
179 };
180
181 /******************************************************************************/
182 /***********************         DECLARATIONS         *************************/
183 /******************************************************************************/
184
185 /**
186  * Close the existing connection to SENSOR and reconnect.
187  *
188  * @param h handle to the service
189  */
190 static void
191 reconnect (struct GNUNET_SENSOR_Handle *h);
192
193
194 /**
195  * Check if we have a request pending in the transmission queue and are
196  * able to transmit it right now.  If so, schedule transmission.
197  *
198  * @param h handle to the service
199  */
200 static void
201 trigger_transmit (struct GNUNET_SENSOR_Handle *h);
202
203 /******************************************************************************/
204 /*******************         CONNECTION FUNCTIONS         *********************/
205 /******************************************************************************/
206
207 /**
208  * Connect to the sensor service.
209  *
210  * @return NULL on error
211  */
212 struct GNUNET_SENSOR_Handle *
213 GNUNET_SENSOR_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
214 {
215   struct GNUNET_CLIENT_Connection *client;
216   struct GNUNET_SENSOR_Handle *h;
217
218   client = GNUNET_CLIENT_connect ("sensor", cfg);
219   if (NULL == client)
220     return NULL;
221   h = GNUNET_new (struct GNUNET_SENSOR_Handle);
222   h->client = client;
223   h->cfg = cfg;
224   return h;
225 }
226
227
228 /**
229  * Disconnect from the sensor service
230  *
231  * @param h handle to disconnect
232  */
233 void
234 GNUNET_SENSOR_disconnect (struct GNUNET_SENSOR_Handle *h)
235 {
236   if (NULL != h->client)
237   {
238     GNUNET_CLIENT_disconnect (h->client);
239     h->client = NULL;
240   }
241   GNUNET_free (h);
242 }
243
244
245 /**
246  * Task scheduled to re-try connecting to the sensor service.
247  *
248  * @param cls the 'struct GNUNET_SENSOR_Handle'
249  * @param tc scheduler context
250  */
251 static void
252 reconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
253 {
254   struct GNUNET_SENSOR_Handle *h = cls;
255
256   h->r_task = GNUNET_SCHEDULER_NO_TASK;
257   reconnect (h);
258 }
259
260
261 /**
262  * Close the existing connection to SENSOR and reconnect.
263  *
264  * @param h handle to the service
265  */
266 static void
267 reconnect (struct GNUNET_SENSOR_Handle *h)
268 {
269   if (GNUNET_SCHEDULER_NO_TASK != h->r_task)
270   {
271     GNUNET_SCHEDULER_cancel (h->r_task);
272     h->r_task = GNUNET_SCHEDULER_NO_TASK;
273   }
274   if (NULL != h->th)
275   {
276     GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
277     h->th = NULL;
278   }
279   if (NULL != h->client)
280   {
281     GNUNET_CLIENT_disconnect (h->client);
282     h->client = NULL;
283   }
284   h->in_receive = GNUNET_NO;
285   h->client = GNUNET_CLIENT_connect ("sensor", h->cfg);
286   if (NULL == h->client)
287   {
288     h->r_task =
289         GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &reconnect_task,
290                                       h);
291     return;
292   }
293   trigger_transmit (h);
294 }
295
296 /******************************************************************************/
297 /******************         SENSOR DATA FUNCTIONS         *********************/
298 /******************************************************************************/
299
300 /**
301  * Cancel an iteration over sensor information.
302  *
303  * @param ic context of the iterator to cancel
304  */
305 void
306 GNUNET_SENSOR_iterate_sensor_cancel (struct GNUNET_SENSOR_SensorIteratorContext
307                                      *ic)
308 {
309   struct GNUNET_SENSOR_Handle *h;
310
311   h = ic->h;
312   if (GNUNET_SCHEDULER_NO_TASK != ic->timeout_task)
313   {
314     GNUNET_SCHEDULER_cancel (ic->timeout_task);
315     ic->timeout_task = GNUNET_SCHEDULER_NO_TASK;
316   }
317   ic->callback = NULL;
318   if (GNUNET_YES == ic->request_transmitted)
319     return;                     /* need to finish processing */
320   GNUNET_CONTAINER_DLL_remove (h->ic_head, h->ic_tail, ic);
321   if (NULL != ic->rc)
322   {
323     GNUNET_CONTAINER_DLL_remove (h->rc_head, h->rc_tail, ic->rc);
324     GNUNET_free (ic->rc);
325   }
326   GNUNET_free (ic);
327 }
328
329
330 /**
331  * Iteration request has timed out.
332  *
333  * @param cls the 'struct GNUNET_SENSOR_SensorIteratorContext*'
334  * @param tc scheduler context
335  */
336 static void
337 signal_sensor_iteration_timeout (void *cls,
338                                  const struct GNUNET_SCHEDULER_TaskContext *tc)
339 {
340   struct GNUNET_SENSOR_SensorIteratorContext *ic = cls;
341   GNUNET_SENSOR_SensorIteratorCB cb;
342   void *cb_cls;
343
344   ic->timeout_task = GNUNET_SCHEDULER_NO_TASK;
345   cb = ic->callback;
346   cb_cls = ic->callback_cls;
347   GNUNET_SENSOR_iterate_sensor_cancel (ic);
348   if (NULL != cb)
349     cb (cb_cls, NULL,
350         _("Timeout transmitting iteration request to `SENSOR' service."));
351 }
352
353
354 /**
355  * Type of a function to call when we receive a message from the
356  * service.  Call the iterator with the result and (if applicable)
357  * continue to receive more messages or trigger processing the next
358  * event (if applicable).
359  *
360  * @param cls closure
361  * @param msg message received, NULL on timeout or fatal error
362  */
363 static void
364 sensor_handler (void *cls, const struct GNUNET_MessageHeader *msg)
365 {
366   struct GNUNET_SENSOR_Handle *h = cls;
367   struct GNUNET_SENSOR_SensorIteratorContext *ic = h->ic_head;
368   GNUNET_SENSOR_SensorIteratorCB cb;
369   void *cb_cls;
370   uint16_t ms;
371   const struct SensorInfoMessage *im;
372   struct SensorInfoShort *sensor;
373   size_t name_len;
374   size_t desc_len;
375   char *str_ptr;
376
377   h->in_receive = GNUNET_NO;
378   if (NULL == msg)
379   {
380     /* sensor service died, signal error */
381     if (NULL != ic)
382     {
383       cb = ic->callback;
384       cb_cls = ic->callback_cls;
385       GNUNET_SENSOR_iterate_sensor_cancel (ic);
386     }
387     else
388     {
389       cb = NULL;
390     }
391     reconnect (h);
392     if (NULL != cb)
393       cb (cb_cls, NULL, _("Failed to receive response from `SENSOR' service."));
394     return;
395   }
396   if (NULL == ic)
397   {
398     /* didn't expect a response, reconnect */
399     reconnect (h);
400     return;
401   }
402   ic->request_transmitted = GNUNET_NO;
403   cb = ic->callback;
404   cb_cls = ic->callback_cls;
405   if (GNUNET_MESSAGE_TYPE_SENSOR_END == ntohs (msg->type))
406   {
407     /* normal end of list of sensors, signal end, process next pending request */
408     LOG (GNUNET_ERROR_TYPE_DEBUG,
409          "Received end of list of sensors from `%s' service\n", "SENSOR");
410     GNUNET_SENSOR_iterate_sensor_cancel (ic);
411     trigger_transmit (h);
412     if ((GNUNET_NO == h->in_receive) && (NULL != h->ic_head))
413     {
414       h->in_receive = GNUNET_YES;
415       GNUNET_CLIENT_receive (h->client, &sensor_handler, h,
416                              GNUNET_TIME_absolute_get_remaining (h->
417                                                                  ic_head->timeout));
418     }
419     if (NULL != cb)
420       cb (cb_cls, NULL, NULL);
421     return;
422   }
423   ms = ntohs (msg->size);
424   im = (const struct SensorInfoMessage *) msg;
425   name_len = ntohs (im->name_len);
426   desc_len = ntohs (im->description_len);
427   if ((ms != sizeof (struct SensorInfoMessage) + name_len + desc_len) ||
428       (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_SENSOR_INFO))
429   {
430     /* malformed message */
431     GNUNET_break (0);
432     GNUNET_SENSOR_iterate_sensor_cancel (ic);
433     reconnect (h);
434     if (NULL != cb)
435       cb (cb_cls, NULL, _("Received invalid message from `SENSOR' service."));
436     return;
437   }
438   sensor = GNUNET_new (struct SensorInfoShort);
439   str_ptr = (char *) &im[1];
440   sensor->name = GNUNET_strndup (str_ptr, name_len);
441   LOG (GNUNET_ERROR_TYPE_DEBUG, "Received sensor name (%d): %.*s\n", name_len,
442        name_len, str_ptr);
443   str_ptr += name_len;
444   if (desc_len > 0)
445   {
446     LOG (GNUNET_ERROR_TYPE_DEBUG, "Received sensor description (%d): %.*s\n",
447          desc_len, desc_len, str_ptr);
448     sensor->description = GNUNET_strndup (str_ptr, desc_len);
449   }
450   sensor->version_major = ntohs (im->version_major);
451   sensor->version_minor = ntohs (im->version_minor);
452   h->in_receive = GNUNET_YES;
453   GNUNET_CLIENT_receive (h->client, &sensor_handler, h,
454                          GNUNET_TIME_absolute_get_remaining (ic->timeout));
455   if (NULL != cb)
456     cb (cb_cls, sensor, NULL);
457 }
458
459
460 /**
461  * We've transmitted the iteration request.  Now get ready to process
462  * the results (or handle transmission error).
463  *
464  * @param cls the 'struct GNUNET_SENSOR_SensorIteratorContext'
465  * @param emsg error message, NULL if transmission worked
466  */
467 static void
468 sensor_iterator_start_receive (void *cls, const char *emsg)
469 {
470   struct GNUNET_SENSOR_SensorIteratorContext *ic = cls;
471   struct GNUNET_SENSOR_Handle *h = ic->h;
472   GNUNET_SENSOR_SensorIteratorCB cb;
473   void *cb_cls;
474
475   ic->rc = NULL;
476   if (NULL != emsg)
477   {
478     cb = ic->callback;
479     cb_cls = ic->callback_cls;
480     GNUNET_SENSOR_iterate_sensor_cancel (ic);
481     reconnect (h);
482     if (NULL != cb)
483       cb (cb_cls, NULL, emsg);
484     return;
485   }
486   LOG (GNUNET_ERROR_TYPE_DEBUG, "Waiting for response from `%s' service.\n",
487        "SENSOR");
488   ic->request_transmitted = GNUNET_YES;
489   if (GNUNET_NO == h->in_receive)
490   {
491     h->in_receive = GNUNET_YES;
492     GNUNET_CLIENT_receive (h->client, &sensor_handler, h,
493                            GNUNET_TIME_absolute_get_remaining (ic->timeout));
494   }
495 }
496
497
498 /**
499  * Transmit the request at the head of the transmission queue
500  * and trigger continuation (if any).
501  *
502  * @param cls the 'struct GNUNET_SENSOR_Handle' (with the queue)
503  * @param size size of the buffer (0 on error)
504  * @param buf where to copy the message
505  * @return number of bytes copied to buf
506  */
507 static size_t
508 do_transmit (void *cls, size_t size, void *buf)
509 {
510   struct GNUNET_SENSOR_Handle *h = cls;
511   struct GNUNET_SENSOR_RequestContext *rc = h->rc_head;
512   size_t ret;
513
514   h->th = NULL;
515   if (NULL == rc)
516     return 0;                   /* request was cancelled in the meantime */
517   if (NULL == buf)
518   {
519     /* sensor service died */
520     LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
521          "Failed to transmit message to `%s' service.\n", "SENSOR");
522     GNUNET_CONTAINER_DLL_remove (h->rc_head, h->rc_tail, rc);
523     reconnect (h);
524     if (NULL != rc->cont)
525       rc->cont (rc->cont_cls, _("failed to transmit request (service down?)"));
526     GNUNET_free (rc);
527     return 0;
528   }
529   ret = rc->size;
530   if (size < ret)
531   {
532     /* change in head of queue (i.e. cancel + add), try again */
533     trigger_transmit (h);
534     return 0;
535   }
536   LOG (GNUNET_ERROR_TYPE_DEBUG,
537        "Transmitting request of size %u to `%s' service.\n", ret, "SENSOR");
538   memcpy (buf, &rc[1], ret);
539   GNUNET_CONTAINER_DLL_remove (h->rc_head, h->rc_tail, rc);
540   trigger_transmit (h);
541   if (NULL != rc->cont)
542     rc->cont (rc->cont_cls, NULL);
543   GNUNET_free (rc);
544   return ret;
545 }
546
547
548 /**
549  * Check if we have a request pending in the transmission queue and are
550  * able to transmit it right now.  If so, schedule transmission.
551  *
552  * @param h handle to the service
553  */
554 static void
555 trigger_transmit (struct GNUNET_SENSOR_Handle *h)
556 {
557   struct GNUNET_SENSOR_RequestContext *rc;
558
559   if (NULL == (rc = h->rc_head))
560     return;                     /* no requests queued */
561   if (NULL != h->th)
562     return;                     /* request already pending */
563   if (NULL == h->client)
564   {
565     /* disconnected, try to reconnect */
566     reconnect (h);
567     return;
568   }
569   h->th =
570       GNUNET_CLIENT_notify_transmit_ready (h->client, rc->size,
571                                            GNUNET_TIME_UNIT_FOREVER_REL,
572                                            GNUNET_YES, &do_transmit, h);
573 }
574
575
576 /**
577  * Client asking to iterate all available sensors
578  *
579  * @param h Handle to SENSOR service
580  * @param timeout how long to wait until timing out
581  * @param sensorname information on one sensor only, can be NULL to get all
582  * @param sensorname_len length of the sensorname parameter
583  * @param callback the method to call for each sensor
584  * @param callback_cls closure for callback
585  * @return iterator context
586  */
587 struct GNUNET_SENSOR_SensorIteratorContext *
588 GNUNET_SENSOR_iterate_sensors (struct GNUNET_SENSOR_Handle *h,
589                                struct GNUNET_TIME_Relative timeout,
590                                const char *sensorname, size_t sensorname_len,
591                                GNUNET_SENSOR_SensorIteratorCB callback,
592                                void *callback_cls)
593 {
594   struct GNUNET_SENSOR_SensorIteratorContext *ic;
595   struct GNUNET_SENSOR_RequestContext *rc;
596   struct GNUNET_MessageHeader *mh;
597
598   ic = GNUNET_new (struct GNUNET_SENSOR_SensorIteratorContext);
599
600   if (NULL == sensorname)
601   {
602     LOG (GNUNET_ERROR_TYPE_INFO,
603          "Requesting list of sensors from SENSOR service\n");
604     rc = GNUNET_malloc (sizeof (struct GNUNET_SENSOR_RequestContext) +
605                         sizeof (struct GNUNET_MessageHeader));
606     rc->size = sizeof (struct GNUNET_MessageHeader);
607     mh = (struct GNUNET_MessageHeader *) &rc[1];
608     mh->size = htons (sizeof (struct GNUNET_MessageHeader));
609     mh->type = htons (GNUNET_MESSAGE_TYPE_SENSOR_GETALL);
610   }
611   else
612   {
613     LOG (GNUNET_ERROR_TYPE_INFO,
614          "Requesting information on sensor `%s' from SENSOR service\n",
615          sensorname);
616     rc = GNUNET_malloc (sizeof (struct GNUNET_SENSOR_RequestContext) +
617                         sizeof (struct GNUNET_MessageHeader) + sensorname_len);
618     rc->size = sizeof (struct GNUNET_MessageHeader) + sensorname_len;
619     mh = (struct GNUNET_MessageHeader *) &rc[1];
620     mh->size = htons (rc->size);
621     mh->type = htons (GNUNET_MESSAGE_TYPE_SENSOR_GET);
622     memcpy (&mh[1], sensorname, sensorname_len);
623   }
624   ic->h = h;
625   ic->rc = rc;
626   ic->callback = callback;
627   ic->callback_cls = callback_cls;
628   ic->timeout = GNUNET_TIME_relative_to_absolute (timeout);
629   ic->timeout_task =
630       GNUNET_SCHEDULER_add_delayed (timeout, &signal_sensor_iteration_timeout,
631                                     ic);
632   rc->cont = &sensor_iterator_start_receive;
633   rc->cont_cls = ic;
634   GNUNET_CONTAINER_DLL_insert_tail (h->rc_head, h->rc_tail, rc);
635   GNUNET_CONTAINER_DLL_insert_tail (h->ic_head, h->ic_tail, ic);
636   trigger_transmit (h);
637   return ic;
638 }
639
640 /* end of sensor_api.c */