SENSOR service integration
[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
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_INFO,
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   sensor->name = GNUNET_strndup((char *)&im[1], name_len);
436   if(desc_len > 0)
437     sensor->description = GNUNET_strndup((char *)((&im[1]) + name_len), desc_len);
438   sensor->version_major = ntohs(im->version_major);
439   sensor->version_minor = ntohs(im->version_minor);
440   h->in_receive = GNUNET_YES;
441   GNUNET_CLIENT_receive (h->client, &sensor_handler, h,
442                          GNUNET_TIME_absolute_get_remaining (ic->timeout));
443   if (NULL != cb)
444     cb (cb_cls, sensor, NULL);
445 }
446
447 /**
448  * We've transmitted the iteration request.  Now get ready to process
449  * the results (or handle transmission error).
450  *
451  * @param cls the 'struct GNUNET_SENSOR_SensorIteratorContext'
452  * @param emsg error message, NULL if transmission worked
453  */
454 static void
455 sensor_iterator_start_receive (void *cls, const char *emsg)
456 {
457   struct GNUNET_SENSOR_SensorIteratorContext *ic = cls;
458   struct GNUNET_SENSOR_Handle *h = ic->h;
459   GNUNET_SENSOR_SensorIteratorCB cb;
460   void *cb_cls;
461
462   ic->rc = NULL;
463   if (NULL != emsg)
464   {
465     cb = ic->callback;
466     cb_cls = ic->callback_cls;
467     GNUNET_SENSOR_iterate_sensor_cancel (ic);
468     reconnect (h);
469     if (NULL != cb)
470       cb (cb_cls, NULL, emsg);
471     return;
472   }
473   LOG (GNUNET_ERROR_TYPE_DEBUG, "Waiting for response from `%s' service.\n",
474        "SENSOR");
475   ic->request_transmitted = GNUNET_YES;
476   if (GNUNET_NO == h->in_receive)
477   {
478     h->in_receive = GNUNET_YES;
479     GNUNET_CLIENT_receive (h->client, &sensor_handler, h,
480          GNUNET_TIME_absolute_get_remaining (ic->timeout));
481   }
482 }
483
484 /**
485  * Transmit the request at the head of the transmission queue
486  * and trigger continuation (if any).
487  *
488  * @param cls the 'struct GNUNET_SENSOR_Handle' (with the queue)
489  * @param size size of the buffer (0 on error)
490  * @param buf where to copy the message
491  * @return number of bytes copied to buf
492  */
493 static size_t
494 do_transmit (void *cls, size_t size, void *buf)
495 {
496   struct GNUNET_SENSOR_Handle *h = cls;
497   struct GNUNET_SENSOR_RequestContext *rc = h->rc_head;
498   size_t ret;
499
500   h->th = NULL;
501   if (NULL == rc)
502     return 0; /* request was cancelled in the meantime */
503   if (NULL == buf)
504   {
505     /* sensor service died */
506     LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
507          "Failed to transmit message to `%s' service.\n", "SENSOR");
508     GNUNET_CONTAINER_DLL_remove (h->rc_head, h->rc_tail, rc);
509     reconnect (h);
510     if (NULL != rc->cont)
511       rc->cont (rc->cont_cls, _("failed to transmit request (service down?)"));
512     GNUNET_free (rc);
513     return 0;
514   }
515   ret = rc->size;
516   if (size < ret)
517   {
518     /* change in head of queue (i.e. cancel + add), try again */
519     trigger_transmit (h);
520     return 0;
521   }
522   LOG (GNUNET_ERROR_TYPE_DEBUG,
523        "Transmitting request of size %u to `%s' service.\n", ret, "SENSOR");
524   memcpy (buf, &rc[1], ret);
525   GNUNET_CONTAINER_DLL_remove (h->rc_head, h->rc_tail, rc);
526   trigger_transmit (h);
527   if (NULL != rc->cont)
528     rc->cont (rc->cont_cls, NULL);
529   GNUNET_free (rc);
530   return ret;
531 }
532
533 /**
534  * Check if we have a request pending in the transmission queue and are
535  * able to transmit it right now.  If so, schedule transmission.
536  *
537  * @param h handle to the service
538  */
539 static void
540 trigger_transmit (struct GNUNET_SENSOR_Handle *h)
541 {
542   struct GNUNET_SENSOR_RequestContext *rc;
543
544   if (NULL == (rc = h->rc_head))
545     return; /* no requests queued */
546   if (NULL != h->th)
547     return; /* request already pending */
548   if (NULL == h->client)
549   {
550     /* disconnected, try to reconnect */
551     reconnect (h);
552     return;
553   }
554   h->th =
555     GNUNET_CLIENT_notify_transmit_ready (h->client, rc->size,
556            GNUNET_TIME_UNIT_FOREVER_REL,
557            GNUNET_YES,
558            &do_transmit, h);
559 }
560
561 /**
562  * Client asking to iterate all available sensors
563  *
564  * @param h Handle to SENSOR service
565  * @param timeout how long to wait until timing out
566  * @param sensorname information on one sensor only, can be NULL to get all
567  * @param sensorname_len length of the sensorname parameter
568  * @param callback the method to call for each sensor
569  * @param callback_cls closure for callback
570  * @return iterator context
571  */
572 struct GNUNET_SENSOR_SensorIteratorContext *
573 GNUNET_SENSOR_iterate_sensors (struct GNUNET_SENSOR_Handle *h,
574     struct GNUNET_TIME_Relative timeout,
575     const char* sensorname, size_t sensorname_len,
576     GNUNET_SENSOR_SensorIteratorCB callback, void *callback_cls)
577 {
578   struct GNUNET_SENSOR_SensorIteratorContext *ic;
579   struct GNUNET_SENSOR_RequestContext *rc;
580   struct GNUNET_MessageHeader *mh;
581
582   ic = GNUNET_new (struct GNUNET_SENSOR_SensorIteratorContext);
583   if (NULL == sensorname)
584   {
585     LOG (GNUNET_ERROR_TYPE_INFO,
586          "Requesting list of sensors from SENSOR service\n");
587     rc =
588         GNUNET_malloc (sizeof (struct GNUNET_SENSOR_RequestContext) +
589                        sizeof (struct GNUNET_MessageHeader));
590     rc->size = sizeof (struct GNUNET_MessageHeader);
591     mh = (struct GNUNET_MessageHeader *) &rc[1];
592     mh->size = htons(sizeof (struct GNUNET_MessageHeader));
593     mh->type = htons(GNUNET_MESSAGE_TYPE_SENSOR_GETALL);
594   }
595   else
596   {
597     LOG (GNUNET_ERROR_TYPE_INFO,
598          "Requesting information on sensor `%s' from SENSOR service\n",
599          sensorname);
600     rc =
601         GNUNET_malloc (sizeof (struct GNUNET_SENSOR_RequestContext) +
602                        sizeof (struct GNUNET_MessageHeader) +
603                        sensorname_len);
604     rc->size = sizeof (struct GNUNET_MessageHeader) + sensorname_len;
605     mh = (struct GNUNET_MessageHeader *) &rc[1];
606     mh->size = htons(rc->size);
607     mh->type = htons(GNUNET_MESSAGE_TYPE_SENSOR_GET);
608     memcpy(&mh[1], sensorname, sensorname_len);
609   }
610   ic->h = h;
611   ic->rc = rc;
612   ic->callback = callback;
613   ic->callback_cls = callback_cls;
614   ic->timeout = GNUNET_TIME_relative_to_absolute (timeout);
615   ic->timeout_task =
616       GNUNET_SCHEDULER_add_delayed (timeout, &signal_sensor_iteration_timeout, ic);
617   rc->cont = &sensor_iterator_start_receive;
618   rc->cont_cls = ic;
619   GNUNET_CONTAINER_DLL_insert_tail (h->rc_head, h->rc_tail, rc);
620   GNUNET_CONTAINER_DLL_insert_tail (h->ic_head,
621             h->ic_tail,
622             ic);
623   trigger_transmit (h);
624   return ic;
625 }
626
627 /* end of sensor_api.c */