2 This file is part of GNUnet.
3 (C) 2009 Christian Grothoff (and other contributing authors)
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.
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.
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.
22 * @file sensordashboard/gnunet-service-sensordashboard.c
23 * @brief Service collecting sensor readings from peers
24 * @author Omar Tarabai
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"
37 * Context of a connected client peer
39 struct ClientPeerContext
45 struct ClientPeerContext *prev;
50 struct ClientPeerContext *next;
53 * GNUnet Peer identity
55 struct GNUNET_PeerIdentity peerid;
58 * Handle to the cadet channel
60 struct GNUNET_CADET_Channel *ch;
63 * CADET transmit handle if we requested a transmission
65 struct GNUNET_CADET_TransmitHandle *th;
68 * Head of DLL of pending messages to be sent to client
70 struct PendingMessage *pm_head;
73 * Tail of DLL of pending messages to be sent to client
75 struct PendingMessage *pm_tail;
78 * Are we in the process of destroying this context?
85 * Message queued to be sent to a client stored in a DLL
93 struct PendingMessage *prev;
98 struct PendingMessage *next;
101 * Actual queued message
103 struct GNUNET_MessageHeader *msg;
108 * Carries a single reading from a sensor
110 struct ClientSensorReading
114 * Sensor this reading is related to
116 struct GNUNET_SENSOR_SensorInfo *sensor;
119 * Timestamp of taking the reading
121 struct GNUNET_TIME_Absolute timestamp;
137 * Path to sensor definition directory
139 static char *sensor_dir;
142 * Global hashmap of defined sensors
144 static struct GNUNET_CONTAINER_MultiHashMap *sensors;
147 * Handle to CADET service
149 static struct GNUNET_CADET_Handle *cadet;
152 * Handle to the peerstore service connection
154 static struct GNUNET_PEERSTORE_Handle *peerstore;
157 * Name of the subsystem used to store sensor values received from remote peers
160 static char *values_subsystem = "sensordashboard-values";
163 * Name of the subsystem used to store anomaly reports received from remote
166 static char *anomalies_subsystem = "sensordashboard-anomalies";
169 * Head of a DLL of all connected client peers
171 static struct ClientPeerContext *cp_head;
174 * Tail of a DLL of all connected client peers
176 static struct ClientPeerContext *cp_tail;
179 * Parameter that defines the complexity of the proof-of-work
181 static long long unsigned int pow_matching_bits;
185 * Trigger sending next pending message to the given client peer if any.
187 * @param cp client peer context struct
190 trigger_send_next_msg (struct ClientPeerContext *cp);
194 * Destroy a given client peer context
196 * @param cp client peer context
199 destroy_clientpeer (struct ClientPeerContext *cp)
201 struct PendingMessage *pm;
203 cp->destroying = GNUNET_YES;
206 GNUNET_CADET_notify_transmit_ready_cancel (cp->th);
212 GNUNET_CONTAINER_DLL_remove (cp->pm_head, cp->pm_tail, pm);
213 GNUNET_free (pm->msg);
219 GNUNET_CADET_channel_destroy (cp->ch);
227 * Task run during shutdown.
233 cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
235 struct ClientPeerContext *cp;
240 GNUNET_CONTAINER_DLL_remove (cp_head, cp_tail, cp);
241 destroy_clientpeer (cp);
246 GNUNET_CADET_disconnect (cadet);
249 if (NULL != peerstore)
251 GNUNET_PEERSTORE_disconnect (peerstore, GNUNET_YES);
254 GNUNET_SENSOR_destroy_sensors (sensors);
255 if (NULL != sensor_dir)
257 GNUNET_free (sensor_dir);
260 GNUNET_SCHEDULER_shutdown ();
265 * Function called whenever a channel is destroyed. Should clean up
266 * any associated state.
268 * It must NOT call #GNUNET_CADET_channel_destroy on the channel.
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
276 cadet_channel_destroyed (void *cls, const struct GNUNET_CADET_Channel *channel,
279 struct ClientPeerContext *cp = channel_ctx;
281 if (GNUNET_YES == cp->destroying)
284 GNUNET_CONTAINER_DLL_remove (cp_head, cp_tail, cp);
285 destroy_clientpeer (cp);
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.
295 * A call to #GNUNET_CADET_channel_destroy causes the channel to be ignored. In
296 * this case the handler MUST return NULL.
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.
304 * @return initial channel context for the channel
305 * (can be NULL -- that's not an error)
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)
312 struct ClientPeerContext *cp;
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);
319 cp->peerid = *initiator;
321 cp->destroying = GNUNET_NO;
322 GNUNET_CONTAINER_DLL_insert (cp_head, cp_tail, cp);
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.
332 * Perform the actual sending of the message to client peer.
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
340 do_send_msg (void *cls, size_t size, void *buf)
342 struct ClientPeerContext *cp = cls;
343 struct PendingMessage *pm;
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)
352 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
353 _("Error trying to send a message to peer `%s'.\n"),
354 GNUNET_i2s (&cp->peerid));
357 memcpy (buf, pm->msg, msg_size);
358 GNUNET_free (pm->msg);
360 trigger_send_next_msg (cp);
366 * Trigger sending next pending message to the given client peer if any.
368 * @param cp client peer context struct
371 trigger_send_next_msg (struct ClientPeerContext *cp)
373 struct PendingMessage *pm;
375 if (NULL == cp->pm_head)
381 GNUNET_CADET_notify_transmit_ready (cp->ch, GNUNET_YES,
382 GNUNET_TIME_UNIT_FOREVER_REL,
383 ntohs (pm->msg->size), &do_send_msg,
389 * Add a new message to the queue to be sent to the given client peer.
391 * @param msg Message to be queued
392 * @param cp Client peer context
395 queue_msg (struct GNUNET_MessageHeader *msg, struct ClientPeerContext *cp)
397 struct PendingMessage *pm;
399 pm = GNUNET_new (struct PendingMessage);
402 GNUNET_CONTAINER_DLL_insert_tail (cp->pm_head, cp->pm_tail, pm);
403 trigger_send_next_msg (cp);
408 * Called with any anomaly report received from a peer.
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.
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).
422 handle_anomaly_report (void *cls, struct GNUNET_CADET_Channel *channel,
424 const struct GNUNET_MessageHeader *message)
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;
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))
442 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
443 "Received invalid anomaly report from peer `%s'.\n",
444 GNUNET_i2s (&cp->peerid));
446 return GNUNET_SYSERR;
449 GNUNET_CONTAINER_multihashmap_get (sensors,
450 &anomaly_msg->sensorname_hash);
454 return GNUNET_SYSERR;
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;
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,
468 GNUNET_free (anomaly_entry);
469 GNUNET_CADET_receive_done (channel);
475 * Iterate over defined sensors, creates and sends brief sensor information to
476 * given client peer over CADET.
478 * @param cls closure, the client peer
479 * @param key sensor key
480 * @param value sensor value
481 * @return #GNUNET_YES to continue iteration
484 send_sensor_brief (void *cls, const struct GNUNET_HashCode *key, void *value)
486 struct ClientPeerContext *cp = cls;
487 struct GNUNET_SENSOR_SensorInfo *sensor = value;
488 struct GNUNET_SENSOR_SensorBriefMessage *msg;
489 uint16_t sensorname_size;
492 /* Create message struct */
493 sensorname_size = strlen (sensor->name) + 1;
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);
504 queue_msg ((struct GNUNET_MessageHeader *) msg, cp);
510 * Called with any sensor list request received.
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.
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).
524 handle_sensor_list_req (void *cls, struct GNUNET_CADET_Channel *channel,
526 const struct GNUNET_MessageHeader *message)
528 struct ClientPeerContext *cp = *channel_ctx;
529 struct GNUNET_MessageHeader *end_msg;
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);
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);
546 * Parses a sensor reading message struct
548 * @param msg message header received
549 * @param sensors multihashmap of loaded sensors
550 * @return sensor reading struct or NULL if error
552 static struct ClientSensorReading *
553 parse_reading_message (const struct GNUNET_MessageHeader *msg,
554 struct GNUNET_CONTAINER_MultiHashMap *sensors)
558 struct GNUNET_SENSOR_ValueMessage *vm;
559 struct GNUNET_SENSOR_SensorInfo *sensor;
560 struct ClientSensorReading *reading;
562 msg_size = ntohs (msg->size);
563 if (msg_size < sizeof (struct GNUNET_SENSOR_ValueMessage))
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)
575 sensor = GNUNET_CONTAINER_multihashmap_get (sensors, &vm->sensorname_hash);
578 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
579 "Unknown sensor name in reading message.\n");
582 if ((sensor->version_minor != ntohs (vm->sensorversion_minor)) ||
583 (sensor->version_major != ntohs (vm->sensorversion_major)))
585 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
586 "Sensor version mismatch in reading message.\n");
589 if (0 == strcmp (sensor->expected_datatype, "numeric") &&
590 sizeof (double) != value_size)
592 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
593 "Invalid value size for a numerical sensor.\n");
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);
606 * Called with any sensor reading messages received from CADET.
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.
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).
620 handle_sensor_reading (void *cls, struct GNUNET_CADET_Channel *channel,
622 const struct GNUNET_MessageHeader *message)
624 struct ClientPeerContext *cp = *channel_ctx;
625 struct ClientSensorReading *reading;
627 reading = parse_reading_message (message, sensors);
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;
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);
652 * Create a message with full information about sensor
654 * @param sensorname Name of sensor requested
655 * @return Message ready to be sent to client or NULL on error
657 static struct GNUNET_SENSOR_SensorFullMessage *
658 create_full_sensor_msg (char *sensorname)
660 struct GNUNET_HashCode key;
661 struct GNUNET_SENSOR_SensorInfo *sensor;
662 struct GNUNET_SENSOR_SensorFullMessage *msg;
664 char *sensorscript_path;
665 uint64_t sensorname_size;
666 uint64_t sensorfile_size;
667 uint64_t sensorscriptname_size;
668 uint64_t sensorscript_size;
672 GNUNET_CRYPTO_hash (sensorname, strlen (sensorname) + 1, &key);
673 sensor = GNUNET_CONTAINER_multihashmap_get (sensors, &key);
676 GNUNET_asprintf (&sensor_path,
681 GNUNET_DISK_file_size (sensor_path,
686 GNUNET_free (sensor_dir);
687 GNUNET_free (sensor_path);
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)
697 GNUNET_asprintf (&sensorscript_path,
702 sensor->ext_process);
704 GNUNET_DISK_file_size (sensorscript_path,
708 sensorscriptname_size = strlen (sensor->ext_process) + 1;
710 /* Construct the msg */
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);
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)
728 memcpy (dummy, sensor->ext_process, sensorscriptname_size);
729 dummy += sensorscriptname_size;
730 GNUNET_DISK_fn_read (sensorscript_path, dummy, sensorscript_size);
732 GNUNET_free_non_null (sensorscript_path);
733 GNUNET_free (sensor_path);
739 * Called with any request for full sensor information.
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.
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).
753 handle_sensor_full_req (void *cls, struct GNUNET_CADET_Channel *channel,
755 const struct GNUNET_MessageHeader *message)
757 struct ClientPeerContext *cp = *channel_ctx;
758 struct GNUNET_SENSOR_SensorBriefMessage *sbm = NULL;
759 struct GNUNET_SENSOR_SensorFullMessage *sfm;
761 uint16_t sensorname_size;
763 msg_size = ntohs (message->size);
764 /* parse & error check */
765 if (msg_size > sizeof (struct GNUNET_SENSOR_SensorBriefMessage))
767 sbm = (struct GNUNET_SENSOR_SensorBriefMessage *) message;
768 sensorname_size = ntohs (sbm->name_size);
770 sizeof (struct GNUNET_SENSOR_SensorBriefMessage) + sensorname_size)
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;
780 /* Create and send msg with full sensor info */
781 sfm = create_full_sensor_msg ((char *) &sbm[1]);
784 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
785 "Error creating full sensor info msg for sensor `%s'.\n",
787 return GNUNET_SYSERR;
789 queue_msg ((struct GNUNET_MessageHeader *) sfm, cp);
790 GNUNET_CADET_receive_done (channel);
796 * Process sensordashboard requests.
799 * @param server the initialized server
800 * @param cfg configuration to use
803 run (void *cls, struct GNUNET_SERVER_Handle *server,
804 const struct GNUNET_CONFIGURATION_Handle *cfg)
806 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
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)},
825 static uint32_t cadet_ports[] = {
826 GNUNET_APPLICATION_TYPE_SENSORDASHBOARD,
827 GNUNET_APPLICATION_TYPE_SENSORUPDATE,
828 GNUNET_APPLICATION_TYPE_END
832 GNUNET_CONFIGURATION_get_value_filename (cfg, "SENSOR", "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);
839 GNUNET_CONFIGURATION_get_value_number (cfg, "sensor-reporting",
843 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "sensor-reporting",
844 "POW_MATCHING_BITS");
845 GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
848 if (pow_matching_bits > sizeof (struct GNUNET_HashCode))
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);
858 GNUNET_CADET_connect (cfg, NULL, &cadet_channel_created,
859 &cadet_channel_destroyed, cadet_handlers,
863 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
864 _("Failed to connect to `%s' service.\n"), "CADET");
865 GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
868 peerstore = GNUNET_PEERSTORE_connect (cfg);
869 if (NULL == peerstore)
871 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
872 _("Failed to connect to `%s' service.\n"), "PEERSTORE");
873 GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
876 GNUNET_SERVER_add_handlers (server, handlers);
877 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task,
883 * The main function for the sensordashboard service.
885 * @param argc number of arguments from the command line
886 * @param argv command line arguments
887 * @return 0 ok, 1 on error
890 main (int argc, char *const *argv)
893 GNUNET_SERVICE_run (argc, argv, "sensordashboard",
894 GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1;
897 /* end of gnunet-service-sensordashboard.c */