sensor: towards reporting to collection point
[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  * Check if we have a request pending in the transmission queue and are
195  * able to transmit it right now.  If so, schedule transmission.
196  *
197  * @param h handle to the service
198  */
199 static void
200 trigger_transmit (struct GNUNET_SENSOR_Handle *h);
201
202 /******************************************************************************/
203 /*******************         CONNECTION FUNCTIONS         *********************/
204 /******************************************************************************/
205
206 /**
207  * Connect to the sensor service.
208  *
209  * @return NULL on error
210  */
211 struct GNUNET_SENSOR_Handle *
212 GNUNET_SENSOR_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
213 {
214   struct GNUNET_CLIENT_Connection *client;
215   struct GNUNET_SENSOR_Handle *h;
216
217   client = GNUNET_CLIENT_connect ("sensor", cfg);
218   if(NULL == client)
219     return NULL;
220   h = GNUNET_new (struct GNUNET_SENSOR_Handle);
221   h->client = client;
222   h->cfg = cfg;
223   return h;
224 }
225
226 /**
227  * Disconnect from the sensor service
228  *
229  * @param h handle to disconnect
230  */
231 void
232 GNUNET_SENSOR_disconnect(struct GNUNET_SENSOR_Handle *h)
233 {
234   if (NULL != h->client)
235   {
236     GNUNET_CLIENT_disconnect (h->client);
237     h->client = NULL;
238   }
239   GNUNET_free (h);
240 }
241
242 /**
243  * Task scheduled to re-try connecting to the sensor service.
244  *
245  * @param cls the 'struct GNUNET_SENSOR_Handle'
246  * @param tc scheduler context
247  */
248 static void
249 reconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
250 {
251   struct GNUNET_SENSOR_Handle *h = cls;
252
253   h->r_task = GNUNET_SCHEDULER_NO_TASK;
254   reconnect (h);
255 }
256
257 /**
258  * Close the existing connection to SENSOR and reconnect.
259  *
260  * @param h handle to the service
261  */
262 static void
263 reconnect (struct GNUNET_SENSOR_Handle *h)
264 {
265   if (GNUNET_SCHEDULER_NO_TASK != h->r_task)
266   {
267     GNUNET_SCHEDULER_cancel (h->r_task);
268     h->r_task = GNUNET_SCHEDULER_NO_TASK;
269   }
270   if (NULL != h->th)
271   {
272     GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
273     h->th = NULL;
274   }
275   if (NULL != h->client)
276   {
277     GNUNET_CLIENT_disconnect (h->client);
278     h->client = NULL;
279   }
280   h->in_receive = GNUNET_NO;
281   h->client = GNUNET_CLIENT_connect ("sensor", h->cfg);
282   if (NULL == h->client)
283   {
284     h->r_task =
285         GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &reconnect_task,
286                                       h);
287     return;
288   }
289   trigger_transmit (h);
290 }
291
292 /******************************************************************************/
293 /******************         SENSOR DATA FUNCTIONS         *********************/
294 /******************************************************************************/
295
296 /**
297  * Cancel an iteration over sensor information.
298  *
299  * @param ic context of the iterator to cancel
300  */
301 void
302 GNUNET_SENSOR_iterate_sensor_cancel (struct GNUNET_SENSOR_SensorIteratorContext *ic)
303 {
304   struct GNUNET_SENSOR_Handle *h;
305
306   h = ic->h;
307   if (GNUNET_SCHEDULER_NO_TASK != ic->timeout_task)
308   {
309     GNUNET_SCHEDULER_cancel (ic->timeout_task);
310     ic->timeout_task = GNUNET_SCHEDULER_NO_TASK;
311   }
312   ic->callback = NULL;
313   if (GNUNET_YES == ic->request_transmitted)
314     return;                     /* need to finish processing */
315   GNUNET_CONTAINER_DLL_remove (h->ic_head,
316              h->ic_tail,
317              ic);
318   if (NULL != ic->rc)
319   {
320     GNUNET_CONTAINER_DLL_remove (h->rc_head, h->rc_tail, ic->rc);
321     GNUNET_free (ic->rc);
322   }
323   GNUNET_free (ic);
324 }
325
326 /**
327  * Iteration request has timed out.
328  *
329  * @param cls the 'struct GNUNET_SENSOR_SensorIteratorContext*'
330  * @param tc scheduler context
331  */
332 static void
333 signal_sensor_iteration_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
334 {
335   struct GNUNET_SENSOR_SensorIteratorContext *ic = cls;
336   GNUNET_SENSOR_SensorIteratorCB cb;
337   void *cb_cls;
338
339   ic->timeout_task = GNUNET_SCHEDULER_NO_TASK;
340   cb = ic->callback;
341   cb_cls = ic->callback_cls;
342   GNUNET_SENSOR_iterate_sensor_cancel (ic);
343   if (NULL != cb)
344     cb (cb_cls, NULL,
345   _("Timeout transmitting iteration request to `SENSOR' service."));
346 }
347
348 /**
349  * Type of a function to call when we receive a message from the
350  * service.  Call the iterator with the result and (if applicable)
351  * continue to receive more messages or trigger processing the next
352  * event (if applicable).
353  *
354  * @param cls closure
355  * @param msg message received, NULL on timeout or fatal error
356  */
357 static void
358 sensor_handler(void *cls, const struct GNUNET_MessageHeader *msg)
359 {
360   struct GNUNET_SENSOR_Handle *h = cls;
361   struct GNUNET_SENSOR_SensorIteratorContext *ic = h->ic_head;
362   GNUNET_SENSOR_SensorIteratorCB cb;
363   void *cb_cls;
364   uint16_t ms;
365   const struct SensorInfoMessage *im;
366   struct SensorInfoShort *sensor;
367   size_t name_len;
368   size_t desc_len;
369   char *str_ptr;
370
371   h->in_receive = GNUNET_NO;
372   if (NULL == msg)
373   {
374     /* sensor service died, signal error */
375     if (NULL != ic)
376     {
377       cb = ic->callback;
378       cb_cls = ic->callback_cls;
379       GNUNET_SENSOR_iterate_sensor_cancel(ic);
380     }
381     else
382     {
383       cb = NULL;
384     }
385     reconnect (h);
386     if (NULL != cb)
387       cb (cb_cls, NULL,
388     _("Failed to receive response from `SENSOR' service."));
389     return;
390   }
391   if (NULL == ic)
392   {
393     /* didn't expect a response, reconnect */
394     reconnect (h);
395     return;
396   }
397   ic->request_transmitted = GNUNET_NO;
398   cb = ic->callback;
399   cb_cls = ic->callback_cls;
400   if (GNUNET_MESSAGE_TYPE_SENSOR_END == ntohs (msg->type))
401   {
402     /* normal end of list of sensors, signal end, process next pending request */
403     LOG (GNUNET_ERROR_TYPE_DEBUG,
404          "Received end of list of sensors from `%s' service\n", "SENSOR");
405     GNUNET_SENSOR_iterate_sensor_cancel(ic);
406     trigger_transmit (h);
407     if ( (GNUNET_NO == h->in_receive) &&
408    (NULL != h->ic_head) )
409     {
410       h->in_receive = GNUNET_YES;
411       GNUNET_CLIENT_receive (h->client, &sensor_handler, h,
412            GNUNET_TIME_absolute_get_remaining (h->ic_head->timeout));
413     }
414     if (NULL != cb)
415       cb (cb_cls, NULL, NULL);
416     return;
417   }
418   ms = ntohs (msg->size);
419   im = (const struct SensorInfoMessage *) msg;
420   name_len = ntohs(im->name_len);
421   desc_len = ntohs(im->description_len);
422   if ((ms != sizeof (struct SensorInfoMessage) + name_len + desc_len) ||
423       (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_SENSOR_INFO))
424   {
425     /* malformed message */
426     GNUNET_break (0);
427     GNUNET_SENSOR_iterate_sensor_cancel(ic);
428     reconnect (h);
429     if (NULL != cb)
430       cb (cb_cls, NULL,
431     _("Received invalid message from `SENSOR' service."));
432     return;
433   }
434   sensor = GNUNET_new(struct SensorInfoShort);
435   str_ptr = (char *)&im[1];
436   sensor->name = GNUNET_strndup(str_ptr, name_len);
437   LOG (GNUNET_ERROR_TYPE_DEBUG, "Received sensor name (%d): %.*s\n",
438                name_len, name_len, str_ptr);
439   str_ptr += name_len;
440   if(desc_len > 0)
441   {
442     LOG (GNUNET_ERROR_TYPE_DEBUG, "Received sensor description (%d): %.*s\n",
443                  desc_len, desc_len, str_ptr);
444     sensor->description = GNUNET_strndup(str_ptr, desc_len);
445   }
446   sensor->version_major = ntohs(im->version_major);
447   sensor->version_minor = ntohs(im->version_minor);
448   h->in_receive = GNUNET_YES;
449   GNUNET_CLIENT_receive (h->client, &sensor_handler, h,
450                          GNUNET_TIME_absolute_get_remaining (ic->timeout));
451   if (NULL != cb)
452     cb (cb_cls, sensor, NULL);
453 }
454
455 /**
456  * We've transmitted the iteration request.  Now get ready to process
457  * the results (or handle transmission error).
458  *
459  * @param cls the 'struct GNUNET_SENSOR_SensorIteratorContext'
460  * @param emsg error message, NULL if transmission worked
461  */
462 static void
463 sensor_iterator_start_receive (void *cls, const char *emsg)
464 {
465   struct GNUNET_SENSOR_SensorIteratorContext *ic = cls;
466   struct GNUNET_SENSOR_Handle *h = ic->h;
467   GNUNET_SENSOR_SensorIteratorCB cb;
468   void *cb_cls;
469
470   ic->rc = NULL;
471   if (NULL != emsg)
472   {
473     cb = ic->callback;
474     cb_cls = ic->callback_cls;
475     GNUNET_SENSOR_iterate_sensor_cancel (ic);
476     reconnect (h);
477     if (NULL != cb)
478       cb (cb_cls, NULL, emsg);
479     return;
480   }
481   LOG (GNUNET_ERROR_TYPE_DEBUG, "Waiting for response from `%s' service.\n",
482        "SENSOR");
483   ic->request_transmitted = GNUNET_YES;
484   if (GNUNET_NO == h->in_receive)
485   {
486     h->in_receive = GNUNET_YES;
487     GNUNET_CLIENT_receive (h->client, &sensor_handler, h,
488          GNUNET_TIME_absolute_get_remaining (ic->timeout));
489   }
490 }
491
492 /**
493  * Transmit the request at the head of the transmission queue
494  * and trigger continuation (if any).
495  *
496  * @param cls the 'struct GNUNET_SENSOR_Handle' (with the queue)
497  * @param size size of the buffer (0 on error)
498  * @param buf where to copy the message
499  * @return number of bytes copied to buf
500  */
501 static size_t
502 do_transmit (void *cls, size_t size, void *buf)
503 {
504   struct GNUNET_SENSOR_Handle *h = cls;
505   struct GNUNET_SENSOR_RequestContext *rc = h->rc_head;
506   size_t ret;
507
508   h->th = NULL;
509   if (NULL == rc)
510     return 0; /* request was cancelled in the meantime */
511   if (NULL == buf)
512   {
513     /* sensor service died */
514     LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
515          "Failed to transmit message to `%s' service.\n", "SENSOR");
516     GNUNET_CONTAINER_DLL_remove (h->rc_head, h->rc_tail, rc);
517     reconnect (h);
518     if (NULL != rc->cont)
519       rc->cont (rc->cont_cls, _("failed to transmit request (service down?)"));
520     GNUNET_free (rc);
521     return 0;
522   }
523   ret = rc->size;
524   if (size < ret)
525   {
526     /* change in head of queue (i.e. cancel + add), try again */
527     trigger_transmit (h);
528     return 0;
529   }
530   LOG (GNUNET_ERROR_TYPE_DEBUG,
531        "Transmitting request of size %u to `%s' service.\n", ret, "SENSOR");
532   memcpy (buf, &rc[1], ret);
533   GNUNET_CONTAINER_DLL_remove (h->rc_head, h->rc_tail, rc);
534   trigger_transmit (h);
535   if (NULL != rc->cont)
536     rc->cont (rc->cont_cls, NULL);
537   GNUNET_free (rc);
538   return ret;
539 }
540
541 /**
542  * Check if we have a request pending in the transmission queue and are
543  * able to transmit it right now.  If so, schedule transmission.
544  *
545  * @param h handle to the service
546  */
547 static void
548 trigger_transmit (struct GNUNET_SENSOR_Handle *h)
549 {
550   struct GNUNET_SENSOR_RequestContext *rc;
551
552   if (NULL == (rc = h->rc_head))
553     return; /* no requests queued */
554   if (NULL != h->th)
555     return; /* request already pending */
556   if (NULL == h->client)
557   {
558     /* disconnected, try to reconnect */
559     reconnect (h);
560     return;
561   }
562   h->th =
563     GNUNET_CLIENT_notify_transmit_ready (h->client, rc->size,
564            GNUNET_TIME_UNIT_FOREVER_REL,
565            GNUNET_YES,
566            &do_transmit, h);
567 }
568
569 /**
570  * Client asking to iterate all available sensors
571  *
572  * @param h Handle to SENSOR service
573  * @param timeout how long to wait until timing out
574  * @param sensorname information on one sensor only, can be NULL to get all
575  * @param sensorname_len length of the sensorname parameter
576  * @param callback the method to call for each sensor
577  * @param callback_cls closure for callback
578  * @return iterator context
579  */
580 struct GNUNET_SENSOR_SensorIteratorContext *
581 GNUNET_SENSOR_iterate_sensors (struct GNUNET_SENSOR_Handle *h,
582     struct GNUNET_TIME_Relative timeout,
583     const char* sensorname, size_t sensorname_len,
584     GNUNET_SENSOR_SensorIteratorCB callback, void *callback_cls)
585 {
586   struct GNUNET_SENSOR_SensorIteratorContext *ic;
587   struct GNUNET_SENSOR_RequestContext *rc;
588   struct GNUNET_MessageHeader *mh;
589
590   ic = GNUNET_new (struct GNUNET_SENSOR_SensorIteratorContext);
591   if (NULL == sensorname)
592   {
593     LOG (GNUNET_ERROR_TYPE_INFO,
594          "Requesting list of sensors from SENSOR service\n");
595     rc =
596         GNUNET_malloc (sizeof (struct GNUNET_SENSOR_RequestContext) +
597                        sizeof (struct GNUNET_MessageHeader));
598     rc->size = sizeof (struct GNUNET_MessageHeader);
599     mh = (struct GNUNET_MessageHeader *) &rc[1];
600     mh->size = htons(sizeof (struct GNUNET_MessageHeader));
601     mh->type = htons(GNUNET_MESSAGE_TYPE_SENSOR_GETALL);
602   }
603   else
604   {
605     LOG (GNUNET_ERROR_TYPE_INFO,
606          "Requesting information on sensor `%s' from SENSOR service\n",
607          sensorname);
608     rc =
609         GNUNET_malloc (sizeof (struct GNUNET_SENSOR_RequestContext) +
610                        sizeof (struct GNUNET_MessageHeader) +
611                        sensorname_len);
612     rc->size = sizeof (struct GNUNET_MessageHeader) + sensorname_len;
613     mh = (struct GNUNET_MessageHeader *) &rc[1];
614     mh->size = htons(rc->size);
615     mh->type = htons(GNUNET_MESSAGE_TYPE_SENSOR_GET);
616     memcpy(&mh[1], sensorname, sensorname_len);
617   }
618   ic->h = h;
619   ic->rc = rc;
620   ic->callback = callback;
621   ic->callback_cls = callback_cls;
622   ic->timeout = GNUNET_TIME_relative_to_absolute (timeout);
623   ic->timeout_task =
624       GNUNET_SCHEDULER_add_delayed (timeout, &signal_sensor_iteration_timeout, ic);
625   rc->cont = &sensor_iterator_start_receive;
626   rc->cont_cls = ic;
627   GNUNET_CONTAINER_DLL_insert_tail (h->rc_head, h->rc_tail, rc);
628   GNUNET_CONTAINER_DLL_insert_tail (h->ic_head,
629             h->ic_tail,
630             ic);
631   trigger_transmit (h);
632   return ic;
633 }
634
635 /* end of sensor_api.c */