2 This file is part of GNUnet.
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 sensor/sensor_util_lib.c
23 * @brief sensor utilities
24 * @author Omar Tarabai
28 #include "gnunet_util_lib.h"
29 #include "gnunet_sensor_util_lib.h"
30 #include "gnunet_statistics_service.h"
32 #define LOG(kind,...) GNUNET_log_from (kind, "sensor-util",__VA_ARGS__)
35 * Supported sources of sensor information
37 static const char *sources[] = { "gnunet-statistics", "process", NULL };
40 * Supported datatypes of sensor information
42 static const char *datatypes[] = { "numeric", "string", NULL };
45 * Parses a version number string into major and minor
47 * @param version full version string
48 * @param major pointer to parsed major value
49 * @param minor pointer to parsed minor value
50 * @return #GNUNET_OK if parsing went ok, #GNUNET_SYSERR in case of error
53 version_parse (char *version, uint16_t * major, uint16_t * minor)
58 for (; isdigit (*version); version++)
61 majorval += *version - '0';
66 for (; isdigit (*version); version++)
69 minorval += *version - '0';
81 * Load sensor definition from configuration
83 * @param cfg configuration handle
84 * @param sectionname configuration section containing definition
86 static struct GNUNET_SENSOR_SensorInfo *
87 load_sensor_from_cfg (struct GNUNET_CONFIGURATION_Handle *cfg,
88 const char *sectionname)
90 struct GNUNET_SENSOR_SensorInfo *sensor;
94 unsigned long long time_sec;
96 struct GNUNET_CRYPTO_EddsaPublicKey public_key;
98 sensor = GNUNET_new (struct GNUNET_SENSOR_SensorInfo);
101 sensor->name = GNUNET_strdup (sectionname);
104 GNUNET_CONFIGURATION_get_value_string (cfg, sectionname, "VERSION",
107 LOG (GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor version\n"));
108 GNUNET_free (sensor);
112 version_parse (version_str, &(sensor->version_major),
113 &(sensor->version_minor)))
115 LOG (GNUNET_ERROR_TYPE_ERROR,
116 _("Invalid sensor version number, format should be major.minor\n"));
117 GNUNET_free (sensor);
118 GNUNET_free (version_str);
121 GNUNET_free (version_str);
123 GNUNET_CONFIGURATION_get_value_string (cfg, sectionname, "DESCRIPTION",
124 &sensor->description);
127 GNUNET_CONFIGURATION_get_value_string (cfg, sectionname, "CATEGORY",
128 &sensor->category) ||
129 NULL == sensor->category)
131 LOG (GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor category\n"));
132 GNUNET_free (sensor);
137 GNUNET_CONFIGURATION_get_value_yesno (cfg, sectionname, "ENABLED"))
138 sensor->enabled = GNUNET_NO;
140 sensor->enabled = GNUNET_YES;
142 sensor->start_time = NULL;
144 GNUNET_CONFIGURATION_get_value_string (cfg, sectionname, "START_TIME",
147 GNUNET_STRINGS_fancy_time_to_absolute (starttime_str, sensor->start_time);
148 GNUNET_free (starttime_str);
151 sensor->end_time = NULL;
153 GNUNET_CONFIGURATION_get_value_string (cfg, sectionname, "END_TIME",
156 GNUNET_STRINGS_fancy_time_to_absolute (endtime_str, sensor->end_time);
157 GNUNET_free (endtime_str);
161 GNUNET_CONFIGURATION_get_value_number (cfg, sectionname, "INTERVAL",
164 LOG (GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor run interval\n"));
165 GNUNET_free (sensor);
169 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, time_sec);
172 GNUNET_CONFIGURATION_get_value_number (cfg, sectionname, "LIFETIME",
176 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, time_sec);
177 if (sensor->lifetime.rel_value_us < sensor->interval.rel_value_us)
178 LOG (GNUNET_ERROR_TYPE_WARNING,
179 "Lifetime of sensor data is preferred to be higher than interval for sensor `%s'.\n",
183 sensor->lifetime = GNUNET_TIME_UNIT_FOREVER_REL;
187 GNUNET_CONFIGURATION_get_value_choice (cfg, sectionname, "SOURCE",
189 (const char **) &sensor->source))
191 LOG (GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor source\n"));
192 GNUNET_free (sensor);
195 if (sources[0] == sensor->source) //gnunet-statistics
198 GNUNET_CONFIGURATION_get_value_string (cfg, sectionname,
199 "GNUNET_STAT_SERVICE",
200 &sensor->gnunet_stat_service) ||
201 GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, sectionname,
203 &sensor->gnunet_stat_name))
205 LOG (GNUNET_ERROR_TYPE_ERROR,
206 _("Error reading sensor gnunet-statistics source information\n"));
207 GNUNET_free (sensor);
210 sensor->gnunet_stat_get_handle = NULL;
212 else if (sources[1] == sensor->source) //process
215 GNUNET_CONFIGURATION_get_value_string (cfg, sectionname, "EXT_PROCESS",
216 &sensor->ext_process))
218 LOG (GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor process name\n"));
219 GNUNET_free (sensor);
222 GNUNET_CONFIGURATION_get_value_string (cfg, sectionname, "EXT_ARGS",
227 GNUNET_CONFIGURATION_get_value_choice (cfg, sectionname,
228 "EXPECTED_DATATYPE", datatypes,
230 &sensor->expected_datatype))
232 LOG (GNUNET_ERROR_TYPE_ERROR,
233 _("Error reading sensor expected datatype\n"));
234 GNUNET_free (sensor);
237 if (sources[0] == sensor->source && datatypes[0] != sensor->expected_datatype)
239 LOG (GNUNET_ERROR_TYPE_ERROR,
241 ("Invalid expected datatype, gnunet-statistics returns uint64 values\n"));
242 GNUNET_free (sensor);
246 sensor->collection_point = NULL;
247 sensor->report_values = GNUNET_NO;
248 sensor->report_anomalies = GNUNET_NO;
250 GNUNET_CONFIGURATION_get_value_string (cfg, sectionname,
251 "COLLECTION_POINT", &dummy))
254 GNUNET_CRYPTO_eddsa_public_key_from_string (dummy, strlen (dummy),
257 sensor->collection_point = GNUNET_new (struct GNUNET_PeerIdentity);
259 sensor->collection_point->public_key = public_key;
261 GNUNET_CONFIGURATION_get_value_number (cfg, sectionname,
262 "VALUE_COLLECTION_INTERVAL",
265 sensor->report_values = GNUNET_YES;
266 sensor->value_reporting_interval =
267 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, time_sec);
270 GNUNET_CONFIGURATION_get_value_yesno (cfg, sectionname,
272 sensor->report_anomalies = GNUNET_YES;
277 sensor->execution_task = NULL;
279 sensor->running = GNUNET_NO;
285 * Load sensor definition from file
287 * @param filename full path to file containing sensor definition
289 static struct GNUNET_SENSOR_SensorInfo *
290 load_sensor_from_file (const char *filename)
292 struct GNUNET_CONFIGURATION_Handle *sensorcfg;
293 const char *filebasename;
294 struct GNUNET_SENSOR_SensorInfo *sensor;
297 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
299 LOG (GNUNET_ERROR_TYPE_ERROR, _("Failed to access sensor file: %s\n"),
303 //load file as configuration
304 sensorcfg = GNUNET_CONFIGURATION_create ();
305 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_parse (sensorcfg, filename))
307 GNUNET_CONFIGURATION_destroy (sensorcfg);
308 LOG (GNUNET_ERROR_TYPE_ERROR, _("Failed to load sensor definition: %s\n"),
312 //configuration section should be the same as filename
313 filebasename = GNUNET_STRINGS_get_short_name (filename);
314 sensor = load_sensor_from_cfg (sensorcfg, filebasename);
317 GNUNET_CONFIGURATION_destroy (sensorcfg);
320 sensor->def_file = GNUNET_strdup (filename);
321 sensor->cfg = sensorcfg;
327 * Given two version numbers as major and minor, compare them.
329 * @param v1_major First part of first version number
330 * @param v1_minor Second part of first version number
331 * @param v2_major First part of second version number
332 * @param v2_minor Second part of second version number
335 GNUNET_SENSOR_version_compare (uint16_t v1_major, uint16_t v1_minor,
336 uint16_t v2_major, uint16_t v2_minor)
338 if (v1_major == v2_major)
339 return (v1_minor < v2_minor) ? -1 : (v1_minor > v2_minor);
341 return (v1_major < v2_major) ? -1 : (v1_major > v2_major);
346 * Adds a new sensor to given hashmap.
347 * If the same name exist, compares versions and update if old.
349 * @param sensor Sensor structure to add
350 * @param map Hashmap to add to
351 * @return #GNUNET_YES if added
352 * #GNUNET_NO if not added which is not necessarily an error
355 add_sensor_to_hashmap (struct GNUNET_SENSOR_SensorInfo *sensor,
356 struct GNUNET_CONTAINER_MultiHashMap *map)
358 struct GNUNET_HashCode key;
359 struct GNUNET_SENSOR_SensorInfo *existing;
361 GNUNET_CRYPTO_hash (sensor->name, strlen (sensor->name) + 1, &key);
362 existing = GNUNET_CONTAINER_multihashmap_get (map, &key);
363 if (NULL != existing) //sensor with same name already exists
365 if (GNUNET_SENSOR_version_compare
366 (existing->version_major, existing->version_minor,
367 sensor->version_major, sensor->version_minor) >= 0)
369 LOG (GNUNET_ERROR_TYPE_INFO,
370 _("Sensor `%s' already exists with same or newer version\n"),
376 GNUNET_CONTAINER_multihashmap_remove (map, &key, existing); //remove the old version
377 GNUNET_free (existing);
378 LOG (GNUNET_ERROR_TYPE_INFO, "Upgrading sensor `%s' to a newer version\n",
383 GNUNET_CONTAINER_multihashmap_put (map, &key, sensor,
384 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
386 LOG (GNUNET_ERROR_TYPE_ERROR,
387 _("Error adding new sensor `%s' to global hashmap.\n"), sensor->name);
395 * Iterating over files in sensors directory
398 * @param filename complete filename (absolute path)
399 * @return #GNUNET_OK to continue to iterate
402 reload_sensors_dir_cb (void *cls, const char *filename)
404 struct GNUNET_CONTAINER_MultiHashMap *sensors = cls;
405 struct GNUNET_SENSOR_SensorInfo *sensor;
407 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
409 sensor = load_sensor_from_file (filename);
412 LOG (GNUNET_ERROR_TYPE_ERROR, _("Error loading sensor from file: %s\n"),
416 if (GNUNET_YES != add_sensor_to_hashmap (sensor, sensors))
417 LOG (GNUNET_ERROR_TYPE_WARNING,
418 "Could not add sensor `%s' to global hashmap\n", sensor->name);
424 * Get path to the default directory containing the sensor definition files with
425 * a trailing directory separator.
427 * @return Default sensor files directory full path
430 GNUNET_SENSOR_get_default_sensor_dir ()
435 datadir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
436 GNUNET_asprintf (&sensordir, "%ssensors%s", datadir, DIR_SEPARATOR_STR);
437 GNUNET_free (datadir);
443 * Reads sensor definitions from given sensor directory.
445 * @param sensordir Path to sensor directory.
446 * @return a multihashmap of loaded sensors
448 struct GNUNET_CONTAINER_MultiHashMap *
449 GNUNET_SENSOR_load_all_sensors (char *sensor_dir)
451 struct GNUNET_CONTAINER_MultiHashMap *sensors;
453 GNUNET_assert (NULL != sensor_dir);
454 sensors = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
455 LOG (GNUNET_ERROR_TYPE_INFO,
456 "Loading sensor definitions from directory `%s'\n", sensor_dir);
457 GNUNET_assert (GNUNET_YES ==
458 GNUNET_DISK_directory_test (sensor_dir, GNUNET_YES));
459 /* read all files in sensors directory */
460 GNUNET_DISK_directory_scan (sensor_dir, &reload_sensors_dir_cb, sensors);
461 LOG (GNUNET_ERROR_TYPE_INFO, "Loaded %d sensors from directory `%s'\n",
462 GNUNET_CONTAINER_multihashmap_size (sensors), sensor_dir);
468 * Remove sensor execution from scheduler
471 * @param key hash of sensor name, key to hashmap
472 * @param value a `struct GNUNET_SENSOR_SensorInfo *`
473 * @return #GNUNET_YES if we should continue to
478 destroy_sensor (void *cls, const struct GNUNET_HashCode *key, void *value)
480 struct GNUNET_SENSOR_SensorInfo *sensor = value;
482 if (NULL != sensor->execution_task)
484 GNUNET_SCHEDULER_cancel (sensor->execution_task);
485 sensor->execution_task = NULL;
487 if (NULL != sensor->gnunet_stat_get_handle)
489 GNUNET_STATISTICS_get_cancel (sensor->gnunet_stat_get_handle);
490 sensor->gnunet_stat_get_handle = NULL;
492 if (NULL != sensor->ext_cmd)
494 GNUNET_OS_command_stop (sensor->ext_cmd);
495 sensor->ext_cmd = NULL;
497 if (NULL != sensor->cfg)
498 GNUNET_CONFIGURATION_destroy (sensor->cfg);
499 if (NULL != sensor->name)
500 GNUNET_free (sensor->name);
501 if (NULL != sensor->def_file)
502 GNUNET_free (sensor->def_file);
503 if (NULL != sensor->description)
504 GNUNET_free (sensor->description);
505 if (NULL != sensor->category)
506 GNUNET_free (sensor->category);
507 if (NULL != sensor->capabilities)
508 GNUNET_free (sensor->capabilities);
509 if (NULL != sensor->gnunet_stat_service)
510 GNUNET_free (sensor->gnunet_stat_service);
511 if (NULL != sensor->gnunet_stat_name)
512 GNUNET_free (sensor->gnunet_stat_name);
513 if (NULL != sensor->ext_process)
514 GNUNET_free (sensor->ext_process);
515 if (NULL != sensor->ext_args)
516 GNUNET_free (sensor->ext_args);
517 if (NULL != sensor->collection_point)
518 GNUNET_free (sensor->collection_point);
519 GNUNET_free (sensor);
525 * Destroys a group of sensors in a hashmap and the hashmap itself
527 * @param sensors hashmap containing the sensors
530 GNUNET_SENSOR_destroy_sensors (struct GNUNET_CONTAINER_MultiHashMap *sensors)
532 LOG (GNUNET_ERROR_TYPE_DEBUG, "Destroying sensor list.\n");
533 GNUNET_CONTAINER_multihashmap_iterate (sensors, &destroy_sensor, NULL);
534 GNUNET_CONTAINER_multihashmap_destroy (sensors);