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 * Minimum sensor execution interval (in seconds)
37 #define MIN_INTERVAL 30
40 * Supported sources of sensor information
42 static const char *sources[] = { "gnunet-statistics", "process", NULL };
45 * Supported datatypes of sensor information
47 static const char *datatypes[] = { "numeric", "string", NULL };
50 * Parses a version number string into major and minor
52 * @param version full version string
53 * @param major pointer to parsed major value
54 * @param minor pointer to parsed minor value
55 * @return #GNUNET_OK if parsing went ok, #GNUNET_SYSERR in case of error
58 version_parse (char *version, uint16_t * major, uint16_t * minor)
63 for (; isdigit (*version); version++)
66 majorval += *version - '0';
71 for (; isdigit (*version); version++)
74 minorval += *version - '0';
86 * Load sensor definition from configuration
88 * @param cfg configuration handle
89 * @param sectionname configuration section containing definition
91 static struct GNUNET_SENSOR_SensorInfo *
92 load_sensor_from_cfg (struct GNUNET_CONFIGURATION_Handle *cfg,
93 const char *sectionname)
95 struct GNUNET_SENSOR_SensorInfo *sensor;
99 unsigned long long time_sec;
101 struct GNUNET_CRYPTO_EddsaPublicKey public_key;
103 sensor = GNUNET_new (struct GNUNET_SENSOR_SensorInfo);
106 sensor->name = GNUNET_strdup (sectionname);
109 GNUNET_CONFIGURATION_get_value_string (cfg, sectionname, "VERSION",
112 LOG (GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor version\n"));
113 GNUNET_free (sensor);
117 version_parse (version_str, &(sensor->version_major),
118 &(sensor->version_minor)))
120 LOG (GNUNET_ERROR_TYPE_ERROR,
121 _("Invalid sensor version number, format should be major.minor\n"));
122 GNUNET_free (sensor);
123 GNUNET_free (version_str);
126 GNUNET_free (version_str);
128 GNUNET_CONFIGURATION_get_value_string (cfg, sectionname, "DESCRIPTION",
129 &sensor->description);
132 GNUNET_CONFIGURATION_get_value_string (cfg, sectionname, "CATEGORY",
133 &sensor->category) ||
134 NULL == sensor->category)
136 LOG (GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor category\n"));
137 GNUNET_free (sensor);
142 GNUNET_CONFIGURATION_get_value_yesno (cfg, sectionname, "ENABLED"))
143 sensor->enabled = GNUNET_NO;
145 sensor->enabled = GNUNET_YES;
147 sensor->start_time = NULL;
149 GNUNET_CONFIGURATION_get_value_string (cfg, sectionname, "START_TIME",
152 GNUNET_STRINGS_fancy_time_to_absolute (starttime_str, sensor->start_time);
153 GNUNET_free (starttime_str);
156 sensor->end_time = NULL;
158 GNUNET_CONFIGURATION_get_value_string (cfg, sectionname, "END_TIME",
161 GNUNET_STRINGS_fancy_time_to_absolute (endtime_str, sensor->end_time);
162 GNUNET_free (endtime_str);
166 GNUNET_CONFIGURATION_get_value_number (cfg, sectionname, "INTERVAL",
169 LOG (GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor run interval\n"));
170 GNUNET_free (sensor);
173 if (time_sec < MIN_INTERVAL)
175 LOG (GNUNET_ERROR_TYPE_ERROR,
176 _("Sensor run interval too low (%" PRIu64 " < %d)\n"), time_sec,
178 GNUNET_free (sensor);
182 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, time_sec);
185 GNUNET_CONFIGURATION_get_value_number (cfg, sectionname, "LIFETIME",
189 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, time_sec);
190 if (sensor->lifetime.rel_value_us < sensor->interval.rel_value_us)
191 LOG (GNUNET_ERROR_TYPE_WARNING,
192 "Lifetime of sensor data is preferred to be higher than interval for sensor `%s'.\n",
196 sensor->lifetime = GNUNET_TIME_UNIT_FOREVER_REL;
200 GNUNET_CONFIGURATION_get_value_choice (cfg, sectionname, "SOURCE",
202 (const char **) &sensor->source))
204 LOG (GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor source\n"));
205 GNUNET_free (sensor);
208 if (sources[0] == sensor->source) //gnunet-statistics
211 GNUNET_CONFIGURATION_get_value_string (cfg, sectionname,
212 "GNUNET_STAT_SERVICE",
213 &sensor->gnunet_stat_service) ||
214 GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, sectionname,
216 &sensor->gnunet_stat_name))
218 LOG (GNUNET_ERROR_TYPE_ERROR,
219 _("Error reading sensor gnunet-statistics source information\n"));
220 GNUNET_free (sensor);
223 sensor->gnunet_stat_get_handle = NULL;
225 else if (sources[1] == sensor->source) //process
228 GNUNET_CONFIGURATION_get_value_string (cfg, sectionname, "EXT_PROCESS",
229 &sensor->ext_process))
231 LOG (GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor process name\n"));
232 GNUNET_free (sensor);
235 GNUNET_CONFIGURATION_get_value_string (cfg, sectionname, "EXT_ARGS",
240 GNUNET_CONFIGURATION_get_value_choice (cfg, sectionname,
241 "EXPECTED_DATATYPE", datatypes,
243 &sensor->expected_datatype))
245 LOG (GNUNET_ERROR_TYPE_ERROR,
246 _("Error reading sensor expected datatype\n"));
247 GNUNET_free (sensor);
250 if (sources[0] == sensor->source && datatypes[0] != sensor->expected_datatype)
252 LOG (GNUNET_ERROR_TYPE_ERROR,
254 ("Invalid expected datatype, gnunet-statistics returns uint64 values\n"));
255 GNUNET_free (sensor);
259 sensor->collection_point = NULL;
260 sensor->report_values = GNUNET_NO;
261 sensor->report_anomalies = GNUNET_NO;
263 GNUNET_CONFIGURATION_get_value_string (cfg, sectionname,
264 "COLLECTION_POINT", &dummy))
267 GNUNET_CRYPTO_eddsa_public_key_from_string (dummy, strlen (dummy),
270 sensor->collection_point = GNUNET_new (struct GNUNET_PeerIdentity);
272 sensor->collection_point->public_key = public_key;
274 GNUNET_CONFIGURATION_get_value_number (cfg, sectionname,
275 "VALUE_COLLECTION_INTERVAL",
278 sensor->report_values = GNUNET_YES;
279 sensor->value_reporting_interval =
280 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, time_sec);
283 GNUNET_CONFIGURATION_get_value_yesno (cfg, sectionname,
285 sensor->report_anomalies = GNUNET_YES;
290 sensor->execution_task = GNUNET_SCHEDULER_NO_TASK;
292 sensor->running = GNUNET_NO;
298 * Load sensor definition from file
300 * @param filename full path to file containing sensor definition
302 static struct GNUNET_SENSOR_SensorInfo *
303 load_sensor_from_file (const char *filename)
305 struct GNUNET_CONFIGURATION_Handle *sensorcfg;
306 const char *filebasename;
307 struct GNUNET_SENSOR_SensorInfo *sensor;
310 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
312 LOG (GNUNET_ERROR_TYPE_ERROR, _("Failed to access sensor file: %s\n"),
316 //load file as configuration
317 sensorcfg = GNUNET_CONFIGURATION_create ();
318 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_parse (sensorcfg, filename))
320 GNUNET_CONFIGURATION_destroy (sensorcfg);
321 LOG (GNUNET_ERROR_TYPE_ERROR, _("Failed to load sensor definition: %s\n"),
325 //configuration section should be the same as filename
326 filebasename = GNUNET_STRINGS_get_short_name (filename);
327 sensor = load_sensor_from_cfg (sensorcfg, filebasename);
330 GNUNET_CONFIGURATION_destroy (sensorcfg);
333 sensor->def_file = GNUNET_strdup (filename);
334 sensor->cfg = sensorcfg;
340 * Given two version numbers as major and minor, compare them.
342 * @param v1_major First part of first version number
343 * @param v1_minor Second part of first version number
344 * @param v2_major First part of second version number
345 * @param v2_minor Second part of second version number
348 GNUNET_SENSOR_version_compare (uint16_t v1_major, uint16_t v1_minor,
349 uint16_t v2_major, uint16_t v2_minor)
351 if (v1_major == v2_major)
352 return (v1_minor < v2_minor) ? -1 : (v1_minor > v2_minor);
354 return (v1_major < v2_major) ? -1 : (v1_major > v2_major);
359 * Adds a new sensor to given hashmap.
360 * If the same name exist, compares versions and update if old.
362 * @param sensor Sensor structure to add
363 * @param map Hashmap to add to
364 * @return #GNUNET_YES if added
365 * #GNUNET_NO if not added which is not necessarily an error
368 add_sensor_to_hashmap (struct GNUNET_SENSOR_SensorInfo *sensor,
369 struct GNUNET_CONTAINER_MultiHashMap *map)
371 struct GNUNET_HashCode key;
372 struct GNUNET_SENSOR_SensorInfo *existing;
374 GNUNET_CRYPTO_hash (sensor->name, strlen (sensor->name) + 1, &key);
375 existing = GNUNET_CONTAINER_multihashmap_get (map, &key);
376 if (NULL != existing) //sensor with same name already exists
378 if (GNUNET_SENSOR_version_compare
379 (existing->version_major, existing->version_minor,
380 sensor->version_major, sensor->version_minor) >= 0)
382 LOG (GNUNET_ERROR_TYPE_INFO,
383 _("Sensor `%s' already exists with same or newer version\n"),
389 GNUNET_CONTAINER_multihashmap_remove (map, &key, existing); //remove the old version
390 GNUNET_free (existing);
391 LOG (GNUNET_ERROR_TYPE_INFO, "Upgrading sensor `%s' to a newer version\n",
396 GNUNET_CONTAINER_multihashmap_put (map, &key, sensor,
397 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
399 LOG (GNUNET_ERROR_TYPE_ERROR,
400 _("Error adding new sensor `%s' to global hashmap.\n"), sensor->name);
408 * Iterating over files in sensors directory
411 * @param filename complete filename (absolute path)
412 * @return #GNUNET_OK to continue to iterate
415 reload_sensors_dir_cb (void *cls, const char *filename)
417 struct GNUNET_CONTAINER_MultiHashMap *sensors = cls;
418 struct GNUNET_SENSOR_SensorInfo *sensor;
420 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
422 sensor = load_sensor_from_file (filename);
425 LOG (GNUNET_ERROR_TYPE_ERROR, _("Error loading sensor from file: %s\n"),
429 if (GNUNET_YES != add_sensor_to_hashmap (sensor, sensors))
430 LOG (GNUNET_ERROR_TYPE_WARNING,
431 "Could not add sensor `%s' to global hashmap\n", sensor->name);
437 * Get path to the default directory containing the sensor definition files with
438 * a trailing directory separator.
440 * @return Default sensor files directory full path
443 GNUNET_SENSOR_get_default_sensor_dir ()
448 datadir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
449 GNUNET_asprintf (&sensordir, "%ssensors%s", datadir, DIR_SEPARATOR_STR);
450 GNUNET_free (datadir);
456 * Reads sensor definitions from given sensor directory.
458 * @param sensordir Path to sensor directory.
459 * @return a multihashmap of loaded sensors
461 struct GNUNET_CONTAINER_MultiHashMap *
462 GNUNET_SENSOR_load_all_sensors (char *sensor_dir)
464 struct GNUNET_CONTAINER_MultiHashMap *sensors;
466 GNUNET_assert (NULL != sensor_dir);
467 sensors = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
468 LOG (GNUNET_ERROR_TYPE_INFO,
469 "Loading sensor definitions from directory `%s'\n", sensor_dir);
470 GNUNET_assert (GNUNET_YES ==
471 GNUNET_DISK_directory_test (sensor_dir, GNUNET_YES));
472 /* read all files in sensors directory */
473 GNUNET_DISK_directory_scan (sensor_dir, &reload_sensors_dir_cb, sensors);
474 LOG (GNUNET_ERROR_TYPE_INFO, "Loaded %d sensors from directory `%s'\n",
475 GNUNET_CONTAINER_multihashmap_size (sensors), sensor_dir);
481 * Remove sensor execution from scheduler
484 * @param key hash of sensor name, key to hashmap
485 * @param value a `struct GNUNET_SENSOR_SensorInfo *`
486 * @return #GNUNET_YES if we should continue to
491 destroy_sensor (void *cls, const struct GNUNET_HashCode *key, void *value)
493 struct GNUNET_SENSOR_SensorInfo *sensor = value;
495 if (GNUNET_SCHEDULER_NO_TASK != sensor->execution_task)
497 GNUNET_SCHEDULER_cancel (sensor->execution_task);
498 sensor->execution_task = GNUNET_SCHEDULER_NO_TASK;
500 if (NULL != sensor->gnunet_stat_get_handle)
502 GNUNET_STATISTICS_get_cancel (sensor->gnunet_stat_get_handle);
503 sensor->gnunet_stat_get_handle = NULL;
505 if (NULL != sensor->ext_cmd)
507 GNUNET_OS_command_stop (sensor->ext_cmd);
508 sensor->ext_cmd = NULL;
510 if (NULL != sensor->cfg)
511 GNUNET_CONFIGURATION_destroy (sensor->cfg);
512 if (NULL != sensor->name)
513 GNUNET_free (sensor->name);
514 if (NULL != sensor->def_file)
515 GNUNET_free (sensor->def_file);
516 if (NULL != sensor->description)
517 GNUNET_free (sensor->description);
518 if (NULL != sensor->category)
519 GNUNET_free (sensor->category);
520 if (NULL != sensor->capabilities)
521 GNUNET_free (sensor->capabilities);
522 if (NULL != sensor->gnunet_stat_service)
523 GNUNET_free (sensor->gnunet_stat_service);
524 if (NULL != sensor->gnunet_stat_name)
525 GNUNET_free (sensor->gnunet_stat_name);
526 if (NULL != sensor->ext_process)
527 GNUNET_free (sensor->ext_process);
528 if (NULL != sensor->ext_args)
529 GNUNET_free (sensor->ext_args);
530 if (NULL != sensor->collection_point)
531 GNUNET_free (sensor->collection_point);
532 GNUNET_free (sensor);
538 * Destroys a group of sensors in a hashmap and the hashmap itself
540 * @param sensors hashmap containing the sensors
543 GNUNET_SENSOR_destroy_sensors (struct GNUNET_CONTAINER_MultiHashMap *sensors)
545 LOG (GNUNET_ERROR_TYPE_DEBUG, "Destroying sensor list.\n");
546 GNUNET_CONTAINER_multihashmap_iterate (sensors, &destroy_sensor, NULL);
547 GNUNET_CONTAINER_multihashmap_destroy (sensors);