sensor: towards update functionality
[oweals/gnunet.git] / src / sensordashboard / gnunet-service-sensordashboard.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009 Christian Grothoff (and other contributing authors)
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 sensordashboard/gnunet-service-sensordashboard.c
23  * @brief Service collecting sensor readings from peers
24  * @author Omar Tarabai
25  */
26 #include <inttypes.h>
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet_applications.h"
30 #include "sensordashboard.h"
31 #include "gnunet_cadet_service.h"
32 #include "gnunet_sensor_util_lib.h"
33 #include "gnunet_peerstore_service.h"
34
35
36 /**
37  * Context of a connected client peer
38  */
39 struct ClientPeerContext
40 {
41
42   /**
43    * DLL
44    */
45   struct ClientPeerContext *prev;
46
47   /*
48    * DLL
49    */
50   struct ClientPeerContext *next;
51
52   /**
53    * GNUnet Peer identity
54    */
55   struct GNUNET_PeerIdentity peerid;
56
57   /**
58    * Handle to the cadet channel
59    */
60   struct GNUNET_CADET_Channel *ch;
61
62   /**
63    * CADET transmit handle if we requested a transmission
64    */
65   struct GNUNET_CADET_TransmitHandle *th;
66
67   /**
68    * Head of DLL of pending messages to be sent to client
69    */
70   struct PendingMessage *pm_head;
71
72   /**
73    * Tail of DLL of pending messages to be sent to client
74    */
75   struct PendingMessage *pm_tail;
76
77   /**
78    * Are we in the process of destroying this context?
79    */
80   int destroying;
81
82 };
83
84 /**
85  * Message queued to be sent to a client stored in a DLL
86  */
87 struct PendingMessage
88 {
89
90   /**
91    * DLL
92    */
93   struct PendingMessage *prev;
94
95   /**
96    * DLL
97    */
98   struct PendingMessage *next;
99
100   /**
101    * Actual queued message
102    */
103   struct GNUNET_MessageHeader *msg;
104
105 };
106
107 /**
108  * Carries a single reading from a sensor
109  */
110 struct ClientSensorReading
111 {
112
113   /**
114    * Sensor this reading is related to
115    */
116   struct GNUNET_SENSOR_SensorInfo *sensor;
117
118   /**
119    * Timestamp of taking the reading
120    */
121   uint64_t timestamp;
122
123   /**
124    * Reading value
125    */
126   void *value;
127
128   /**
129    * Size of @e value
130    */
131   uint16_t value_size;
132
133 };
134
135
136 /**
137  * Global hashmap of defined sensors
138  */
139 static struct GNUNET_CONTAINER_MultiHashMap *sensors;
140
141 /**
142  * Handle to CADET service
143  */
144 static struct GNUNET_CADET_Handle *cadet;
145
146 /**
147  * Handle to the peerstore service connection
148  */
149 static struct GNUNET_PEERSTORE_Handle *peerstore;
150
151 /**
152  * Name of this subsystem to be used for peerstore operations
153  */
154 static char *subsystem = "sensordashboard";
155
156 /**
157  * Head of a DLL of all connected client peers
158  */
159 static struct ClientPeerContext *cp_head;
160
161 /**
162  * Tail of a DLL of all connected client peers
163  */
164 static struct ClientPeerContext *cp_tail;
165
166
167 /**
168  * Trigger sending next pending message to the given client peer if any.
169  *
170  * @param cp client peer context struct
171  */
172 static void
173 trigger_send_next_msg (struct ClientPeerContext *cp);
174
175
176 /**
177  * Destroy a given client peer context
178  *
179  * @param cp client peer context
180  */
181 static void
182 destroy_clientpeer (struct ClientPeerContext *cp)
183 {
184   struct PendingMessage *pm;
185
186   cp->destroying = GNUNET_YES;
187   if (NULL != cp->th)
188   {
189     GNUNET_CADET_notify_transmit_ready_cancel (cp->th);
190     cp->th = NULL;
191   }
192   pm = cp->pm_head;
193   while (NULL != pm)
194   {
195     GNUNET_CONTAINER_DLL_remove (cp->pm_head, cp->pm_tail, pm);
196     GNUNET_free (pm->msg);
197     GNUNET_free (pm);
198     pm = cp->pm_head;
199   }
200   if (NULL != cp->ch)
201   {
202     GNUNET_CADET_channel_destroy (cp->ch);
203     cp->ch = NULL;
204   }
205   GNUNET_free (cp);
206 }
207
208
209 /**
210  * Task run during shutdown.
211  *
212  * @param cls unused
213  * @param tc unused
214  */
215 static void
216 cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
217 {
218   struct ClientPeerContext *cp;
219
220   cp = cp_head;
221   while (NULL != cp)
222   {
223     GNUNET_CONTAINER_DLL_remove (cp_head, cp_tail, cp);
224     destroy_clientpeer (cp);
225     cp = cp_head;
226   }
227   if (NULL != cadet)
228   {
229     GNUNET_CADET_disconnect (cadet);
230     cadet = NULL;
231   }
232   if (NULL != peerstore)
233   {
234     GNUNET_PEERSTORE_disconnect (peerstore, GNUNET_YES);
235     peerstore = NULL;
236   }
237   GNUNET_SENSOR_destroy_sensors (sensors);
238   GNUNET_SCHEDULER_shutdown ();
239 }
240
241
242 /**
243  * Function called whenever a channel is destroyed.  Should clean up
244  * any associated state.
245  *
246  * It must NOT call #GNUNET_CADET_channel_destroy on the channel.
247  *
248  * @param cls closure (set from #GNUNET_CADET_connect)
249  * @param channel connection to the other end (henceforth invalid)
250  * @param channel_ctx place where local state associated
251  *                   with the channel is stored
252  */
253 static void
254 cadet_channel_destroyed (void *cls,
255                          const struct GNUNET_CADET_Channel *channel,
256                          void *channel_ctx)
257 {
258   struct ClientPeerContext *cp = channel_ctx;
259
260   if (GNUNET_YES == cp->destroying)
261     return;
262   cp->ch = NULL;
263   GNUNET_CONTAINER_DLL_remove (cp_head, cp_tail, cp);
264   destroy_clientpeer (cp);
265 }
266
267
268 /**
269  * Method called whenever another peer has added us to a channel
270  * the other peer initiated.
271  * Only called (once) upon reception of data with a message type which was
272  * subscribed to in #GNUNET_CADET_connect.
273  *
274  * A call to #GNUNET_CADET_channel_destroy causes the channel to be ignored. In
275  * this case the handler MUST return NULL.
276  *
277  * @param cls closure
278  * @param channel new handle to the channel
279  * @param initiator peer that started the channel
280  * @param port Port this channel is for.
281  * @param options CadetOption flag field, with all active option bits set to 1.
282  *
283  * @return initial channel context for the channel
284  *         (can be NULL -- that's not an error)
285  */
286 static void *
287 cadet_channel_created (void *cls,
288                        struct GNUNET_CADET_Channel *channel,
289                        const struct GNUNET_PeerIdentity *initiator,
290                        uint32_t port, enum GNUNET_CADET_ChannelOption options)
291 {
292   struct ClientPeerContext *cp;
293
294   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
295               "Received a channel connection from peer `%s'.\n",
296               GNUNET_i2s (initiator));
297   cp = GNUNET_new (struct ClientPeerContext);
298   cp->peerid = *initiator;
299   cp->ch = channel;
300   cp->destroying = GNUNET_NO;
301   GNUNET_CONTAINER_DLL_insert (cp_head, cp_tail, cp);
302   return cp;
303 }
304
305
306 /**
307  * Function called to notify a client about the connection begin ready
308  * to queue more data.  @a buf will be NULL and @a size zero if the
309  * connection was closed for writing in the meantime.
310  *
311  * Perform the actual sending of the message to client peer.
312  *
313  * @param cls closure, a `struct ClientPeerContext *`
314  * @param size number of bytes available in @a buf
315  * @param buf where the callee should write the message
316  * @return number of bytes written to @a buf
317  */
318 static size_t
319 do_send_msg (void *cls, size_t size, void *buf)
320 {
321   struct ClientPeerContext *cp = cls;
322   struct PendingMessage *pm;
323   size_t msg_size;
324
325   cp->th = NULL;
326   pm = cp->pm_head;
327   msg_size = ntohs (pm->msg->size);
328   GNUNET_CONTAINER_DLL_remove (cp->pm_head, cp->pm_tail, pm);
329   if (NULL == buf || size < msg_size)
330   {
331     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
332                 _("Error trying to send a message to peer `%s'.\n"),
333                 GNUNET_i2s (&cp->peerid));
334     return 0;
335   }
336   memcpy (buf, pm->msg, msg_size);
337   GNUNET_free (pm->msg);
338   GNUNET_free (pm);
339   trigger_send_next_msg (cp);
340   return msg_size;
341 }
342
343
344 /**
345  * Trigger sending next pending message to the given client peer if any.
346  *
347  * @param cp client peer context struct
348  */
349 static void
350 trigger_send_next_msg (struct ClientPeerContext *cp)
351 {
352   struct PendingMessage *pm;
353
354   if (NULL == cp->pm_head)
355     return;
356   if (NULL != cp->th)
357     return;
358   pm = cp->pm_head;
359   cp->th = GNUNET_CADET_notify_transmit_ready (cp->ch,
360                                                GNUNET_YES,
361                                                GNUNET_TIME_UNIT_FOREVER_REL,
362                                                ntohs (pm->msg->size),
363                                                &do_send_msg,
364                                                cp);
365 }
366
367
368 /**
369  * Add a new message to the queue to be sent to the given client peer.
370  *
371  * @param msg Message to be queued
372  * @param cp Client peer context
373  */
374 static void
375 queue_msg (struct GNUNET_MessageHeader *msg, struct ClientPeerContext *cp)
376 {
377   struct PendingMessage *pm;
378
379   pm = GNUNET_new (struct PendingMessage);
380   pm->msg = msg;
381   GNUNET_CONTAINER_DLL_insert_tail (cp->pm_head, cp->pm_tail, pm);
382   trigger_send_next_msg (cp);
383 }
384
385
386 /**
387  * Iterate over defined sensors, creates and sends brief sensor information to
388  * given client peer over CADET.
389  *
390  * @param cls closure, the client peer
391  * @param key sensor key
392  * @param value sensor value
393  * @return #GNUNET_YES to continue iteration
394  */
395 static int
396 send_sensor_brief (void *cls,
397                    const struct GNUNET_HashCode *key,
398                    void *value)
399 {
400   struct ClientPeerContext *cp = cls;
401   struct GNUNET_SENSOR_SensorInfo *sensor = value;
402   struct GNUNET_SENSOR_SensorBriefMessage *msg;
403   uint16_t sensorname_size;
404   uint16_t total_size;
405
406   /* Create message struct */
407   sensorname_size = strlen (sensor->name) + 1;
408   total_size = sizeof (struct GNUNET_SENSOR_SensorBriefMessage) +
409                sensorname_size;
410   msg = GNUNET_malloc (total_size);
411   msg->header.size = htons (total_size);
412   msg->header.type = htons (GNUNET_MESSAGE_TYPE_SENSOR_BRIEF);
413   msg->name_size = htons (sensorname_size);
414   msg->version_major = htons (sensor->version_major);
415   msg->version_minor = htons (sensor->version_minor);
416   memcpy (&msg[1], sensor->name, sensorname_size);
417   /* Queue the msg */
418   queue_msg ((struct GNUNET_MessageHeader *)msg, cp);
419   return GNUNET_YES;
420 }
421
422
423 /**
424  * Called with any sensor list request received.
425  *
426  * Each time the function must call #GNUNET_CADET_receive_done on the channel
427  * in order to receive the next message. This doesn't need to be immediate:
428  * can be delayed if some processing is done on the message.
429  *
430  * @param cls Closure (set from #GNUNET_CADET_connect).
431  * @param channel Connection to the other end.
432  * @param channel_ctx Place to store local state associated with the channel.
433  * @param message The actual message.
434  * @return #GNUNET_OK to keep the channel open,
435  *         #GNUNET_SYSERR to close it (signal serious error).
436  */
437 static int
438 handle_sensor_list_req (void *cls,
439                         struct GNUNET_CADET_Channel *channel,
440                         void **channel_ctx,
441                         const struct GNUNET_MessageHeader *message)
442 {
443   struct ClientPeerContext *cp = *channel_ctx;
444   struct GNUNET_MessageHeader *end_msg;
445
446   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
447               "Received a sensor list request from peer `%s'.\n",
448               GNUNET_i2s (&cp->peerid));
449   GNUNET_CONTAINER_multihashmap_iterate (sensors,
450                                          &send_sensor_brief,
451                                          cp);
452   end_msg = GNUNET_new (struct GNUNET_MessageHeader);
453   end_msg->size = htons (sizeof (struct GNUNET_MessageHeader));
454   end_msg->type = htons (GNUNET_MESSAGE_TYPE_SENSOR_END);
455   queue_msg (end_msg, cp);
456   GNUNET_CADET_receive_done (channel);
457   return GNUNET_OK;
458 }
459
460
461 /**
462  * Parses a sensor reading message struct
463  *
464  * @param msg message header received
465  * @param sensors multihashmap of loaded sensors
466  * @return sensor reading struct or NULL if error
467  */
468 static struct ClientSensorReading *
469 parse_reading_message (const struct GNUNET_MessageHeader *msg,
470                        struct GNUNET_CONTAINER_MultiHashMap *sensors)
471 {
472   uint16_t msg_size;
473   struct GNUNET_SENSOR_ReadingMessage *rm;
474   uint16_t sensorname_size;
475   uint16_t value_size;
476   void *dummy;
477   char *sensorname;
478   struct GNUNET_HashCode key;
479   struct GNUNET_SENSOR_SensorInfo *sensor;
480   struct ClientSensorReading *reading;
481
482   msg_size = ntohs (msg->size);
483   if (msg_size < sizeof (struct GNUNET_SENSOR_ReadingMessage))
484   {
485     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Invalid reading message size.\n");
486     return NULL;
487   }
488   rm = (struct GNUNET_SENSOR_ReadingMessage *)msg;
489   sensorname_size = ntohs (rm->sensorname_size);
490   value_size = ntohs (rm->value_size);
491   if ((sizeof (struct GNUNET_SENSOR_ReadingMessage)
492       + sensorname_size + value_size) != msg_size)
493   {
494     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Invalid reading message size.\n");
495     return NULL;
496   }
497   dummy = &rm[1];
498   sensorname = GNUNET_malloc (sensorname_size);
499   memcpy (sensorname, dummy, sensorname_size);
500   GNUNET_CRYPTO_hash(sensorname, sensorname_size, &key);
501   GNUNET_free (sensorname);
502   sensor = GNUNET_CONTAINER_multihashmap_get (sensors, &key);
503   if (NULL == sensor)
504   {
505     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
506         "Unknown sensor name in reading message.\n");
507     return NULL;
508   }
509   if ((sensor->version_minor != ntohs (rm->sensorversion_minor)) ||
510       (sensor->version_major != ntohs (rm->sensorversion_major)))
511   {
512     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
513                 "Sensor version mismatch in reading message.\n");
514     return NULL;
515   }
516   if (0 == strcmp (sensor->expected_datatype, "numeric") &&
517       sizeof (double) != value_size)
518   {
519     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
520                 "Invalid value size for a numerical sensor.\n");
521     return NULL;
522   }
523   reading = GNUNET_new (struct ClientSensorReading);
524   reading->sensor = sensor;
525   reading->timestamp = GNUNET_be64toh (rm->timestamp);
526   reading->value_size = value_size;
527   reading->value = GNUNET_malloc (value_size);
528   dummy += sensorname_size;
529   memcpy (reading->value, dummy, value_size);
530   return reading;
531 }
532
533
534 /**
535  * Called with any sensor reading messages received from CADET.
536  *
537  * Each time the function must call #GNUNET_CADET_receive_done on the channel
538  * in order to receive the next message. This doesn't need to be immediate:
539  * can be delayed if some processing is done on the message.
540  *
541  * @param cls Closure (set from #GNUNET_CADET_connect).
542  * @param channel Connection to the other end.
543  * @param channel_ctx Place to store local state associated with the channel.
544  * @param message The actual message.
545  * @return #GNUNET_OK to keep the channel open,
546  *         #GNUNET_SYSERR to close it (signal serious error).
547  */
548 static int
549 handle_sensor_reading (void *cls,
550                        struct GNUNET_CADET_Channel *channel,
551                        void **channel_ctx,
552                        const struct GNUNET_MessageHeader *message)
553 {
554   struct ClientPeerContext *cp = *channel_ctx;
555   struct ClientSensorReading *reading;
556
557   reading = parse_reading_message (message, sensors);
558   if (NULL == reading)
559   {
560     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
561                 "Received an invalid sensor reading from peer `%s'.\n",
562                 GNUNET_i2s (&cp->peerid));
563     return GNUNET_SYSERR;
564   }
565   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
566               "Received a sensor reading from peer `%s':\n"
567               "# Sensor name: `%s'\n"
568               "# Timestamp: %" PRIu64 "\n"
569               "# Value size: %" PRIu64 ".\n",
570               GNUNET_i2s (&cp->peerid),
571               reading->sensor->name,
572               reading->timestamp,
573               reading->value_size);
574   GNUNET_PEERSTORE_store (peerstore, subsystem, &cp->peerid,
575                           reading->sensor->name, reading->value,
576                           reading->value_size, GNUNET_TIME_UNIT_FOREVER_ABS,
577                           GNUNET_PEERSTORE_STOREOPTION_MULTIPLE, NULL, NULL);
578   GNUNET_free (reading->value);
579   GNUNET_free (reading);
580   GNUNET_CADET_receive_done (channel);
581   return GNUNET_OK;
582 }
583
584
585 /**
586  * Create a message with full information about sensor
587  *
588  * @param sensorname Name of sensor requested
589  * @return Message ready to be sent to client or NULL on error
590  */
591 static struct GNUNET_SENSOR_SensorFullMessage *
592 create_full_sensor_msg (char *sensorname)
593 {
594   struct GNUNET_HashCode key;
595   struct GNUNET_SENSOR_SensorInfo *sensor;
596   struct GNUNET_SENSOR_SensorFullMessage *msg;
597   char *sensor_dir;
598   char *sensor_path;
599   char *sensorscript_path;
600   uint64_t sensorfile_size;
601   uint64_t sensorscriptname_size;
602   uint64_t sensorscript_size;
603   uint64_t total_size;
604   void *dummy;
605
606   GNUNET_CRYPTO_hash (sensorname, strlen (sensorname) + 1, &key);
607   sensor = GNUNET_CONTAINER_multihashmap_get (sensors, &key);
608   if (NULL == sensor)
609     return NULL;
610   sensor_dir = GNUNET_SENSOR_get_sensor_dir ();
611   GNUNET_asprintf (&sensor_path, "%s%s",
612                    sensor_dir, sensorname);
613   if (GNUNET_OK != GNUNET_DISK_file_size (sensor_path,
614                                           &sensorfile_size,
615                                           GNUNET_NO,
616                                           GNUNET_YES))
617   {
618     GNUNET_free (sensor_dir);
619     GNUNET_free (sensor_path);
620     return NULL;
621   }
622   sensorscript_size = 0;
623   sensorscriptname_size = 0;
624   /* Test if there is an associated script */
625   if (NULL != sensor->ext_process)
626   {
627     GNUNET_asprintf (&sensorscript_path, "%s%s-files%s%s",
628                      sensor_dir,
629                      sensor->name,
630                      DIR_SEPARATOR_STR,
631                      sensor->ext_process);
632     if (GNUNET_OK == GNUNET_DISK_file_size (sensorscript_path,
633                                             &sensorscript_size,
634                                             GNUNET_NO,
635                                             GNUNET_YES))
636       sensorscriptname_size = strlen (sensor->ext_process) + 1;
637   }
638   /* Construct the msg */
639   total_size = sizeof (struct GNUNET_SENSOR_SensorFullMessage) +
640                sensorfile_size + sensorscriptname_size + sensorscript_size;
641   msg = GNUNET_malloc (total_size);
642   msg->header.size = htons (total_size);
643   msg->header.type = htons (GNUNET_MESSAGE_TYPE_SENSOR_FULL);
644   msg->cfg_size = htons (sensorfile_size);
645   msg->scriptname_size = htons (sensorscriptname_size);
646   msg->script_size = htons (sensorscript_size);
647   dummy = &msg[1];
648   GNUNET_DISK_fn_read (sensor_path, dummy, sensorfile_size);
649   dummy += sensorfile_size;
650   if (sensorscriptname_size > 0)
651   {
652     memcpy (dummy, sensor->ext_process, sensorscriptname_size);
653     dummy += sensorscriptname_size;
654     GNUNET_DISK_fn_read (sensorscript_path, dummy, sensorscript_size);
655   }
656   GNUNET_free (sensor_dir);
657   GNUNET_free (sensor_path);
658   GNUNET_free (sensorscript_path);
659   return msg;
660 }
661
662
663 /**
664  * Called with any request for full sensor information.
665  *
666  * Each time the function must call #GNUNET_CADET_receive_done on the channel
667  * in order to receive the next message. This doesn't need to be immediate:
668  * can be delayed if some processing is done on the message.
669  *
670  * @param cls Closure (set from #GNUNET_CADET_connect).
671  * @param channel Connection to the other end.
672  * @param channel_ctx Place to store local state associated with the channel.
673  * @param message The actual message.
674  * @return #GNUNET_OK to keep the channel open,
675  *         #GNUNET_SYSERR to close it (signal serious error).
676  */
677 static int
678 handle_sensor_full_req (void *cls,
679                         struct GNUNET_CADET_Channel *channel,
680                         void **channel_ctx,
681                         const struct GNUNET_MessageHeader *message)
682 {
683   struct ClientPeerContext *cp = *channel_ctx;
684   struct GNUNET_SENSOR_SensorBriefMessage *sbm = NULL;
685   struct GNUNET_SENSOR_SensorFullMessage *sfm;
686   uint16_t msg_size;
687   uint16_t sensorname_size;
688
689   msg_size = ntohs (message->size);
690   /* parse & error check */
691   if (msg_size > sizeof (struct GNUNET_SENSOR_SensorBriefMessage))
692   {
693     sbm = (struct GNUNET_SENSOR_SensorBriefMessage *)message;
694     sensorname_size = ntohs (sbm->name_size);
695     if (msg_size != sizeof (struct GNUNET_SENSOR_SensorBriefMessage) +
696                     sensorname_size)
697       sbm = NULL;
698   }
699   if (NULL == sbm)
700   {
701     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
702                 "Received an invalid full sensor request from peer `%s'.\n",
703                 GNUNET_i2s (&cp->peerid));
704     return GNUNET_SYSERR;
705   }
706   /* Create and send msg with full sensor info */
707   sfm = create_full_sensor_msg ((char *)&sbm[1]);
708   if (NULL == sfm)
709   {
710     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
711                 "Error creating full sensor info msg for sensor `%s'.\n",
712                 (char *)&sbm[1]);
713     return GNUNET_SYSERR;
714   }
715   queue_msg ((struct GNUNET_MessageHeader *)sfm, cp);
716   GNUNET_CADET_receive_done (channel);
717   return GNUNET_OK;
718 }
719
720
721 /**
722  * Process sensordashboard requests.
723  *
724  * @param cls closure
725  * @param server the initialized server
726  * @param cfg configuration to use
727  */
728 static void
729 run (void *cls, struct GNUNET_SERVER_Handle *server,
730      const struct GNUNET_CONFIGURATION_Handle *cfg)
731 {
732   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
733       {NULL, NULL, 0, 0}
734   };
735   static struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
736       {&handle_sensor_reading,
737        GNUNET_MESSAGE_TYPE_SENSOR_READING, 0},
738       {&handle_sensor_list_req,
739        GNUNET_MESSAGE_TYPE_SENSOR_LIST_REQ,
740        sizeof (struct GNUNET_MessageHeader)},
741       {&handle_sensor_full_req,
742       GNUNET_MESSAGE_TYPE_SENSOR_FULL_REQ,
743       sizeof (struct GNUNET_MessageHeader)},
744       {NULL, 0, 0}
745   };
746   static uint32_t cadet_ports[] = {
747       GNUNET_APPLICATION_TYPE_SENSORDASHBOARD,
748       GNUNET_APPLICATION_TYPE_SENSORUPDATE,
749       GNUNET_APPLICATION_TYPE_END
750   };
751   sensors = GNUNET_SENSOR_load_all_sensors ();
752   GNUNET_assert (NULL != sensors);
753   cadet = GNUNET_CADET_connect(cfg,
754                                NULL,
755                                &cadet_channel_created,
756                                &cadet_channel_destroyed,
757                                cadet_handlers,
758                                cadet_ports);
759   if (NULL == cadet)
760   {
761     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
762                 _("Failed to connect to `%s' service.\n"), "CADET");
763     GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
764     return;
765   }
766   peerstore = GNUNET_PEERSTORE_connect (cfg);
767   if (NULL == peerstore)
768   {
769     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
770                 _("Failed to connect to `%s' service.\n"), "PEERSTORE");
771     GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
772     return;
773   }
774   GNUNET_SERVER_add_handlers (server, handlers);
775   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task,
776                                 NULL);
777 }
778
779
780 /**
781  * The main function for the sensordashboard service.
782  *
783  * @param argc number of arguments from the command line
784  * @param argv command line arguments
785  * @return 0 ok, 1 on error
786  */
787 int
788 main (int argc, char *const *argv)
789 {
790   return (GNUNET_OK ==
791           GNUNET_SERVICE_run (argc, argv, "sensordashboard",
792                               GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1;
793 }
794
795 /* end of gnunet-service-sensordashboard.c */