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