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