From e68aa2bf46213e33bf1bc07a335df8aeb5ac01c3 Mon Sep 17 00:00:00 2001 From: Omar Tarabai Date: Thu, 3 Jul 2014 14:06:02 +0000 Subject: [PATCH] moved common sensor functionality to a util lib --- src/include/gnunet_protocols.h | 5 + src/include/gnunet_sensor_service.h | 157 +------ src/include/gnunet_sensor_util_lib.h | 215 +++++++++ src/sensor/Makefile.am | 13 +- src/sensor/gnunet-service-sensor-reporting.c | 12 +- src/sensor/gnunet-service-sensor.c | 393 +--------------- src/sensor/sensor.h | 1 + src/sensor/sensor_util_lib.c | 424 ++++++++++++++++++ src/sensordashboard/Makefile.am | 3 +- .../gnunet-service-sensordashboard.c | 29 ++ 10 files changed, 704 insertions(+), 548 deletions(-) create mode 100644 src/include/gnunet_sensor_util_lib.h create mode 100644 src/sensor/sensor_util_lib.c diff --git a/src/include/gnunet_protocols.h b/src/include/gnunet_protocols.h index 371115ada..06e906622 100644 --- a/src/include/gnunet_protocols.h +++ b/src/include/gnunet_protocols.h @@ -2421,6 +2421,11 @@ extern "C" */ #define GNUNET_MESSAGE_TYPE_SENSOR_END 803 +/** + * Message carrying a single sensor reading + */ +#define GNUNET_MESSAGE_TYPE_SENSOR_READING 804 + /******************************************************************************* * PEERSTORE message types diff --git a/src/include/gnunet_sensor_service.h b/src/include/gnunet_sensor_service.h index 1bfed345a..f81248b28 100644 --- a/src/include/gnunet_sensor_service.h +++ b/src/include/gnunet_sensor_service.h @@ -43,158 +43,6 @@ extern "C" */ struct GNUNET_SENSOR_Handle; -/** - * Structure containing sensor definition - */ -struct SensorInfo -{ - - /** - * The configuration handle - * carrying sensor information - */ - struct GNUNET_CONFIGURATION_Handle *cfg; - - /* - * Sensor name - */ - char *name; - - /* - * Path to definition file - */ - char *def_file; - - /* - * First part of version number - */ - uint16_t version_major; - - /* - * Second part of version number - */ - uint16_t version_minor; - - /* - * Sensor description - */ - char *description; - - /* - * Sensor currently enabled - */ - int enabled; - - /* - * Category under which the sensor falls (e.g. tcp, datastore) - */ - char *category; - - /* - * When does the sensor become active - */ - struct GNUNET_TIME_Absolute *start_time; - - /* - * When does the sensor expire - */ - struct GNUNET_TIME_Absolute *end_time; - - /* - * Time interval to collect sensor information (e.g. every 1 min) - */ - struct GNUNET_TIME_Relative interval; - - /* - * Lifetime of an information sample after which it is deleted from storage - * If not supplied, will default to the interval value - */ - struct GNUNET_TIME_Relative lifetime; - - /* - * A set of required peer capabilities for the sensor to collect meaningful information (e.g. ipv6) - */ - char *capabilities; - - /* - * Either "gnunet-statistics" or external "process" - */ - char *source; - - /* - * Name of the GNUnet service that is the source for the gnunet-statistics entry - */ - char *gnunet_stat_service; - - /* - * Name of the gnunet-statistics entry - */ - char *gnunet_stat_name; - - /** - * Handle to statistics get request (OR GNUNET_SCHEDULER_NO_TASK) - */ - struct GNUNET_STATISTICS_GetHandle *gnunet_stat_get_handle; - - /* - * Name of the external process to be executed - */ - char *ext_process; - - /* - * Arguments to be passed to the external process - */ - char *ext_args; - - /* - * Handle to the external process - */ - struct GNUNET_OS_CommandHandle *ext_cmd; - - /* - * Did we already receive a value - * from the currently running external - * proccess ? #GNUNET_YES / #GNUNET_NO - */ - int ext_cmd_value_received; - - /* - * The output datatype to be expected - */ - char *expected_datatype; - - /* - * Peer-identity of peer running collection point - */ - struct GNUNET_PeerIdentity *collection_point; - - /* - * Time interval to send sensor information to collection point (e.g. every 30 mins) - */ - struct GNUNET_TIME_Relative collection_interval; - - /* - * Flag specifying if value is to be communicated to the p2p network - */ - int p2p_report; - - /* - * Time interval to communicate value to the p2p network - */ - struct GNUNET_TIME_Relative p2p_interval; - - /* - * Execution task (OR GNUNET_SCHEDULER_NO_TASK) - */ - GNUNET_SCHEDULER_TaskIdentifier execution_task; - - /* - * Is the sensor being executed - */ - int running; - -}; - /** * Structure containing brief info about sensor */ @@ -232,6 +80,11 @@ GNUNET_NETWORK_STRUCT_BEGIN struct GNUNET_SENSOR_Reading { + /** + * GNUNET general message header + */ + struct GNUNET_MessageHeader *header; + /** * Size of the sensor name value, allocated * at position 0 after this struct diff --git a/src/include/gnunet_sensor_util_lib.h b/src/include/gnunet_sensor_util_lib.h new file mode 100644 index 000000000..15fb61b4c --- /dev/null +++ b/src/include/gnunet_sensor_util_lib.h @@ -0,0 +1,215 @@ +/* + This file is part of GNUnet. + (C) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file sensor/sensor_util_lib.c + * @brief senor utilities + * @author Omar Tarabai + */ + +#ifndef GNUNET_SENSOR_UTIL_LIB_H +#define GNUNET_SENSOR_UTIL_LIB_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +/** + * Structure containing sensor definition + */ +struct SensorInfo +{ + + /** + * The configuration handle + * carrying sensor information + */ + struct GNUNET_CONFIGURATION_Handle *cfg; + + /* + * Sensor name + */ + char *name; + + /* + * Path to definition file + */ + char *def_file; + + /* + * First part of version number + */ + uint16_t version_major; + + /* + * Second part of version number + */ + uint16_t version_minor; + + /* + * Sensor description + */ + char *description; + + /* + * Sensor currently enabled + */ + int enabled; + + /* + * Category under which the sensor falls (e.g. tcp, datastore) + */ + char *category; + + /* + * When does the sensor become active + */ + struct GNUNET_TIME_Absolute *start_time; + + /* + * When does the sensor expire + */ + struct GNUNET_TIME_Absolute *end_time; + + /* + * Time interval to collect sensor information (e.g. every 1 min) + */ + struct GNUNET_TIME_Relative interval; + + /* + * Lifetime of an information sample after which it is deleted from storage + * If not supplied, will default to the interval value + */ + struct GNUNET_TIME_Relative lifetime; + + /* + * A set of required peer capabilities for the sensor to collect meaningful information (e.g. ipv6) + */ + char *capabilities; + + /* + * Either "gnunet-statistics" or external "process" + */ + char *source; + + /* + * Name of the GNUnet service that is the source for the gnunet-statistics entry + */ + char *gnunet_stat_service; + + /* + * Name of the gnunet-statistics entry + */ + char *gnunet_stat_name; + + /** + * Handle to statistics get request (OR GNUNET_SCHEDULER_NO_TASK) + */ + struct GNUNET_STATISTICS_GetHandle *gnunet_stat_get_handle; + + /* + * Name of the external process to be executed + */ + char *ext_process; + + /* + * Arguments to be passed to the external process + */ + char *ext_args; + + /* + * Handle to the external process + */ + struct GNUNET_OS_CommandHandle *ext_cmd; + + /* + * Did we already receive a value + * from the currently running external + * proccess ? #GNUNET_YES / #GNUNET_NO + */ + int ext_cmd_value_received; + + /* + * The output datatype to be expected + */ + char *expected_datatype; + + /* + * Peer-identity of peer running collection point + */ + struct GNUNET_PeerIdentity *collection_point; + + /* + * Time interval to send sensor information to collection point (e.g. every 30 mins) + */ + struct GNUNET_TIME_Relative collection_interval; + + /* + * Flag specifying if value is to be communicated to the p2p network + */ + int p2p_report; + + /* + * Time interval to communicate value to the p2p network + */ + struct GNUNET_TIME_Relative p2p_interval; + + /* + * Execution task (OR GNUNET_SCHEDULER_NO_TASK) + */ + GNUNET_SCHEDULER_TaskIdentifier execution_task; + + /* + * Is the sensor being executed + */ + int running; + +}; + +/** + * Reads sensor definitions from local data files + * + * @return a multihashmap of loaded sensors + */ +struct GNUNET_CONTAINER_MultiHashMap * +GNUNET_SENSOR_load_all_sensors (); + +/* + * Get path to the directory containing the sensor definition files + * + * @return sensor files directory + */ +char * +GNUNET_SENSOR_get_sensor_dir (); + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +/* ifndef GNUNET_SENSOR_UTIL_LIB_H */ +#endif +/* end of gnunet_sensor_util_lib.h */ diff --git a/src/sensor/Makefile.am b/src/sensor/Makefile.am index e16e41ee5..a9b703cbd 100644 --- a/src/sensor/Makefile.am +++ b/src/sensor/Makefile.am @@ -24,7 +24,8 @@ libexec_PROGRAMS = \ gnunet-service-sensor lib_LTLIBRARIES = \ - libgnunetsensor.la + libgnunetsensor.la \ + libgnunetsensorutil.la gnunet_sensor_SOURCES = \ gnunet-sensor.c @@ -38,6 +39,7 @@ gnunet_service_sensor_SOURCES = \ gnunet-service-sensor-analysis.c \ gnunet-service-sensor-reporting.c gnunet_service_sensor_LDADD = \ + libgnunetsensorutil.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/peerstore/libgnunetpeerstore.la \ @@ -51,6 +53,15 @@ libgnunetsensor_la_LIBADD = \ libgnunetsensor_la_LDFLAGS = \ $(GNUNET_LDFLAGS) +libgnunetsensorutil_la_SOURCES = \ + sensor_util_lib.c +libgnunetsensorutil_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la +libgnunetsensorutil_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) +libgnunetsensorutil_la_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la + plugin_LTLIBRARIES = \ libgnunet_plugin_sensor_model_gaussian.la diff --git a/src/sensor/gnunet-service-sensor-reporting.c b/src/sensor/gnunet-service-sensor-reporting.c index 6c8a05490..7b32c7f6c 100644 --- a/src/sensor/gnunet-service-sensor-reporting.c +++ b/src/sensor/gnunet-service-sensor-reporting.c @@ -305,11 +305,13 @@ construct_reading_message (struct ReportingContext *rc, sensorname_size + rc->last_value_size; ret = GNUNET_malloc (total_size); - ret->sensorname_size = sensorname_size; - ret->sensorversion_major = rc->sensor->version_major; - ret->sensorversion_minor = rc->sensor->version_minor; - ret->timestamp = rc->timestamp; - ret->value_size = rc->last_value_size; + ret->header->size = htons (total_size); + ret->header->type = htons (GNUNET_MESSAGE_TYPE_SENSOR_READING); + ret->sensorname_size = GNUNET_htobe64 (sensorname_size); + ret->sensorversion_major = htons (rc->sensor->version_major); + ret->sensorversion_minor = htons (rc->sensor->version_minor); + ret->timestamp = GNUNET_htobe64 (rc->timestamp); + ret->value_size = GNUNET_htobe64 (rc->last_value_size); dummy = &ret[1]; memcpy (dummy, rc->sensor->name, sensorname_size); dummy += sensorname_size; diff --git a/src/sensor/gnunet-service-sensor.c b/src/sensor/gnunet-service-sensor.c index 0e5133d6f..b41d8906c 100644 --- a/src/sensor/gnunet-service-sensor.c +++ b/src/sensor/gnunet-service-sensor.c @@ -30,11 +30,6 @@ #include "gnunet_statistics_service.h" #include "gnunet_peerstore_service.h" -/** - * Minimum sensor execution interval (in seconds) - */ -#define MIN_INTERVAL 30 - /** * Our configuration. */ @@ -45,16 +40,6 @@ static const struct GNUNET_CONFIGURATION_Handle *cfg; */ static struct GNUNET_CONTAINER_MultiHashMap *sensors; -/** - * Supported sources of sensor information - */ -static const char *sources[] = { "gnunet-statistics", "process", NULL }; - -/** - * Supported datatypes of sensor information - */ -static const char *datatypes[] = { "numeric", "string", NULL }; - /** * Handle to statistics service */ @@ -190,375 +175,6 @@ handle_client_disconnect (void *cls, { } -/** - * Parses a version number string into major and minor - * - * @param version full version string - * @param major pointer to parsed major value - * @param minor pointer to parsed minor value - * @return #GNUNET_OK if parsing went ok, #GNUNET_SYSERROR in case of error - */ -static int -version_parse(char *version, uint16_t *major, uint16_t *minor) -{ - int majorval = 0; - int minorval = 0; - - for(; isdigit(*version); version++) - { - majorval *= 10; - majorval += *version - '0'; - } - if(*version != '.') - return GNUNET_SYSERR; - version++; - for(; isdigit(*version); version++) - { - minorval *= 10; - minorval += *version - '0'; - } - if(*version != 0) - return GNUNET_SYSERR; - *major = majorval; - *minor = minorval; - - return GNUNET_OK; -} - -/** - * Load sensor definition from configuration - * - * @param cfg configuration handle - * @param sectionname configuration section containing definition - */ -static struct SensorInfo * -load_sensor_from_cfg(struct GNUNET_CONFIGURATION_Handle *cfg, const char *sectionname) -{ - struct SensorInfo *sensor; - char *version_str; - char *starttime_str; - char *endtime_str; - unsigned long long time_sec; - char *dummy; - struct GNUNET_CRYPTO_EddsaPublicKey public_key; - - sensor = GNUNET_new(struct SensorInfo); - //name - sensor->name = GNUNET_strdup(sectionname); - //version - if(GNUNET_OK != GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "VERSION", &version_str)) - { - GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor version\n")); - GNUNET_free(sensor); - return NULL; - } - if(GNUNET_OK != version_parse(version_str, &(sensor->version_major), &(sensor->version_minor))) - { - GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Invalid sensor version number, format should be major.minor\n")); - GNUNET_free(sensor); - GNUNET_free(version_str); - return NULL; - } - GNUNET_free(version_str); - //description - GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "DESCRIPTION", &sensor->description); - //category - if(GNUNET_OK != GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "CATEGORY", &sensor->category) || - NULL == sensor->category) - { - GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor category\n")); - GNUNET_free(sensor); - return NULL; - } - //enabled - if(GNUNET_NO == GNUNET_CONFIGURATION_get_value_yesno(cfg, sectionname, "ENABLED")) - sensor->enabled = GNUNET_NO; - else - sensor->enabled = GNUNET_YES; - //start time - sensor->start_time = NULL; - if(GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "START_TIME", &starttime_str)) - { - GNUNET_STRINGS_fancy_time_to_absolute(starttime_str, sensor->start_time); - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Start time loaded: `%s'. Parsed: %d\n", starttime_str, (NULL != sensor->start_time)); - GNUNET_free(starttime_str); - } - //end time - sensor->end_time = NULL; - if(GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "END_TIME", &endtime_str)) - { - GNUNET_STRINGS_fancy_time_to_absolute(endtime_str, sensor->end_time); - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "End time loaded: `%s'. Parsed: %d\n", endtime_str, (NULL != sensor->end_time)); - GNUNET_free(endtime_str); - } - //interval - if(GNUNET_OK != GNUNET_CONFIGURATION_get_value_number(cfg, sectionname, "INTERVAL", &time_sec)) - { - GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor run interval\n")); - GNUNET_free(sensor); - return NULL; - } - if(time_sec < MIN_INTERVAL) - { - GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Sensor run interval too low (%" PRIu64 " < %d)\n"), - time_sec, MIN_INTERVAL); - GNUNET_free(sensor); - return NULL; - } - sensor->interval = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, time_sec); - //lifetime - if(GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg, sectionname, "LIFETIME", &time_sec)) - { - sensor->lifetime = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, time_sec); - if (sensor->lifetime.rel_value_us < sensor->interval.rel_value_us) - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Lifetime of sensor data is preferred to be higher than interval for sensor `%s'.\n", - sensor->name); - } - else - sensor->lifetime = sensor->interval; - //capabilities TODO - //source - if(GNUNET_OK != GNUNET_CONFIGURATION_get_value_choice(cfg, sectionname, "SOURCE", sources, (const char **)&sensor->source)) - { - GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor source\n")); - GNUNET_free(sensor); - return NULL; - } - if(sources[0] == sensor->source) //gnunet-statistics - { - if(GNUNET_OK != GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "GNUNET_STAT_SERVICE", &sensor->gnunet_stat_service) || - GNUNET_OK != GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "GNUNET_STAT_NAME", &sensor->gnunet_stat_name)) - { - GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor gnunet-statistics source information\n")); - GNUNET_free(sensor); - return NULL; - } - sensor->gnunet_stat_get_handle = NULL; - } - else if(sources[1] == sensor->source) //process - { - if(GNUNET_OK != GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "EXT_PROCESS", &sensor->ext_process)) - { - GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor process name\n")); - GNUNET_free(sensor); - return NULL; - } - GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "EXT_ARGS", &sensor->ext_args); - } - //expected datatype - if(GNUNET_OK != GNUNET_CONFIGURATION_get_value_choice(cfg, sectionname, "EXPECTED_DATATYPE", datatypes, (const char **)&sensor->expected_datatype)) - { - GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor expected datatype\n")); - GNUNET_free(sensor); - return NULL; - } - if(sources[0] == sensor->source && datatypes[0] != sensor->expected_datatype) - { - GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Invalid expected datatype, gnunet-statistics returns uint64 values\n")); - GNUNET_free(sensor); - return NULL; - } - //reporting mechanism - if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "COLLECTION_POINT", &dummy)) - { - if(GNUNET_OK != GNUNET_CONFIGURATION_get_value_number(cfg, sectionname, "COLLECTION_INTERVAL", &time_sec)) - { - GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor collection interval\n")); - } - else - { - sensor->collection_interval = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, time_sec); - if (GNUNET_OK == GNUNET_CRYPTO_eddsa_public_key_from_string(dummy, strlen(dummy), &public_key)) - { - sensor->collection_point = GNUNET_new(struct GNUNET_PeerIdentity); - sensor->collection_point->public_key = public_key; - } - } - } - sensor->p2p_report = GNUNET_NO; - if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno(cfg, sectionname, "P2P_REPORT")) - { - if(GNUNET_OK != GNUNET_CONFIGURATION_get_value_number(cfg, sectionname, "P2P_INTERVAL", &time_sec)) - { - GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor p2p reporting interval\n")); - } - else - { - sensor->p2p_interval = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, time_sec); - sensor->p2p_report = GNUNET_YES; - } - } - //execution task - sensor->execution_task = GNUNET_SCHEDULER_NO_TASK; - //running - sensor->running = GNUNET_NO; - - return sensor; -} - -/** - * Load sensor definition from file - * - * @param filename full path to file containing sensor definition - */ -static struct SensorInfo * -load_sensor_from_file(const char *filename) -{ - struct GNUNET_CONFIGURATION_Handle *sensorcfg; - const char *filebasename; - struct SensorInfo *sensor; - - //test file - if(GNUNET_YES != GNUNET_DISK_file_test(filename)) - { - GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Failed to access sensor file: %s\n"), filename); - return NULL; - } - //load file as configuration - sensorcfg = GNUNET_CONFIGURATION_create(); - if(GNUNET_SYSERR == GNUNET_CONFIGURATION_parse(sensorcfg, filename)) - { - GNUNET_CONFIGURATION_destroy(sensorcfg); - GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Failed to load sensor definition: %s\n"), filename); - return NULL; - } - //configuration section should be the same as filename - filebasename = GNUNET_STRINGS_get_short_name(filename); - sensor = load_sensor_from_cfg(sensorcfg, filebasename); - if(NULL == sensor) - { - GNUNET_CONFIGURATION_destroy(sensorcfg); - return NULL; - } - sensor->def_file = GNUNET_strdup(filename); - sensor->cfg = sensorcfg; - - return sensor; -} - -/** - * Compares version numbers of two sensors - * - * @param s1 first sensor - * @param s2 second sensor - * @return 1: s1 > s2, 0: s1 == s2, -1: s1 < s2 - */ -static int -sensor_version_compare(struct SensorInfo *s1, struct SensorInfo *s2) -{ - if(s1->version_major == s2->version_major) - return (s1->version_minor < s2->version_minor) ? -1 : (s1->version_minor > s2->version_minor); - else - return (s1->version_major < s2->version_major) ? -1 : (s1->version_major > s2->version_major); -} - -/** - * Adds a new sensor to given hashmap. - * If the same name exist, compares versions and update if old. - * - * @param sensor Sensor structure to add - * @param map Hashmap to add to - * @return #GNUNET_YES if added, #GNUNET_NO if not added which is not necessarily an error - */ -static int -add_sensor_to_hashmap(struct SensorInfo *sensor, struct GNUNET_CONTAINER_MultiHashMap *map) -{ - struct GNUNET_HashCode key; - struct SensorInfo *existing; - - GNUNET_CRYPTO_hash(sensor->name, strlen(sensor->name), &key); - existing = GNUNET_CONTAINER_multihashmap_get(map, &key); - if(NULL != existing) //sensor with same name already exists - { - if(sensor_version_compare(existing, sensor) >= 0) //same or newer version already exist - { - GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Sensor `%s' already exists with same or newer version\n"), sensor->name); - return GNUNET_NO; - } - else - { - GNUNET_CONTAINER_multihashmap_remove(map, &key, existing); //remove the old version - GNUNET_free(existing); - GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Upgrading sensor `%s' to a newer version\n", sensor->name); - } - } - if(GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_put(map, &key, sensor, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) - { - GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Error adding new sensor `%s' to global hashmap, this should not happen\n"), sensor->name); - return GNUNET_NO; - } - - return GNUNET_YES; -} - -/** - * Iterating over files in sensors directory - * - * @param cls closure - * @param filename complete filename (absolute path) - * @return #GNUNET_OK to continue to iterate - */ -static int -reload_sensors_dir_cb(void *cls, const char *filename) -{ - struct SensorInfo *sensor; - - if(GNUNET_YES != GNUNET_DISK_file_test(filename)) - return GNUNET_OK; - sensor = load_sensor_from_file(filename); - if(NULL == sensor) - { - GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Error loading sensor from file: %s\n"), filename); - return GNUNET_OK; - } - if(GNUNET_YES == add_sensor_to_hashmap(sensor, sensors)) - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, _("Sensor `%s' added to global hashmap\n"), sensor->name); - else - GNUNET_log(GNUNET_ERROR_TYPE_WARNING, ("Could not add sensor `%s' to global hashmap\n"), sensor->name); - - return GNUNET_OK; -} - -/* - * Get path to the directory containing the sensor definition files - * - * @return sensor files directory - */ -static char * -get_sensor_dir() -{ - char* datadir; - char* sensordir; - - datadir = GNUNET_OS_installation_get_path(GNUNET_OS_IPK_DATADIR); - GNUNET_asprintf(&sensordir, "%ssensors%s", - datadir, DIR_SEPARATOR_STR); - GNUNET_free(datadir); - - return sensordir; -} - -/** - * Reads sensor definitions from data files - * - */ -static void -reload_sensors() -{ - char* sensordir; - - sensordir = get_sensor_dir(); - GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Reloading sensor definitions from directory `%s'\n"), sensordir); - GNUNET_assert(GNUNET_YES == GNUNET_DISK_directory_test(sensordir, GNUNET_YES)); - - //read all files in sensors directory - GNUNET_DISK_directory_scan(sensordir, &reload_sensors_dir_cb, NULL); - GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Loaded %d sensors from directory `%s'\n"), - GNUNET_CONTAINER_multihashmap_size(sensors), sensordir); - GNUNET_free(sensordir); -} - /** * Creates a structure with basic sensor info to be sent to a client * @@ -896,7 +512,7 @@ sensor_run (void *cls, return; sensorinfo->running = GNUNET_YES; GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Starting the execution of sensor `%s'\n", sensorinfo->name); - if(sources[0] == sensorinfo->source) //gnunet-statistics + if(0 == strcmp ("gnunet-statistics", sensorinfo->source)) { sensorinfo->gnunet_stat_get_handle = GNUNET_STATISTICS_get(statistics, sensorinfo->gnunet_stat_service, @@ -906,7 +522,7 @@ sensor_run (void *cls, &sensor_statistics_iterator, sensorinfo); } - else if(sources[1] == sensorinfo->source) + else if(0 == strcmp ("process", sensorinfo->source)) { if(GNUNET_YES == is_path(sensorinfo->ext_process)) { @@ -923,7 +539,7 @@ sensor_run (void *cls, if(GNUNET_SYSERR == check_result) { //search in sensor directory - sensors_dir = get_sensor_dir(); + sensors_dir = GNUNET_SENSOR_get_sensor_dir (); GNUNET_free(process_path); GNUNET_asprintf(&process_path, "%s%s-files%s%s", sensors_dir, @@ -1023,8 +639,7 @@ run (void *cls, }; cfg = c; - sensors = GNUNET_CONTAINER_multihashmap_create(10, GNUNET_NO); - reload_sensors(); + sensors = GNUNET_SENSOR_load_all_sensors (); schedule_all_sensors(); SENSOR_analysis_start(c, sensors); SENSOR_reporting_start(c, sensors); diff --git a/src/sensor/sensor.h b/src/sensor/sensor.h index 9966be951..d64907250 100644 --- a/src/sensor/sensor.h +++ b/src/sensor/sensor.h @@ -24,6 +24,7 @@ */ #include "gnunet_sensor_service.h" +#include "gnunet_sensor_util_lib.h" GNUNET_NETWORK_STRUCT_BEGIN diff --git a/src/sensor/sensor_util_lib.c b/src/sensor/sensor_util_lib.c new file mode 100644 index 000000000..90befe6af --- /dev/null +++ b/src/sensor/sensor_util_lib.c @@ -0,0 +1,424 @@ +/* + This file is part of GNUnet. + (C) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file sensor/sensor_util_lib.c + * @brief senor utilities + * @author Omar Tarabai + */ +#include +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_sensor_util_lib.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "sensor-util",__VA_ARGS__) + +/** + * Minimum sensor execution interval (in seconds) + */ +#define MIN_INTERVAL 30 + +/** + * Supported sources of sensor information + */ +static const char *sources[] = { "gnunet-statistics", "process", NULL }; + +/** + * Supported datatypes of sensor information + */ +static const char *datatypes[] = { "numeric", "string", NULL }; + +/** + * Parses a version number string into major and minor + * + * @param version full version string + * @param major pointer to parsed major value + * @param minor pointer to parsed minor value + * @return #GNUNET_OK if parsing went ok, #GNUNET_SYSERROR in case of error + */ +static int +version_parse(char *version, uint16_t *major, uint16_t *minor) +{ + int majorval = 0; + int minorval = 0; + + for(; isdigit(*version); version++) + { + majorval *= 10; + majorval += *version - '0'; + } + if(*version != '.') + return GNUNET_SYSERR; + version++; + for(; isdigit(*version); version++) + { + minorval *= 10; + minorval += *version - '0'; + } + if(*version != 0) + return GNUNET_SYSERR; + *major = majorval; + *minor = minorval; + + return GNUNET_OK; +} + +/** + * Load sensor definition from configuration + * + * @param cfg configuration handle + * @param sectionname configuration section containing definition + */ +static struct SensorInfo * +load_sensor_from_cfg(struct GNUNET_CONFIGURATION_Handle *cfg, const char *sectionname) +{ + struct SensorInfo *sensor; + char *version_str; + char *starttime_str; + char *endtime_str; + unsigned long long time_sec; + char *dummy; + struct GNUNET_CRYPTO_EddsaPublicKey public_key; + + sensor = GNUNET_new(struct SensorInfo); + //name + sensor->name = GNUNET_strdup(sectionname); + //version + if(GNUNET_OK != GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "VERSION", &version_str)) + { + LOG (GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor version\n")); + GNUNET_free(sensor); + return NULL; + } + if(GNUNET_OK != version_parse(version_str, &(sensor->version_major), &(sensor->version_minor))) + { + LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid sensor version number, format should be major.minor\n")); + GNUNET_free(sensor); + GNUNET_free(version_str); + return NULL; + } + GNUNET_free(version_str); + //description + GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "DESCRIPTION", &sensor->description); + //category + if(GNUNET_OK != GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "CATEGORY", &sensor->category) || + NULL == sensor->category) + { + LOG (GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor category\n")); + GNUNET_free(sensor); + return NULL; + } + //enabled + if(GNUNET_NO == GNUNET_CONFIGURATION_get_value_yesno(cfg, sectionname, "ENABLED")) + sensor->enabled = GNUNET_NO; + else + sensor->enabled = GNUNET_YES; + //start time + sensor->start_time = NULL; + if(GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "START_TIME", &starttime_str)) + { + GNUNET_STRINGS_fancy_time_to_absolute(starttime_str, sensor->start_time); + LOG (GNUNET_ERROR_TYPE_DEBUG, "Start time loaded: `%s'. Parsed: %d\n", starttime_str, (NULL != sensor->start_time)); + GNUNET_free(starttime_str); + } + //end time + sensor->end_time = NULL; + if(GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "END_TIME", &endtime_str)) + { + GNUNET_STRINGS_fancy_time_to_absolute(endtime_str, sensor->end_time); + LOG (GNUNET_ERROR_TYPE_DEBUG, "End time loaded: `%s'. Parsed: %d\n", endtime_str, (NULL != sensor->end_time)); + GNUNET_free(endtime_str); + } + //interval + if(GNUNET_OK != GNUNET_CONFIGURATION_get_value_number(cfg, sectionname, "INTERVAL", &time_sec)) + { + LOG (GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor run interval\n")); + GNUNET_free(sensor); + return NULL; + } + if(time_sec < MIN_INTERVAL) + { + LOG (GNUNET_ERROR_TYPE_ERROR, _("Sensor run interval too low (%" PRIu64 " < %d)\n"), + time_sec, MIN_INTERVAL); + GNUNET_free(sensor); + return NULL; + } + sensor->interval = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, time_sec); + //lifetime + if(GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg, sectionname, "LIFETIME", &time_sec)) + { + sensor->lifetime = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, time_sec); + if (sensor->lifetime.rel_value_us < sensor->interval.rel_value_us) + LOG (GNUNET_ERROR_TYPE_WARNING, + "Lifetime of sensor data is preferred to be higher than interval for sensor `%s'.\n", + sensor->name); + } + else + sensor->lifetime = sensor->interval; + //capabilities TODO + //source + if(GNUNET_OK != GNUNET_CONFIGURATION_get_value_choice(cfg, sectionname, "SOURCE", sources, (const char **)&sensor->source)) + { + LOG (GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor source\n")); + GNUNET_free(sensor); + return NULL; + } + if(sources[0] == sensor->source) //gnunet-statistics + { + if(GNUNET_OK != GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "GNUNET_STAT_SERVICE", &sensor->gnunet_stat_service) || + GNUNET_OK != GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "GNUNET_STAT_NAME", &sensor->gnunet_stat_name)) + { + LOG (GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor gnunet-statistics source information\n")); + GNUNET_free(sensor); + return NULL; + } + sensor->gnunet_stat_get_handle = NULL; + } + else if(sources[1] == sensor->source) //process + { + if(GNUNET_OK != GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "EXT_PROCESS", &sensor->ext_process)) + { + LOG (GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor process name\n")); + GNUNET_free(sensor); + return NULL; + } + GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "EXT_ARGS", &sensor->ext_args); + } + //expected datatype + if(GNUNET_OK != GNUNET_CONFIGURATION_get_value_choice(cfg, sectionname, "EXPECTED_DATATYPE", datatypes, (const char **)&sensor->expected_datatype)) + { + LOG (GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor expected datatype\n")); + GNUNET_free(sensor); + return NULL; + } + if(sources[0] == sensor->source && datatypes[0] != sensor->expected_datatype) + { + LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid expected datatype, gnunet-statistics returns uint64 values\n")); + GNUNET_free(sensor); + return NULL; + } + //reporting mechanism + if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "COLLECTION_POINT", &dummy)) + { + if(GNUNET_OK != GNUNET_CONFIGURATION_get_value_number(cfg, sectionname, "COLLECTION_INTERVAL", &time_sec)) + { + LOG (GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor collection interval\n")); + } + else + { + sensor->collection_interval = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, time_sec); + if (GNUNET_OK == GNUNET_CRYPTO_eddsa_public_key_from_string(dummy, strlen(dummy), &public_key)) + { + sensor->collection_point = GNUNET_new(struct GNUNET_PeerIdentity); + sensor->collection_point->public_key = public_key; + } + } + } + sensor->p2p_report = GNUNET_NO; + if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno(cfg, sectionname, "P2P_REPORT")) + { + if(GNUNET_OK != GNUNET_CONFIGURATION_get_value_number(cfg, sectionname, "P2P_INTERVAL", &time_sec)) + { + LOG (GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor p2p reporting interval\n")); + } + else + { + sensor->p2p_interval = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, time_sec); + sensor->p2p_report = GNUNET_YES; + } + } + //execution task + sensor->execution_task = GNUNET_SCHEDULER_NO_TASK; + //running + sensor->running = GNUNET_NO; + + return sensor; +} + +/** + * Load sensor definition from file + * + * @param filename full path to file containing sensor definition + */ +static struct SensorInfo * +load_sensor_from_file(const char *filename) +{ + struct GNUNET_CONFIGURATION_Handle *sensorcfg; + const char *filebasename; + struct SensorInfo *sensor; + + //test file + if(GNUNET_YES != GNUNET_DISK_file_test(filename)) + { + LOG (GNUNET_ERROR_TYPE_ERROR, _("Failed to access sensor file: %s\n"), filename); + return NULL; + } + //load file as configuration + sensorcfg = GNUNET_CONFIGURATION_create(); + if(GNUNET_SYSERR == GNUNET_CONFIGURATION_parse(sensorcfg, filename)) + { + GNUNET_CONFIGURATION_destroy(sensorcfg); + LOG (GNUNET_ERROR_TYPE_ERROR, _("Failed to load sensor definition: %s\n"), filename); + return NULL; + } + //configuration section should be the same as filename + filebasename = GNUNET_STRINGS_get_short_name(filename); + sensor = load_sensor_from_cfg(sensorcfg, filebasename); + if(NULL == sensor) + { + GNUNET_CONFIGURATION_destroy(sensorcfg); + return NULL; + } + sensor->def_file = GNUNET_strdup(filename); + sensor->cfg = sensorcfg; + + return sensor; +} + +/** + * Compares version numbers of two sensors + * + * @param s1 first sensor + * @param s2 second sensor + * @return 1: s1 > s2, 0: s1 == s2, -1: s1 < s2 + */ +static int +sensor_version_compare(struct SensorInfo *s1, struct SensorInfo *s2) +{ + if(s1->version_major == s2->version_major) + return (s1->version_minor < s2->version_minor) ? -1 : (s1->version_minor > s2->version_minor); + else + return (s1->version_major < s2->version_major) ? -1 : (s1->version_major > s2->version_major); +} + +/** + * Adds a new sensor to given hashmap. + * If the same name exist, compares versions and update if old. + * + * @param sensor Sensor structure to add + * @param map Hashmap to add to + * @return #GNUNET_YES if added, #GNUNET_NO if not added which is not necessarily an error + */ +static int +add_sensor_to_hashmap(struct SensorInfo *sensor, struct GNUNET_CONTAINER_MultiHashMap *map) +{ + struct GNUNET_HashCode key; + struct SensorInfo *existing; + + GNUNET_CRYPTO_hash(sensor->name, strlen(sensor->name), &key); + existing = GNUNET_CONTAINER_multihashmap_get(map, &key); + if(NULL != existing) //sensor with same name already exists + { + if(sensor_version_compare(existing, sensor) >= 0) //same or newer version already exist + { + LOG (GNUNET_ERROR_TYPE_INFO, _("Sensor `%s' already exists with same or newer version\n"), sensor->name); + return GNUNET_NO; + } + else + { + GNUNET_CONTAINER_multihashmap_remove(map, &key, existing); //remove the old version + GNUNET_free(existing); + LOG (GNUNET_ERROR_TYPE_INFO, "Upgrading sensor `%s' to a newer version\n", sensor->name); + } + } + if(GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_put(map, &key, sensor, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) + { + LOG (GNUNET_ERROR_TYPE_ERROR, _("Error adding new sensor `%s' to global hashmap, this should not happen\n"), sensor->name); + return GNUNET_NO; + } + + return GNUNET_YES; +} + +/** + * Iterating over files in sensors directory + * + * @param cls closure + * @param filename complete filename (absolute path) + * @return #GNUNET_OK to continue to iterate + */ +static int +reload_sensors_dir_cb(void *cls, const char *filename) +{ + struct GNUNET_CONTAINER_MultiHashMap *sensors = cls; + struct SensorInfo *sensor; + + if(GNUNET_YES != GNUNET_DISK_file_test(filename)) + return GNUNET_OK; + sensor = load_sensor_from_file(filename); + if(NULL == sensor) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + _("Error loading sensor from file: %s\n"), filename); + return GNUNET_OK; + } + if(GNUNET_YES == add_sensor_to_hashmap(sensor, sensors)) + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Sensor `%s' added to global hashmap\n", sensor->name); + else + LOG (GNUNET_ERROR_TYPE_WARNING, + "Could not add sensor `%s' to global hashmap\n", sensor->name); + + return GNUNET_OK; +} + +/* + * Get path to the directory containing the sensor definition files + * + * @return sensor files directory + */ +char * +GNUNET_SENSOR_get_sensor_dir () +{ + char* datadir; + char* sensordir; + + datadir = GNUNET_OS_installation_get_path(GNUNET_OS_IPK_DATADIR); + GNUNET_asprintf(&sensordir, "%ssensors%s", + datadir, DIR_SEPARATOR_STR); + GNUNET_free(datadir); + + return sensordir; +} + +/** + * Reads sensor definitions from local data files + * + * @return a multihashmap of loaded sensors + */ +struct GNUNET_CONTAINER_MultiHashMap * +GNUNET_SENSOR_load_all_sensors () +{ + char* sensordir; + struct GNUNET_CONTAINER_MultiHashMap *sensors; + + sensors = GNUNET_CONTAINER_multihashmap_create(10, GNUNET_NO); + sensordir = GNUNET_SENSOR_get_sensor_dir (); + LOG (GNUNET_ERROR_TYPE_INFO, + "Loading sensor definitions from directory `%s'\n", sensordir); + GNUNET_assert(GNUNET_YES == GNUNET_DISK_directory_test(sensordir, GNUNET_YES)); + + //read all files in sensors directory + GNUNET_DISK_directory_scan(sensordir, &reload_sensors_dir_cb, sensors); + LOG (GNUNET_ERROR_TYPE_INFO, "Loaded %d sensors from directory `%s'\n", + GNUNET_CONTAINER_multihashmap_size(sensors), sensordir); + GNUNET_free(sensordir); + return sensors; +} diff --git a/src/sensordashboard/Makefile.am b/src/sensordashboard/Makefile.am index 419486ff4..d54da840b 100644 --- a/src/sensordashboard/Makefile.am +++ b/src/sensordashboard/Makefile.am @@ -22,7 +22,7 @@ libexec_PROGRAMS = \ gnunet-service-sensordashboard gnunet_sensordashboard_SOURCES = \ - gnunet-sensordashboard.c + gnunet-sensordashboard.c gnunet_sensordashboard_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) @@ -32,6 +32,7 @@ gnunet_service_sensordashboard_SOURCES = \ gnunet_service_sensordashboard_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/cadet/libgnunetcadet.la \ + $(top_builddir)/src/sensor/libgnunetsensorutil.la \ $(GN_LIBINTL) diff --git a/src/sensordashboard/gnunet-service-sensordashboard.c b/src/sensordashboard/gnunet-service-sensordashboard.c index 5f451844e..91c7e98f5 100644 --- a/src/sensordashboard/gnunet-service-sensordashboard.c +++ b/src/sensordashboard/gnunet-service-sensordashboard.c @@ -28,9 +28,15 @@ #include "gnunet_applications.h" #include "sensordashboard.h" #include "gnunet_cadet_service.h" +#include "gnunet_sensor_util_lib.h" +/** + * Handle to CADET service + */ static struct GNUNET_CADET_Handle *cadet; +static struct GNUNET_CONTAINER_MultiHashMap *sensors; + /** * Task run during shutdown. * @@ -95,6 +101,26 @@ static void *cadet_channel_created (void *cls, return NULL; /* FIXME */ } +/** + * Called with any sensor reading messages received from CADET. + * + * Each time the function must call #GNUNET_CADET_receive_done on the channel + * in order to receive the next message. This doesn't need to be immediate: + * can be delayed if some processing is done on the message. + * + * @param cls Closure (set from #GNUNET_CADET_connect). + * @param channel Connection to the other end. + * @param channel_ctx Place to store local state associated with the channel. + * @param message The actual message. + * @return #GNUNET_OK to keep the channel open, + * #GNUNET_SYSERR to close it (signal serious error). + */ +int sensor_reading_receiver (void *cls, struct GNUNET_CADET_Channel *channel, + void **channel_ctx, const struct GNUNET_MessageHeader *message) +{ + +} + /** * Process sensordashboard requests. * @@ -110,12 +136,15 @@ run (void *cls, struct GNUNET_SERVER_Handle *server, {NULL, NULL, 0, 0} }; static struct GNUNET_CADET_MessageHandler cadet_handlers[] = { + {&sensor_reading_receiver, GNUNET_MESSAGE_TYPE_SENSOR_READING, 0}, {NULL, 0, 0} }; static uint32_t cadet_ports[] = { GNUNET_APPLICATION_TYPE_SENSORDASHBOARD, GNUNET_APPLICATION_TYPE_END }; + sensors = GNUNET_SENSOR_load_all_sensors (); + GNUNET_assert (NULL != sensors); cadet = GNUNET_CADET_connect(cfg, NULL, &cadet_channel_created, -- 2.25.1