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, "%s%s", sensor_dir, sensorname);
678 GNUNET_DISK_file_size (sensor_path, &sensorfile_size, GNUNET_NO,
681 GNUNET_free (sensor_dir);
682 GNUNET_free (sensor_path);
685 sensorname_size = strlen (sensorname) + 1;
686 sensorscript_size = 0;
687 sensorscriptname_size = 0;
688 /* Test if there is an associated script */
689 if (NULL != sensor->ext_process)
691 GNUNET_asprintf (&sensorscript_path, "%s%s-files%s%s", sensor_dir,
692 sensor->name, DIR_SEPARATOR_STR, sensor->ext_process);
694 GNUNET_DISK_file_size (sensorscript_path, &sensorscript_size, GNUNET_NO,
697 sensorscriptname_size = strlen (sensor->ext_process) + 1;
700 /* Construct the msg */
702 sizeof (struct GNUNET_SENSOR_SensorFullMessage) + sensorname_size +
703 sensorfile_size + sensorscriptname_size + sensorscript_size;
704 msg = GNUNET_malloc (total_size);
705 msg->header.size = htons (total_size);
706 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SENSOR_FULL);
707 msg->sensorname_size = htons (sensorname_size);
708 msg->sensorfile_size = htons (sensorfile_size);
709 msg->scriptname_size = htons (sensorscriptname_size);
710 msg->scriptfile_size = htons (sensorscript_size);
712 memcpy (dummy, sensorname, sensorname_size);
713 dummy += sensorname_size;
714 GNUNET_DISK_fn_read (sensor_path, dummy, sensorfile_size);
715 dummy += sensorfile_size;
716 if (sensorscriptname_size > 0)
718 memcpy (dummy, sensor->ext_process, sensorscriptname_size);
719 dummy += sensorscriptname_size;
720 GNUNET_DISK_fn_read (sensorscript_path, dummy, sensorscript_size);
721 GNUNET_free (sensorscript_path);
723 GNUNET_free (sensor_path);
729 * Called with any request for full sensor information.
731 * Each time the function must call #GNUNET_CADET_receive_done on the channel
732 * in order to receive the next message. This doesn't need to be immediate:
733 * can be delayed if some processing is done on the message.
735 * @param cls Closure (set from #GNUNET_CADET_connect).
736 * @param channel Connection to the other end.
737 * @param channel_ctx Place to store local state associated with the channel.
738 * @param message The actual message.
739 * @return #GNUNET_OK to keep the channel open,
740 * #GNUNET_SYSERR to close it (signal serious error).
743 handle_sensor_full_req (void *cls, struct GNUNET_CADET_Channel *channel,
745 const struct GNUNET_MessageHeader *message)
747 struct ClientPeerContext *cp = *channel_ctx;
748 struct GNUNET_SENSOR_SensorBriefMessage *sbm = NULL;
749 struct GNUNET_SENSOR_SensorFullMessage *sfm;
751 uint16_t sensorname_size;
753 msg_size = ntohs (message->size);
754 /* parse & error check */
755 if (msg_size > sizeof (struct GNUNET_SENSOR_SensorBriefMessage))
757 sbm = (struct GNUNET_SENSOR_SensorBriefMessage *) message;
758 sensorname_size = ntohs (sbm->name_size);
760 sizeof (struct GNUNET_SENSOR_SensorBriefMessage) + sensorname_size)
765 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
766 "Received an invalid full sensor request from peer `%s'.\n",
767 GNUNET_i2s (&cp->peerid));
768 return GNUNET_SYSERR;
770 /* Create and send msg with full sensor info */
771 sfm = create_full_sensor_msg ((char *) &sbm[1]);
774 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
775 "Error creating full sensor info msg for sensor `%s'.\n",
777 return GNUNET_SYSERR;
779 queue_msg ((struct GNUNET_MessageHeader *) sfm, cp);
780 GNUNET_CADET_receive_done (channel);
786 * Process sensordashboard requests.
789 * @param server the initialized server
790 * @param cfg configuration to use
793 run (void *cls, struct GNUNET_SERVER_Handle *server,
794 const struct GNUNET_CONFIGURATION_Handle *cfg)
796 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
799 static struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
800 {&handle_sensor_reading,
801 GNUNET_MESSAGE_TYPE_SENSOR_READING, 0},
802 {&handle_sensor_list_req,
803 GNUNET_MESSAGE_TYPE_SENSOR_LIST_REQ,
804 sizeof (struct GNUNET_MessageHeader)},
805 {&handle_sensor_full_req,
806 GNUNET_MESSAGE_TYPE_SENSOR_FULL_REQ,
807 sizeof (struct GNUNET_MessageHeader)},
808 {&handle_anomaly_report,
809 GNUNET_MESSAGE_TYPE_SENSOR_ANOMALY_REPORT,
810 sizeof (struct GNUNET_MessageHeader) +
811 sizeof (struct GNUNET_SENSOR_crypto_pow_block) +
812 sizeof (struct GNUNET_SENSOR_AnomalyReportMessage)},
815 static uint32_t cadet_ports[] = {
816 GNUNET_APPLICATION_TYPE_SENSORDASHBOARD,
817 GNUNET_APPLICATION_TYPE_SENSORUPDATE,
818 GNUNET_APPLICATION_TYPE_END
822 GNUNET_CONFIGURATION_get_value_filename (cfg, "SENSOR", "SENSOR_DIR",
824 sensor_dir = GNUNET_SENSOR_get_default_sensor_dir ();
825 sensors = GNUNET_SENSOR_load_all_sensors (sensor_dir);
826 GNUNET_assert (NULL != sensors);
829 GNUNET_CONFIGURATION_get_value_number (cfg, "sensor-reporting",
833 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "sensor-reporting",
834 "POW_MATCHING_BITS");
835 GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
838 if (pow_matching_bits > sizeof (struct GNUNET_HashCode))
840 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
841 "Matching bits value too large (%d > %d).\n", pow_matching_bits,
842 sizeof (struct GNUNET_HashCode));
843 GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
848 GNUNET_CADET_connect (cfg, NULL, &cadet_channel_created,
849 &cadet_channel_destroyed, cadet_handlers,
853 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
854 _("Failed to connect to `%s' service.\n"), "CADET");
855 GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
858 peerstore = GNUNET_PEERSTORE_connect (cfg);
859 if (NULL == peerstore)
861 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
862 _("Failed to connect to `%s' service.\n"), "PEERSTORE");
863 GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
866 GNUNET_SERVER_add_handlers (server, handlers);
867 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task,
873 * The main function for the sensordashboard service.
875 * @param argc number of arguments from the command line
876 * @param argv command line arguments
877 * @return 0 ok, 1 on error
880 main (int argc, char *const *argv)
883 GNUNET_SERVICE_run (argc, argv, "sensordashboard",
884 GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1;
887 /* end of gnunet-service-sensordashboard.c */