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/gnunet-service-sensor_analysis.c
23 * @brief sensor service analysis functionality
24 * @author Omar Tarabai
28 #include "gnunet_util_lib.h"
30 #include "gnunet_statistics_service.h"
31 #include "gnunet_peerstore_service.h"
33 #define LOG(kind,...) GNUNET_log_from (kind, "sensor-monitoring",__VA_ARGS__)
38 static const struct GNUNET_CONFIGURATION_Handle *cfg;
41 * Hashmap of loaded sensor definitions
43 static struct GNUNET_CONTAINER_MultiHashMap *sensors;
46 * Path to sensor definitions directory
48 static char *sensor_dir;
51 * Handle to statistics service
53 static struct GNUNET_STATISTICS_Handle *statistics;
56 * Handle to peerstore service
58 static struct GNUNET_PEERSTORE_Handle *peerstore;
63 static struct GNUNET_PeerIdentity peerid;
67 * Stop the sensor monitoring module
70 SENSOR_monitoring_stop ()
72 if (NULL != statistics)
74 GNUNET_STATISTICS_destroy (statistics, GNUNET_YES);
77 if (NULL != peerstore)
79 GNUNET_PEERSTORE_disconnect (peerstore, GNUNET_YES);
82 if (NULL != sensor_dir)
84 GNUNET_free (sensor_dir);
91 * Change the state of the sensor.
92 * Write the change to file to make it persistent.
94 * @param sensor sensor info struct
95 * @param state new enabled state: #GNUNET_YES / #GNUNET_NO
98 set_sensor_enabled (struct GNUNET_SENSOR_SensorInfo *sensor, int state)
100 LOG (GNUNET_ERROR_TYPE_DEBUG, "Sensor `%s': Setting enabled to %d.\n",
101 sensor->name, state);
102 sensor->enabled = GNUNET_NO;
103 GNUNET_assert (NULL != sensor->cfg);
104 GNUNET_CONFIGURATION_set_value_string (sensor->cfg, sensor->name, "ENABLED",
105 (GNUNET_YES == state) ? "YES" : "NO");
106 GNUNET_CONFIGURATION_write (sensor->cfg, sensor->def_file);
111 * Do a series of checks to determine if sensor should execute
113 * @return #GNUNET_YES / #GNUNET_NO
116 should_run_sensor (struct GNUNET_SENSOR_SensorInfo *sensorinfo)
118 struct GNUNET_TIME_Absolute now;
120 if (GNUNET_NO == sensorinfo->enabled)
122 LOG (GNUNET_ERROR_TYPE_INFO, "Sensor `%s' is disabled, will not run\n",
126 now = GNUNET_TIME_absolute_get ();
127 if (NULL != sensorinfo->start_time &&
128 now.abs_value_us < sensorinfo->start_time->abs_value_us)
130 LOG (GNUNET_ERROR_TYPE_INFO,
131 "Start time for sensor `%s' not reached yet, will not run\n",
135 if (NULL != sensorinfo->end_time &&
136 now.abs_value_us >= sensorinfo->end_time->abs_value_us)
138 LOG (GNUNET_ERROR_TYPE_INFO, "Sensor `%s' expired, disabling.\n",
140 set_sensor_enabled (sensorinfo, GNUNET_NO);
148 * Callback function to process statistic values
150 * @param cls `struct GNUNET_SENSOR_SensorInfo *`
151 * @param ss name of subsystem that created the statistic
152 * @param name the name of the datum
153 * @param value the current value
154 * @param is_persistent #GNUNET_YES if the value is persistent, #GNUNET_NO if not
155 * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
158 sensor_statistics_iterator (void *cls, const char *ss, const char *name,
159 uint64_t value, int is_persistent)
161 struct GNUNET_SENSOR_SensorInfo *sensorinfo = cls;
162 double dvalue = (double) value;
163 struct GNUNET_TIME_Absolute expiry;
165 LOG (GNUNET_ERROR_TYPE_INFO,
166 "Received a value for sensor `%s': %" PRIu64 "\n", sensorinfo->name,
168 expiry = GNUNET_TIME_relative_to_absolute (sensorinfo->lifetime);
169 GNUNET_PEERSTORE_store (peerstore, "sensor", &peerid, sensorinfo->name,
170 &dvalue, sizeof (dvalue), expiry,
171 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE, NULL, NULL);
172 return GNUNET_SYSERR; /* We only want one value */
177 * Continuation called after sensor gets all gnunet statistics values
179 * @param cls `struct GNUNET_SENSOR_SensorInfo *`
180 * @param success #GNUNET_OK if statistics were
181 * successfully obtained, #GNUNET_SYSERR if not.
184 end_sensor_run_stat (void *cls, int success)
186 struct GNUNET_SENSOR_SensorInfo *sensorinfo = cls;
188 sensorinfo->gnunet_stat_get_handle = NULL;
189 sensorinfo->running = GNUNET_NO;
194 * Tries to parse a received sensor value to its
197 * @param value the string value received, should be null terminated
198 * @param sensor sensor information struct
199 * @param ret pointer to parsed value
200 * @return size of new parsed value, 0 for error
203 parse_sensor_value (const char *value, struct GNUNET_SENSOR_SensorInfo *sensor,
212 if (0 == strcmp ("numeric", sensor->expected_datatype))
214 dval = GNUNET_new (double);
216 *dval = strtod (value, &endptr);
220 return sizeof (double);
222 if (0 == strcmp ("string", sensor->expected_datatype))
224 *ret = GNUNET_strdup (value);
225 return strlen (value) + 1;
227 LOG (GNUNET_ERROR_TYPE_ERROR,
228 _("Unknown value type expected by sensor, this should not happen.\n"));
234 * Callback for output of executed sensor process
236 * @param cls `struct GNUNET_SENSOR_SensorInfo *`
237 * @param line line of output from a command, NULL for the end
240 sensor_process_callback (void *cls, const char *line)
242 struct GNUNET_SENSOR_SensorInfo *sensorinfo = cls;
245 struct GNUNET_TIME_Absolute expiry;
249 GNUNET_OS_command_stop (sensorinfo->ext_cmd);
250 sensorinfo->ext_cmd = NULL;
251 sensorinfo->running = GNUNET_NO;
252 sensorinfo->ext_cmd_value_received = GNUNET_NO;
255 if (GNUNET_YES == sensorinfo->ext_cmd_value_received)
256 return; /* We only want one *valid* value */
257 LOG (GNUNET_ERROR_TYPE_INFO, "Received a value for sensor `%s': %s\n",
258 sensorinfo->name, line);
259 valsize = parse_sensor_value (line, sensorinfo, &value);
260 if (valsize == 0) /* invalid value, FIXME: should we disable the sensor now? */
262 LOG (GNUNET_ERROR_TYPE_ERROR,
263 _("Received an invalid value for sensor `%s': %s\n"), sensorinfo->name,
268 sensorinfo->ext_cmd_value_received = GNUNET_YES;
269 expiry = GNUNET_TIME_relative_to_absolute (sensorinfo->lifetime);
270 GNUNET_PEERSTORE_store (peerstore, "sensor", &peerid, sensorinfo->name,
271 value, valsize, expiry,
272 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE, NULL, NULL);
279 * Checks if the given file is a path
281 * @return #GNUNET_YES / #GNUNET_NO
284 is_path (char *filename)
289 filename_len = strlen (filename);
290 for (i = 0; i < filename_len; i++)
292 if (DIR_SEPARATOR == filename[i])
300 * Actual execution of a sensor
302 * @param cls 'struct SensorInfo'
306 sensor_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
308 struct GNUNET_SENSOR_SensorInfo *sensorinfo = cls;
312 sensorinfo->execution_task =
313 GNUNET_SCHEDULER_add_delayed (sensorinfo->interval, &sensor_run,
315 if (GNUNET_YES == sensorinfo->running) //FIXME: should we try to kill?
317 LOG (GNUNET_ERROR_TYPE_WARNING,
318 "Sensor `%s' running for too long, will try again next interval\n",
322 if (GNUNET_NO == should_run_sensor (sensorinfo))
324 sensorinfo->running = GNUNET_YES;
325 LOG (GNUNET_ERROR_TYPE_DEBUG, "Starting the execution of sensor `%s'\n",
327 if (0 == strcmp ("gnunet-statistics", sensorinfo->source))
329 sensorinfo->gnunet_stat_get_handle = GNUNET_STATISTICS_get (statistics, sensorinfo->gnunet_stat_service, sensorinfo->gnunet_stat_name, sensorinfo->interval, //try to get values only for the interval of the sensor
330 &end_sensor_run_stat,
331 &sensor_statistics_iterator,
334 else if (0 == strcmp ("process", sensorinfo->source))
336 if (GNUNET_YES == is_path (sensorinfo->ext_process))
338 LOG (GNUNET_ERROR_TYPE_ERROR,
340 ("Sensor `%s': External process should not be a path, disabling sensor.\n"),
342 set_sensor_enabled (sensorinfo, GNUNET_NO);
345 //check if the process exists in $PATH
346 process_path = GNUNET_strdup (sensorinfo->ext_process);
348 GNUNET_OS_check_helper_binary (process_path, GNUNET_NO, NULL);
349 if (GNUNET_SYSERR == check_result)
351 //search in sensor directory
352 GNUNET_free (process_path);
353 GNUNET_asprintf (&process_path, "%s%s-files%s%s", sensor_dir,
354 sensorinfo->name, DIR_SEPARATOR_STR,
355 sensorinfo->ext_process);
356 GNUNET_free (sensor_dir);
358 GNUNET_OS_check_helper_binary (process_path, GNUNET_NO, NULL);
360 if (GNUNET_SYSERR == check_result)
362 LOG (GNUNET_ERROR_TYPE_ERROR,
364 ("Sensor `%s' process `%s' problem: binary doesn't exist or not executable\n"),
365 sensorinfo->name, sensorinfo->ext_process);
366 set_sensor_enabled (sensorinfo, GNUNET_NO);
367 sensorinfo->running = GNUNET_NO;
368 GNUNET_free (process_path);
371 sensorinfo->ext_cmd_value_received = GNUNET_NO;
372 sensorinfo->ext_cmd =
373 GNUNET_OS_command_run (&sensor_process_callback, sensorinfo,
374 GNUNET_TIME_UNIT_FOREVER_REL, process_path,
375 sensorinfo->ext_process, sensorinfo->ext_args,
377 LOG (GNUNET_ERROR_TYPE_DEBUG, "Process started for sensor `%s'\n",
379 GNUNET_free (process_path);
383 sensorinfo->running = GNUNET_NO;
384 GNUNET_break (0); /* shouldn't happen */
390 * Starts the execution of a sensor
393 * @param key hash of sensor name, key to hashmap (unused)
394 * @param value a `struct GNUNET_SENSOR_SensorInfo *`
395 * @return #GNUNET_YES if we should continue to
400 schedule_sensor (void *cls, const struct GNUNET_HashCode *key, void *value)
402 struct GNUNET_SENSOR_SensorInfo *sensorinfo = value;
404 if (GNUNET_NO == should_run_sensor (sensorinfo))
406 LOG (GNUNET_ERROR_TYPE_DEBUG,
407 "Scheduling sensor `%s' to run after %" PRIu64 " microseconds\n",
408 sensorinfo->name, sensorinfo->interval.rel_value_us);
409 if (GNUNET_SCHEDULER_NO_TASK != sensorinfo->execution_task)
411 LOG (GNUNET_ERROR_TYPE_ERROR,
412 _("Sensor `%s' execution task already set, this should not happen\n"),
416 sensorinfo->execution_task =
417 GNUNET_SCHEDULER_add_delayed (sensorinfo->interval, &sensor_run,
424 * Starts the execution of all enabled sensors
427 schedule_all_sensors ()
429 GNUNET_CONTAINER_multihashmap_iterate (sensors, &schedule_sensor, NULL);
434 * Start the sensor monitoring module
436 * @param c our service configuration
437 * @param sensors multihashmap of loaded sensors
438 * @return #GNUNET_OK if started successfully, #GNUNET_SYSERR otherwise
441 SENSOR_monitoring_start (const struct GNUNET_CONFIGURATION_Handle *c,
442 struct GNUNET_CONTAINER_MultiHashMap *s)
444 LOG (GNUNET_ERROR_TYPE_DEBUG, "Starting sensor reporting module.\n");
445 GNUNET_assert (NULL != s);
448 statistics = GNUNET_STATISTICS_create ("sensor", cfg);
450 GNUNET_CONFIGURATION_get_value_filename (cfg, "SENSOR", "SENSOR_DIR",
453 sensor_dir = GNUNET_SENSOR_get_default_sensor_dir ();
455 if (NULL == statistics)
457 SENSOR_monitoring_stop ();
458 return GNUNET_SYSERR;
460 peerstore = GNUNET_PEERSTORE_connect (cfg);
461 if (NULL == peerstore)
463 SENSOR_monitoring_stop ();
464 return GNUNET_SYSERR;
466 GNUNET_CRYPTO_get_peer_identity (cfg, &peerid);
467 schedule_all_sensors ();
471 /* end of gnunet-service-sensor_analysis.c */