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