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 senor 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;
299 * Load sensor definition from file
301 * @param filename full path to file containing sensor definition
303 static struct GNUNET_SENSOR_SensorInfo *
304 load_sensor_from_file (const char *filename)
306 struct GNUNET_CONFIGURATION_Handle *sensorcfg;
307 const char *filebasename;
308 struct GNUNET_SENSOR_SensorInfo *sensor;
311 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
313 LOG (GNUNET_ERROR_TYPE_ERROR, _("Failed to access sensor file: %s\n"),
317 //load file as configuration
318 sensorcfg = GNUNET_CONFIGURATION_create ();
319 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_parse (sensorcfg, filename))
321 GNUNET_CONFIGURATION_destroy (sensorcfg);
322 LOG (GNUNET_ERROR_TYPE_ERROR, _("Failed to load sensor definition: %s\n"),
326 //configuration section should be the same as filename
327 filebasename = GNUNET_STRINGS_get_short_name (filename);
328 sensor = load_sensor_from_cfg (sensorcfg, filebasename);
331 GNUNET_CONFIGURATION_destroy (sensorcfg);
334 sensor->def_file = GNUNET_strdup (filename);
335 sensor->cfg = sensorcfg;
341 * Given two version numbers as major and minor, compare them.
343 * @param v1_major First part of first version number
344 * @param v1_minor Second part of first version number
345 * @param v2_major First part of second version number
346 * @param v2_minor Second part of second version number
349 GNUNET_SENSOR_version_compare (uint16_t v1_major, uint16_t v1_minor,
350 uint16_t v2_major, uint16_t v2_minor)
352 if (v1_major == v2_major)
353 return (v1_minor < v2_minor) ? -1 : (v1_minor > v2_minor);
355 return (v1_major < v2_major) ? -1 : (v1_major > v2_major);
360 * Adds a new sensor to given hashmap.
361 * If the same name exist, compares versions and update if old.
363 * @param sensor Sensor structure to add
364 * @param map Hashmap to add to
365 * @return #GNUNET_YES if added
366 * #GNUNET_NO if not added which is not necessarily an error
369 add_sensor_to_hashmap (struct GNUNET_SENSOR_SensorInfo *sensor,
370 struct GNUNET_CONTAINER_MultiHashMap *map)
372 struct GNUNET_HashCode key;
373 struct GNUNET_SENSOR_SensorInfo *existing;
375 GNUNET_CRYPTO_hash (sensor->name, strlen (sensor->name) + 1, &key);
376 existing = GNUNET_CONTAINER_multihashmap_get (map, &key);
377 if (NULL != existing) //sensor with same name already exists
379 if (GNUNET_SENSOR_version_compare
380 (existing->version_major, existing->version_minor,
381 sensor->version_major, sensor->version_minor) >= 0)
383 LOG (GNUNET_ERROR_TYPE_INFO,
384 _("Sensor `%s' already exists with same or newer version\n"),
390 GNUNET_CONTAINER_multihashmap_remove (map, &key, existing); //remove the old version
391 GNUNET_free (existing);
392 LOG (GNUNET_ERROR_TYPE_INFO, "Upgrading sensor `%s' to a newer version\n",
397 GNUNET_CONTAINER_multihashmap_put (map, &key, sensor,
398 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
400 LOG (GNUNET_ERROR_TYPE_ERROR,
401 _("Error adding new sensor `%s' to global hashmap.\n"), sensor->name);
409 * Iterating over files in sensors directory
412 * @param filename complete filename (absolute path)
413 * @return #GNUNET_OK to continue to iterate
416 reload_sensors_dir_cb (void *cls, const char *filename)
418 struct GNUNET_CONTAINER_MultiHashMap *sensors = cls;
419 struct GNUNET_SENSOR_SensorInfo *sensor;
421 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
423 sensor = load_sensor_from_file (filename);
426 LOG (GNUNET_ERROR_TYPE_ERROR, _("Error loading sensor from file: %s\n"),
430 if (GNUNET_YES != add_sensor_to_hashmap (sensor, sensors))
431 LOG (GNUNET_ERROR_TYPE_WARNING,
432 "Could not add sensor `%s' to global hashmap\n", sensor->name);
438 * Get path to the directory containing the sensor definition files with a
439 * trailing directory separator.
441 * @return sensor files directory full path
444 GNUNET_SENSOR_get_sensor_dir ()
449 datadir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
450 GNUNET_asprintf (&sensordir, "%ssensors%s", datadir, DIR_SEPARATOR_STR);
451 GNUNET_free (datadir);
457 * Reads sensor definitions from local data files
459 * @return a multihashmap of loaded sensors
461 struct GNUNET_CONTAINER_MultiHashMap *
462 GNUNET_SENSOR_load_all_sensors ()
465 struct GNUNET_CONTAINER_MultiHashMap *sensors;
467 sensors = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
468 sensordir = GNUNET_SENSOR_get_sensor_dir ();
469 LOG (GNUNET_ERROR_TYPE_INFO,
470 "Loading sensor definitions from directory `%s'\n", sensordir);
471 GNUNET_assert (GNUNET_YES ==
472 GNUNET_DISK_directory_test (sensordir, GNUNET_YES));
473 /* read all files in sensors directory */
474 GNUNET_DISK_directory_scan (sensordir, &reload_sensors_dir_cb, sensors);
475 LOG (GNUNET_ERROR_TYPE_INFO, "Loaded %d sensors from directory `%s'\n",
476 GNUNET_CONTAINER_multihashmap_size (sensors), sensordir);
477 GNUNET_free (sensordir);
483 * Remove sensor execution from scheduler
486 * @param key hash of sensor name, key to hashmap
487 * @param value a `struct GNUNET_SENSOR_SensorInfo *`
488 * @return #GNUNET_YES if we should continue to
493 destroy_sensor (void *cls, const struct GNUNET_HashCode *key, void *value)
495 struct GNUNET_SENSOR_SensorInfo *sensor = value;
497 if (GNUNET_SCHEDULER_NO_TASK != sensor->execution_task)
499 GNUNET_SCHEDULER_cancel (sensor->execution_task);
500 sensor->execution_task = GNUNET_SCHEDULER_NO_TASK;
502 if (NULL != sensor->gnunet_stat_get_handle)
504 GNUNET_STATISTICS_get_cancel (sensor->gnunet_stat_get_handle);
505 sensor->gnunet_stat_get_handle = NULL;
507 if (NULL != sensor->ext_cmd)
509 GNUNET_OS_command_stop (sensor->ext_cmd);
510 sensor->ext_cmd = NULL;
512 if (NULL != sensor->cfg)
513 GNUNET_CONFIGURATION_destroy (sensor->cfg);
514 if (NULL != sensor->name)
515 GNUNET_free (sensor->name);
516 if (NULL != sensor->def_file)
517 GNUNET_free (sensor->def_file);
518 if (NULL != sensor->description)
519 GNUNET_free (sensor->description);
520 if (NULL != sensor->category)
521 GNUNET_free (sensor->category);
522 if (NULL != sensor->capabilities)
523 GNUNET_free (sensor->capabilities);
524 if (NULL != sensor->gnunet_stat_service)
525 GNUNET_free (sensor->gnunet_stat_service);
526 if (NULL != sensor->gnunet_stat_name)
527 GNUNET_free (sensor->gnunet_stat_name);
528 if (NULL != sensor->ext_process)
529 GNUNET_free (sensor->ext_process);
530 if (NULL != sensor->ext_args)
531 GNUNET_free (sensor->ext_args);
532 if (NULL != sensor->collection_point)
533 GNUNET_free (sensor->collection_point);
534 GNUNET_free (sensor);
540 * Destroys a group of sensors in a hashmap and the hashmap itself
542 * @param sensors hashmap containing the sensors
545 GNUNET_SENSOR_destroy_sensors (struct GNUNET_CONTAINER_MultiHashMap *sensors)
547 LOG (GNUNET_ERROR_TYPE_DEBUG, "Destroying sensor list.\n");
548 GNUNET_CONTAINER_multihashmap_iterate (sensors, &destroy_sensor, NULL);
549 GNUNET_CONTAINER_multihashmap_destroy (sensors);