aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorOmar Tarabai <tarabai@devegypt.com>2014-08-11 15:04:11 +0000
committerOmar Tarabai <tarabai@devegypt.com>2014-08-11 15:04:11 +0000
commit1183a75a1a5d862f575d58c8873a9036a0fd3dbb (patch)
treeb9b644208f68bfffedd28471d2327f582f761206 /src
parentab550f5d9523c43a7384e97dc5ee1d645885c397 (diff)
downloadgnunet-1183a75a1a5d862f575d58c8873a9036a0fd3dbb.tar.gz
gnunet-1183a75a1a5d862f575d58c8873a9036a0fd3dbb.zip
sensor: separate monitoring functions
Diffstat (limited to 'src')
-rw-r--r--src/sensor/Makefile.am1
-rw-r--r--src/sensor/gnunet-service-sensor.c399
-rw-r--r--src/sensor/gnunet-service-sensor_analysis.c10
-rw-r--r--src/sensor/gnunet-service-sensor_monitoring.c473
-rw-r--r--src/sensor/gnunet-service-sensor_update.c6
-rw-r--r--src/sensor/sensor.h21
6 files changed, 509 insertions, 401 deletions
diff --git a/src/sensor/Makefile.am b/src/sensor/Makefile.am
index 6cc66c72e..f7f713fdd 100644
--- a/src/sensor/Makefile.am
+++ b/src/sensor/Makefile.am
@@ -36,6 +36,7 @@ gnunet_sensor_LDADD = \
36 36
37gnunet_service_sensor_SOURCES = \ 37gnunet_service_sensor_SOURCES = \
38 gnunet-service-sensor.c \ 38 gnunet-service-sensor.c \
39 gnunet-service-sensor_monitoring.c \
39 gnunet-service-sensor_analysis.c \ 40 gnunet-service-sensor_analysis.c \
40 gnunet-service-sensor_reporting.c \ 41 gnunet-service-sensor_reporting.c \
41 gnunet-service-sensor_update.c 42 gnunet-service-sensor_update.c
diff --git a/src/sensor/gnunet-service-sensor.c b/src/sensor/gnunet-service-sensor.c
index bf88094ea..047ad9183 100644
--- a/src/sensor/gnunet-service-sensor.c
+++ b/src/sensor/gnunet-service-sensor.c
@@ -23,12 +23,9 @@
23 * @brief sensor service implementation 23 * @brief sensor service implementation
24 * @author Omar Tarabai 24 * @author Omar Tarabai
25 */ 25 */
26#include <inttypes.h>
27#include "platform.h" 26#include "platform.h"
28#include "gnunet_util_lib.h" 27#include "gnunet_util_lib.h"
29#include "sensor.h" 28#include "sensor.h"
30#include "gnunet_statistics_service.h"
31#include "gnunet_peerstore_service.h"
32 29
33/** 30/**
34 * Our configuration. 31 * Our configuration.
@@ -45,26 +42,6 @@ static char *sensor_dir;
45 */ 42 */
46static struct GNUNET_CONTAINER_MultiHashMap *sensors; 43static struct GNUNET_CONTAINER_MultiHashMap *sensors;
47 44
48/**
49 * Handle to statistics service
50 */
51static struct GNUNET_STATISTICS_Handle *statistics;
52
53/**
54 * Handle to peerstore service
55 */
56static struct GNUNET_PEERSTORE_Handle *peerstore;
57
58/**
59 * Service name
60 */
61static char *subsystem = "sensor";
62
63/**
64 * My peer id
65 */
66static struct GNUNET_PeerIdentity peerid;
67
68 45
69/** 46/**
70 * Resets the service by stopping components, reloading sensors and starting 47 * Resets the service by stopping components, reloading sensors and starting
@@ -75,26 +52,6 @@ reset ();
75 52
76 53
77/** 54/**
78 * Change the state of the sensor.
79 * Write the change to file to make it persistent.
80 *
81 * @param sensor sensor info struct
82 * @param state new enabled state: #GNUNET_YES / #GNUNET_NO
83 */
84static void
85set_sensor_enabled (struct GNUNET_SENSOR_SensorInfo *sensor, int state)
86{
87 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sensor `%s': Setting enabled to %d.\n",
88 sensor->name, state);
89 sensor->enabled = GNUNET_NO;
90 GNUNET_assert (NULL != sensor->cfg);
91 GNUNET_CONFIGURATION_set_value_string (sensor->cfg, sensor->name, "ENABLED",
92 (GNUNET_YES == state) ? "YES" : "NO");
93 GNUNET_CONFIGURATION_write (sensor->cfg, sensor->def_file);
94}
95
96
97/**
98 * Stops components and destroys sensors 55 * Stops components and destroys sensors
99 */ 56 */
100static void 57static void
@@ -103,6 +60,7 @@ stop ()
103 SENSOR_update_stop (); 60 SENSOR_update_stop ();
104 SENSOR_analysis_stop (); 61 SENSOR_analysis_stop ();
105 SENSOR_reporting_stop (); 62 SENSOR_reporting_stop ();
63 SENSOR_monitoring_stop ();
106 GNUNET_SENSOR_destroy_sensors (sensors); 64 GNUNET_SENSOR_destroy_sensors (sensors);
107} 65}
108 66
@@ -117,16 +75,6 @@ static void
117shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) 75shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
118{ 76{
119 stop (); 77 stop ();
120 if (NULL != statistics)
121 {
122 GNUNET_STATISTICS_destroy (statistics, GNUNET_YES);
123 statistics = NULL;
124 }
125 if (NULL != peerstore)
126 {
127 GNUNET_PEERSTORE_disconnect (peerstore, GNUNET_YES);
128 peerstore = NULL;
129 }
130 if (NULL != sensor_dir) 78 if (NULL != sensor_dir)
131 { 79 {
132 GNUNET_free (sensor_dir); 80 GNUNET_free (sensor_dir);
@@ -137,18 +85,6 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
137 85
138 86
139/** 87/**
140 * A client disconnected. Remove all of its data structure entries.
141 *
142 * @param cls closure, NULL
143 * @param client identification of the client
144 */
145static void
146handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
147{
148}
149
150
151/**
152 * Creates a structure with basic sensor info to be sent to a client. 88 * Creates a structure with basic sensor info to be sent to a client.
153 * 89 *
154 * @param sensor sensor information 90 * @param sensor sensor information
@@ -288,338 +224,13 @@ handle_get_all_sensors (void *cls, struct GNUNET_SERVER_Client *client,
288 224
289 225
290/** 226/**
291 * Do a series of checks to determine if sensor should execute
292 *
293 * @return #GNUNET_YES / #GNUNET_NO
294 */
295static int
296should_run_sensor (struct GNUNET_SENSOR_SensorInfo *sensorinfo)
297{
298 struct GNUNET_TIME_Absolute now;
299
300 if (GNUNET_NO == sensorinfo->enabled)
301 {
302 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
303 "Sensor `%s' is disabled, will not run\n", sensorinfo->name);
304 return GNUNET_NO;
305 }
306 now = GNUNET_TIME_absolute_get ();
307 if (NULL != sensorinfo->start_time &&
308 now.abs_value_us < sensorinfo->start_time->abs_value_us)
309 {
310 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
311 "Start time for sensor `%s' not reached yet, will not run\n",
312 sensorinfo->name);
313 return GNUNET_NO;
314 }
315 if (NULL != sensorinfo->end_time &&
316 now.abs_value_us >= sensorinfo->end_time->abs_value_us)
317 {
318 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Sensor `%s' expired, disabling.\n",
319 sensorinfo->name);
320 set_sensor_enabled (sensorinfo, GNUNET_NO);
321 return GNUNET_NO;
322 }
323 return GNUNET_YES;
324}
325
326
327/**
328 * Callback function to process statistic values
329 *
330 * @param cls `struct GNUNET_SENSOR_SensorInfo *`
331 * @param ss name of subsystem that created the statistic
332 * @param name the name of the datum
333 * @param value the current value
334 * @param is_persistent #GNUNET_YES if the value is persistent, #GNUNET_NO if not
335 * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
336 */
337static int
338sensor_statistics_iterator (void *cls, const char *ss, const char *name,
339 uint64_t value, int is_persistent)
340{
341 struct GNUNET_SENSOR_SensorInfo *sensorinfo = cls;
342 double dvalue = (double) value;
343 struct GNUNET_TIME_Absolute expiry;
344
345 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
346 "Received a value for sensor `%s': %" PRIu64 "\n",
347 sensorinfo->name, value);
348 expiry = GNUNET_TIME_relative_to_absolute (sensorinfo->lifetime);
349 GNUNET_PEERSTORE_store (peerstore, subsystem, &peerid, sensorinfo->name,
350 &dvalue, sizeof (dvalue), expiry,
351 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE, NULL, NULL);
352 return GNUNET_SYSERR; /* We only want one value */
353}
354
355
356/**
357 * Continuation called after sensor gets all gnunet statistics values
358 *
359 * @param cls `struct GNUNET_SENSOR_SensorInfo *`
360 * @param success #GNUNET_OK if statistics were
361 * successfully obtained, #GNUNET_SYSERR if not.
362 */
363static void
364end_sensor_run_stat (void *cls, int success)
365{
366 struct GNUNET_SENSOR_SensorInfo *sensorinfo = cls;
367
368 sensorinfo->gnunet_stat_get_handle = NULL;
369 sensorinfo->running = GNUNET_NO;
370}
371
372
373/**
374 * Tries to parse a received sensor value to its
375 * expected datatype
376 *
377 * @param value the string value received, should be null terminated
378 * @param sensor sensor information struct
379 * @param ret pointer to parsed value
380 * @return size of new parsed value, 0 for error
381 */
382static size_t
383parse_sensor_value (const char *value, struct GNUNET_SENSOR_SensorInfo *sensor,
384 void **ret)
385{
386 double *dval;
387 char *endptr;
388
389 *ret = NULL;
390 if ('\0' == *value)
391 return 0;
392 if (0 == strcmp ("numeric", sensor->expected_datatype))
393 {
394 dval = GNUNET_new (double);
395
396 *dval = strtod (value, &endptr);
397 if (value == endptr)
398 return 0;
399 *ret = dval;
400 return sizeof (double);
401 }
402 if (0 == strcmp ("string", sensor->expected_datatype))
403 {
404 *ret = GNUNET_strdup (value);
405 return strlen (value) + 1;
406 }
407 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
408 _
409 ("Unknown value type expected by sensor, this should not happen.\n"));
410 return 0;
411}
412
413
414/**
415 * Callback for output of executed sensor process
416 *
417 * @param cls `struct GNUNET_SENSOR_SensorInfo *`
418 * @param line line of output from a command, NULL for the end
419 */
420static void
421sensor_process_callback (void *cls, const char *line)
422{
423 struct GNUNET_SENSOR_SensorInfo *sensorinfo = cls;
424 void *value;
425 size_t valsize;
426 struct GNUNET_TIME_Absolute expiry;
427
428 if (NULL == line)
429 {
430 GNUNET_OS_command_stop (sensorinfo->ext_cmd);
431 sensorinfo->ext_cmd = NULL;
432 sensorinfo->running = GNUNET_NO;
433 sensorinfo->ext_cmd_value_received = GNUNET_NO;
434 return;
435 }
436 if (GNUNET_YES == sensorinfo->ext_cmd_value_received)
437 return; /* We only want one *valid* value */
438 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Received a value for sensor `%s': %s\n",
439 sensorinfo->name, line);
440 valsize = parse_sensor_value (line, sensorinfo, &value);
441 if (valsize == 0) /* invalid value, FIXME: should we disable the sensor now? */
442 {
443 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
444 _("Received an invalid value for sensor `%s': %s\n"),
445 sensorinfo->name, line);
446 }
447 else
448 {
449 sensorinfo->ext_cmd_value_received = GNUNET_YES;
450 expiry = GNUNET_TIME_relative_to_absolute (sensorinfo->lifetime);
451 GNUNET_PEERSTORE_store (peerstore, subsystem, &peerid, sensorinfo->name,
452 value, valsize, expiry,
453 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE, NULL, NULL);
454 GNUNET_free (value);
455 }
456}
457
458
459/**
460 * Checks if the given file is a path
461 *
462 * @return #GNUNET_YES / #GNUNET_NO
463 */
464static int
465is_path (char *filename)
466{
467 size_t filename_len;
468 int i;
469
470 filename_len = strlen (filename);
471 for (i = 0; i < filename_len; i++)
472 {
473 if (DIR_SEPARATOR == filename[i])
474 return GNUNET_YES;
475 }
476 return GNUNET_NO;
477}
478
479
480/**
481 * Actual execution of a sensor
482 *
483 * @param cls 'struct SensorInfo'
484 * @param tc unsed
485 */
486static void
487sensor_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
488{
489 struct GNUNET_SENSOR_SensorInfo *sensorinfo = cls;
490 int check_result;
491 char *process_path;
492
493 sensorinfo->execution_task =
494 GNUNET_SCHEDULER_add_delayed (sensorinfo->interval, &sensor_run,
495 sensorinfo);
496 if (GNUNET_YES == sensorinfo->running) //FIXME: should we try to kill?
497 {
498 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
499 "Sensor `%s' running for too long, will try again next interval\n",
500 sensorinfo->name);
501 return;
502 }
503 if (GNUNET_NO == should_run_sensor (sensorinfo))
504 return;
505 sensorinfo->running = GNUNET_YES;
506 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
507 "Starting the execution of sensor `%s'\n", sensorinfo->name);
508 if (0 == strcmp ("gnunet-statistics", sensorinfo->source))
509 {
510 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
511 &end_sensor_run_stat,
512 &sensor_statistics_iterator,
513 sensorinfo);
514 }
515 else if (0 == strcmp ("process", sensorinfo->source))
516 {
517 if (GNUNET_YES == is_path (sensorinfo->ext_process))
518 {
519 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
520 _
521 ("Sensor `%s': External process should not be a path, disabling sensor.\n"),
522 sensorinfo->name);
523 set_sensor_enabled (sensorinfo, GNUNET_NO);
524 return;
525 }
526 //check if the process exists in $PATH
527 process_path = GNUNET_strdup (sensorinfo->ext_process);
528 check_result =
529 GNUNET_OS_check_helper_binary (process_path, GNUNET_NO, NULL);
530 if (GNUNET_SYSERR == check_result)
531 {
532 //search in sensor directory
533 GNUNET_free (process_path);
534 GNUNET_asprintf (&process_path, "%s%s-files%s%s", sensor_dir,
535 sensorinfo->name, DIR_SEPARATOR_STR,
536 sensorinfo->ext_process);
537 GNUNET_free (sensor_dir);
538 check_result =
539 GNUNET_OS_check_helper_binary (process_path, GNUNET_NO, NULL);
540 }
541 if (GNUNET_SYSERR == check_result)
542 {
543 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
544 _
545 ("Sensor `%s' process `%s' problem: binary doesn't exist or not executable\n"),
546 sensorinfo->name, sensorinfo->ext_process);
547 set_sensor_enabled (sensorinfo, GNUNET_NO);
548 sensorinfo->running = GNUNET_NO;
549 GNUNET_free (process_path);
550 return;
551 }
552 sensorinfo->ext_cmd_value_received = GNUNET_NO;
553 sensorinfo->ext_cmd =
554 GNUNET_OS_command_run (&sensor_process_callback, sensorinfo,
555 GNUNET_TIME_UNIT_FOREVER_REL, process_path,
556 sensorinfo->ext_process, sensorinfo->ext_args,
557 NULL);
558 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Process started for sensor `%s'\n",
559 sensorinfo->name);
560 GNUNET_free (process_path);
561 }
562 else
563 {
564 sensorinfo->running = GNUNET_NO;
565 GNUNET_break (0); /* shouldn't happen */
566 }
567}
568
569
570/**
571 * Starts the execution of a sensor
572 *
573 * @param cls unused
574 * @param key hash of sensor name, key to hashmap (unused)
575 * @param value a `struct GNUNET_SENSOR_SensorInfo *`
576 * @return #GNUNET_YES if we should continue to
577 * iterate,
578 * #GNUNET_NO if not.
579 */
580static int
581schedule_sensor (void *cls, const struct GNUNET_HashCode *key, void *value)
582{
583 struct GNUNET_SENSOR_SensorInfo *sensorinfo = value;
584
585 if (GNUNET_NO == should_run_sensor (sensorinfo))
586 return GNUNET_YES;
587 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
588 "Scheduling sensor `%s' to run after %" PRIu64 " microseconds\n",
589 sensorinfo->name, sensorinfo->interval.rel_value_us);
590 if (GNUNET_SCHEDULER_NO_TASK != sensorinfo->execution_task)
591 {
592 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
593 _
594 ("Sensor `%s' execution task already set, this should not happen\n"),
595 sensorinfo->name);
596 return GNUNET_NO;
597 }
598 sensorinfo->execution_task =
599 GNUNET_SCHEDULER_add_delayed (sensorinfo->interval, &sensor_run,
600 sensorinfo);
601 return GNUNET_YES;
602}
603
604
605/**
606 * Starts the execution of all enabled sensors
607 */
608static void
609schedule_all_sensors ()
610{
611 GNUNET_CONTAINER_multihashmap_iterate (sensors, &schedule_sensor, NULL);
612}
613
614
615/**
616 * Loads sensors and starts different service components 227 * Loads sensors and starts different service components
617 */ 228 */
618static void 229static void
619start () 230start ()
620{ 231{
621 sensors = GNUNET_SENSOR_load_all_sensors (sensor_dir); 232 sensors = GNUNET_SENSOR_load_all_sensors (sensor_dir);
622 schedule_all_sensors (); 233 SENSOR_monitoring_start (cfg, sensors);
623 SENSOR_reporting_start (cfg, sensors); 234 SENSOR_reporting_start (cfg, sensors);
624 SENSOR_analysis_start (cfg, sensors); 235 SENSOR_analysis_start (cfg, sensors);
625 SENSOR_update_start (cfg, sensors, &reset); 236 SENSOR_update_start (cfg, sensors, &reset);
@@ -649,12 +260,10 @@ run (void *cls, struct GNUNET_SERVER_Handle *server,
649 if (GNUNET_OK != 260 if (GNUNET_OK !=
650 GNUNET_CONFIGURATION_get_value_filename (cfg, "SENSOR", "SENSOR_DIR", 261 GNUNET_CONFIGURATION_get_value_filename (cfg, "SENSOR", "SENSOR_DIR",
651 &sensor_dir)) 262 &sensor_dir))
263 {
652 sensor_dir = GNUNET_SENSOR_get_default_sensor_dir (); 264 sensor_dir = GNUNET_SENSOR_get_default_sensor_dir ();
653 statistics = GNUNET_STATISTICS_create ("sensor", cfg); 265 }
654 GNUNET_CRYPTO_get_peer_identity (cfg, &peerid);
655 peerstore = GNUNET_PEERSTORE_connect (cfg);
656 GNUNET_SERVER_add_handlers (server, handlers); 266 GNUNET_SERVER_add_handlers (server, handlers);
657 GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
658 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, 267 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
659 NULL); 268 NULL);
660 start (); 269 start ();
diff --git a/src/sensor/gnunet-service-sensor_analysis.c b/src/sensor/gnunet-service-sensor_analysis.c
index 63249a4e2..a53c22589 100644
--- a/src/sensor/gnunet-service-sensor_analysis.c
+++ b/src/sensor/gnunet-service-sensor_analysis.c
@@ -86,6 +86,11 @@ struct SensorModel
86 */ 86 */
87static const struct GNUNET_CONFIGURATION_Handle *cfg; 87static const struct GNUNET_CONFIGURATION_Handle *cfg;
88 88
89/**
90 * Hashmap of loaded sensors
91 */
92struct GNUNET_CONTAINER_MultiHashMap *sensors;
93
89/* 94/*
90 * Model library name 95 * Model library name
91 */ 96 */
@@ -271,12 +276,13 @@ init_sensor_model (void *cls, const struct GNUNET_HashCode *key, void *value)
271 */ 276 */
272int 277int
273SENSOR_analysis_start (const struct GNUNET_CONFIGURATION_Handle *c, 278SENSOR_analysis_start (const struct GNUNET_CONFIGURATION_Handle *c,
274 struct GNUNET_CONTAINER_MultiHashMap *sensors) 279 struct GNUNET_CONTAINER_MultiHashMap *s)
275{ 280{
276 char *model_name; 281 char *model_name;
277 282
278 GNUNET_assert (NULL != sensors); 283 GNUNET_assert (NULL != s);
279 cfg = c; 284 cfg = c;
285 sensors = s;
280 if (GNUNET_OK != 286 if (GNUNET_OK !=
281 GNUNET_CONFIGURATION_get_value_string (cfg, "sensor-analysis", "MODEL", 287 GNUNET_CONFIGURATION_get_value_string (cfg, "sensor-analysis", "MODEL",
282 &model_name)) 288 &model_name))
diff --git a/src/sensor/gnunet-service-sensor_monitoring.c b/src/sensor/gnunet-service-sensor_monitoring.c
new file mode 100644
index 000000000..33173e1ae
--- /dev/null
+++ b/src/sensor/gnunet-service-sensor_monitoring.c
@@ -0,0 +1,473 @@
1/*
2 This file is part of GNUnet.
3 (C)
4
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.
9
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.
14
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.
19*/
20
21/**
22 * @file sensor/gnunet-service-sensor_analysis.c
23 * @brief sensor service analysis functionality
24 * @author Omar Tarabai
25 */
26#include <inttypes.h>
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "sensor.h"
30#include "gnunet_statistics_service.h"
31#include "gnunet_peerstore_service.h"
32
33#define LOG(kind,...) GNUNET_log_from (kind, "sensor-monitoring",__VA_ARGS__)
34
35/**
36 * Our configuration.
37 */
38static const struct GNUNET_CONFIGURATION_Handle *cfg;
39
40/**
41 * Hashmap of loaded sensor definitions
42 */
43static struct GNUNET_CONTAINER_MultiHashMap *sensors;
44
45/**
46 * Path to sensor definitions directory
47 */
48static char *sensor_dir;
49
50/**
51 * Handle to statistics service
52 */
53static struct GNUNET_STATISTICS_Handle *statistics;
54
55/**
56 * Handle to peerstore service
57 */
58static struct GNUNET_PEERSTORE_Handle *peerstore;
59
60/**
61 * My peer id
62 */
63static struct GNUNET_PeerIdentity peerid;
64
65
66/**
67 * Stop the sensor monitoring module
68 */
69void
70SENSOR_monitoring_stop ()
71{
72 if (NULL != statistics)
73 {
74 GNUNET_STATISTICS_destroy (statistics, GNUNET_YES);
75 statistics = NULL;
76 }
77 if (NULL != peerstore)
78 {
79 GNUNET_PEERSTORE_disconnect (peerstore, GNUNET_YES);
80 peerstore = NULL;
81 }
82 if (NULL != sensor_dir)
83 {
84 GNUNET_free (sensor_dir);
85 sensor_dir = NULL;
86 }
87}
88
89
90/**
91 * Change the state of the sensor.
92 * Write the change to file to make it persistent.
93 *
94 * @param sensor sensor info struct
95 * @param state new enabled state: #GNUNET_YES / #GNUNET_NO
96 */
97static void
98set_sensor_enabled (struct GNUNET_SENSOR_SensorInfo *sensor, int state)
99{
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);
107}
108
109
110/**
111 * Do a series of checks to determine if sensor should execute
112 *
113 * @return #GNUNET_YES / #GNUNET_NO
114 */
115static int
116should_run_sensor (struct GNUNET_SENSOR_SensorInfo *sensorinfo)
117{
118 struct GNUNET_TIME_Absolute now;
119
120 if (GNUNET_NO == sensorinfo->enabled)
121 {
122 LOG (GNUNET_ERROR_TYPE_INFO,
123 "Sensor `%s' is disabled, will not run\n", sensorinfo->name);
124 return GNUNET_NO;
125 }
126 now = GNUNET_TIME_absolute_get ();
127 if (NULL != sensorinfo->start_time &&
128 now.abs_value_us < sensorinfo->start_time->abs_value_us)
129 {
130 LOG (GNUNET_ERROR_TYPE_INFO,
131 "Start time for sensor `%s' not reached yet, will not run\n",
132 sensorinfo->name);
133 return GNUNET_NO;
134 }
135 if (NULL != sensorinfo->end_time &&
136 now.abs_value_us >= sensorinfo->end_time->abs_value_us)
137 {
138 LOG (GNUNET_ERROR_TYPE_INFO, "Sensor `%s' expired, disabling.\n",
139 sensorinfo->name);
140 set_sensor_enabled (sensorinfo, GNUNET_NO);
141 return GNUNET_NO;
142 }
143 return GNUNET_YES;
144}
145
146
147/**
148 * Callback function to process statistic values
149 *
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
156 */
157static int
158sensor_statistics_iterator (void *cls, const char *ss, const char *name,
159 uint64_t value, int is_persistent)
160{
161 struct GNUNET_SENSOR_SensorInfo *sensorinfo = cls;
162 double dvalue = (double) value;
163 struct GNUNET_TIME_Absolute expiry;
164
165 LOG (GNUNET_ERROR_TYPE_INFO,
166 "Received a value for sensor `%s': %" PRIu64 "\n",
167 sensorinfo->name, value);
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 */
173}
174
175
176/**
177 * Continuation called after sensor gets all gnunet statistics values
178 *
179 * @param cls `struct GNUNET_SENSOR_SensorInfo *`
180 * @param success #GNUNET_OK if statistics were
181 * successfully obtained, #GNUNET_SYSERR if not.
182 */
183static void
184end_sensor_run_stat (void *cls, int success)
185{
186 struct GNUNET_SENSOR_SensorInfo *sensorinfo = cls;
187
188 sensorinfo->gnunet_stat_get_handle = NULL;
189 sensorinfo->running = GNUNET_NO;
190}
191
192
193/**
194 * Tries to parse a received sensor value to its
195 * expected datatype
196 *
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
201 */
202static size_t
203parse_sensor_value (const char *value, struct GNUNET_SENSOR_SensorInfo *sensor,
204 void **ret)
205{
206 double *dval;
207 char *endptr;
208
209 *ret = NULL;
210 if ('\0' == *value)
211 return 0;
212 if (0 == strcmp ("numeric", sensor->expected_datatype))
213 {
214 dval = GNUNET_new (double);
215
216 *dval = strtod (value, &endptr);
217 if (value == endptr)
218 return 0;
219 *ret = dval;
220 return sizeof (double);
221 }
222 if (0 == strcmp ("string", sensor->expected_datatype))
223 {
224 *ret = GNUNET_strdup (value);
225 return strlen (value) + 1;
226 }
227 LOG (GNUNET_ERROR_TYPE_ERROR,
228 _
229 ("Unknown value type expected by sensor, this should not happen.\n"));
230 return 0;
231}
232
233
234/**
235 * Callback for output of executed sensor process
236 *
237 * @param cls `struct GNUNET_SENSOR_SensorInfo *`
238 * @param line line of output from a command, NULL for the end
239 */
240static void
241sensor_process_callback (void *cls, const char *line)
242{
243 struct GNUNET_SENSOR_SensorInfo *sensorinfo = cls;
244 void *value;
245 size_t valsize;
246 struct GNUNET_TIME_Absolute expiry;
247
248 if (NULL == line)
249 {
250 GNUNET_OS_command_stop (sensorinfo->ext_cmd);
251 sensorinfo->ext_cmd = NULL;
252 sensorinfo->running = GNUNET_NO;
253 sensorinfo->ext_cmd_value_received = GNUNET_NO;
254 return;
255 }
256 if (GNUNET_YES == sensorinfo->ext_cmd_value_received)
257 return; /* We only want one *valid* value */
258 LOG (GNUNET_ERROR_TYPE_INFO, "Received a value for sensor `%s': %s\n",
259 sensorinfo->name, line);
260 valsize = parse_sensor_value (line, sensorinfo, &value);
261 if (valsize == 0) /* invalid value, FIXME: should we disable the sensor now? */
262 {
263 LOG (GNUNET_ERROR_TYPE_ERROR,
264 _("Received an invalid value for sensor `%s': %s\n"),
265 sensorinfo->name, line);
266 }
267 else
268 {
269 sensorinfo->ext_cmd_value_received = GNUNET_YES;
270 expiry = GNUNET_TIME_relative_to_absolute (sensorinfo->lifetime);
271 GNUNET_PEERSTORE_store (peerstore, "sensor", &peerid, sensorinfo->name,
272 value, valsize, expiry,
273 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE, NULL, NULL);
274 GNUNET_free (value);
275 }
276}
277
278
279/**
280 * Checks if the given file is a path
281 *
282 * @return #GNUNET_YES / #GNUNET_NO
283 */
284static int
285is_path (char *filename)
286{
287 size_t filename_len;
288 int i;
289
290 filename_len = strlen (filename);
291 for (i = 0; i < filename_len; i++)
292 {
293 if (DIR_SEPARATOR == filename[i])
294 return GNUNET_YES;
295 }
296 return GNUNET_NO;
297}
298
299
300/**
301 * Actual execution of a sensor
302 *
303 * @param cls 'struct SensorInfo'
304 * @param tc unsed
305 */
306static void
307sensor_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
308{
309 struct GNUNET_SENSOR_SensorInfo *sensorinfo = cls;
310 int check_result;
311 char *process_path;
312
313 sensorinfo->execution_task =
314 GNUNET_SCHEDULER_add_delayed (sensorinfo->interval, &sensor_run,
315 sensorinfo);
316 if (GNUNET_YES == sensorinfo->running) //FIXME: should we try to kill?
317 {
318 LOG (GNUNET_ERROR_TYPE_WARNING,
319 "Sensor `%s' running for too long, will try again next interval\n",
320 sensorinfo->name);
321 return;
322 }
323 if (GNUNET_NO == should_run_sensor (sensorinfo))
324 return;
325 sensorinfo->running = GNUNET_YES;
326 LOG (GNUNET_ERROR_TYPE_DEBUG,
327 "Starting the execution of sensor `%s'\n", sensorinfo->name);
328 if (0 == strcmp ("gnunet-statistics", sensorinfo->source))
329 {
330 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
331 &end_sensor_run_stat,
332 &sensor_statistics_iterator,
333 sensorinfo);
334 }
335 else if (0 == strcmp ("process", sensorinfo->source))
336 {
337 if (GNUNET_YES == is_path (sensorinfo->ext_process))
338 {
339 LOG (GNUNET_ERROR_TYPE_ERROR,
340 _
341 ("Sensor `%s': External process should not be a path, disabling sensor.\n"),
342 sensorinfo->name);
343 set_sensor_enabled (sensorinfo, GNUNET_NO);
344 return;
345 }
346 //check if the process exists in $PATH
347 process_path = GNUNET_strdup (sensorinfo->ext_process);
348 check_result =
349 GNUNET_OS_check_helper_binary (process_path, GNUNET_NO, NULL);
350 if (GNUNET_SYSERR == check_result)
351 {
352 //search in sensor directory
353 GNUNET_free (process_path);
354 GNUNET_asprintf (&process_path, "%s%s-files%s%s", sensor_dir,
355 sensorinfo->name, DIR_SEPARATOR_STR,
356 sensorinfo->ext_process);
357 GNUNET_free (sensor_dir);
358 check_result =
359 GNUNET_OS_check_helper_binary (process_path, GNUNET_NO, NULL);
360 }
361 if (GNUNET_SYSERR == check_result)
362 {
363 LOG (GNUNET_ERROR_TYPE_ERROR,
364 _
365 ("Sensor `%s' process `%s' problem: binary doesn't exist or not executable\n"),
366 sensorinfo->name, sensorinfo->ext_process);
367 set_sensor_enabled (sensorinfo, GNUNET_NO);
368 sensorinfo->running = GNUNET_NO;
369 GNUNET_free (process_path);
370 return;
371 }
372 sensorinfo->ext_cmd_value_received = GNUNET_NO;
373 sensorinfo->ext_cmd =
374 GNUNET_OS_command_run (&sensor_process_callback, sensorinfo,
375 GNUNET_TIME_UNIT_FOREVER_REL, process_path,
376 sensorinfo->ext_process, sensorinfo->ext_args,
377 NULL);
378 LOG (GNUNET_ERROR_TYPE_DEBUG, "Process started for sensor `%s'\n",
379 sensorinfo->name);
380 GNUNET_free (process_path);
381 }
382 else
383 {
384 sensorinfo->running = GNUNET_NO;
385 GNUNET_break (0); /* shouldn't happen */
386 }
387}
388
389
390/**
391 * Starts the execution of a sensor
392 *
393 * @param cls unused
394 * @param key hash of sensor name, key to hashmap (unused)
395 * @param value a `struct GNUNET_SENSOR_SensorInfo *`
396 * @return #GNUNET_YES if we should continue to
397 * iterate,
398 * #GNUNET_NO if not.
399 */
400static int
401schedule_sensor (void *cls, const struct GNUNET_HashCode *key, void *value)
402{
403 struct GNUNET_SENSOR_SensorInfo *sensorinfo = value;
404
405 if (GNUNET_NO == should_run_sensor (sensorinfo))
406 return GNUNET_YES;
407 LOG (GNUNET_ERROR_TYPE_DEBUG,
408 "Scheduling sensor `%s' to run after %" PRIu64 " microseconds\n",
409 sensorinfo->name, sensorinfo->interval.rel_value_us);
410 if (GNUNET_SCHEDULER_NO_TASK != sensorinfo->execution_task)
411 {
412 LOG (GNUNET_ERROR_TYPE_ERROR,
413 _
414 ("Sensor `%s' execution task already set, this should not happen\n"),
415 sensorinfo->name);
416 return GNUNET_NO;
417 }
418 sensorinfo->execution_task =
419 GNUNET_SCHEDULER_add_delayed (sensorinfo->interval, &sensor_run,
420 sensorinfo);
421 return GNUNET_YES;
422}
423
424
425/**
426 * Starts the execution of all enabled sensors
427 */
428static void
429schedule_all_sensors ()
430{
431 GNUNET_CONTAINER_multihashmap_iterate (sensors, &schedule_sensor, NULL);
432}
433
434
435/**
436 * Start the sensor monitoring module
437 *
438 * @param c our service configuration
439 * @param sensors multihashmap of loaded sensors
440 * @return #GNUNET_OK if started successfully, #GNUNET_SYSERR otherwise
441 */
442int
443SENSOR_monitoring_start (const struct GNUNET_CONFIGURATION_Handle *c,
444 struct GNUNET_CONTAINER_MultiHashMap *s)
445{
446 LOG (GNUNET_ERROR_TYPE_DEBUG, "Starting sensor reporting module.\n");
447 GNUNET_assert (NULL != s);
448 sensors = s;
449 cfg = c;
450 statistics = GNUNET_STATISTICS_create ("sensor", cfg);
451 if (GNUNET_OK !=
452 GNUNET_CONFIGURATION_get_value_filename (cfg, "SENSOR", "SENSOR_DIR",
453 &sensor_dir))
454 {
455 sensor_dir = GNUNET_SENSOR_get_default_sensor_dir ();
456 }
457 if (NULL == statistics)
458 {
459 SENSOR_monitoring_stop ();
460 return GNUNET_SYSERR;
461 }
462 peerstore = GNUNET_PEERSTORE_connect (cfg);
463 if (NULL == peerstore)
464 {
465 SENSOR_monitoring_stop ();
466 return GNUNET_SYSERR;
467 }
468 GNUNET_CRYPTO_get_peer_identity (cfg, &peerid);
469 schedule_all_sensors ();
470 return GNUNET_OK;
471}
472
473/* end of gnunet-service-sensor_analysis.c */
diff --git a/src/sensor/gnunet-service-sensor_update.c b/src/sensor/gnunet-service-sensor_update.c
index cbc63308d..1bcdd792a 100644
--- a/src/sensor/gnunet-service-sensor_update.c
+++ b/src/sensor/gnunet-service-sensor_update.c
@@ -168,12 +168,12 @@ static int updating;
168/** 168/**
169 * GNUnet scheduler task that starts the update check process. 169 * GNUnet scheduler task that starts the update check process.
170 */ 170 */
171GNUNET_SCHEDULER_TaskIdentifier update_task; 171static GNUNET_SCHEDULER_TaskIdentifier update_task;
172 172
173/** 173/**
174 * Pointer to service reset function called when we have new sensor updates. 174 * Pointer to service reset function called when we have new sensor updates.
175 */ 175 */
176void (*reset_cb) (); 176static void (*reset_cb) ();
177 177
178 178
179/** 179/**
@@ -646,7 +646,7 @@ update_sensor (char *sensorname, void *sensorfile, uint16_t sensorfile_size,
646 * @param cls unused 646 * @param cls unused
647 * @param tc unused 647 * @param tc unused
648 */ 648 */
649void 649static void
650reset (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) 650reset (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
651{ 651{
652 reset_cb (); 652 reset_cb ();
diff --git a/src/sensor/sensor.h b/src/sensor/sensor.h
index 5d75ee427..c5dd3bb1b 100644
--- a/src/sensor/sensor.h
+++ b/src/sensor/sensor.h
@@ -77,7 +77,7 @@ SENSOR_analysis_stop ();
77 */ 77 */
78int 78int
79SENSOR_analysis_start (const struct GNUNET_CONFIGURATION_Handle *c, 79SENSOR_analysis_start (const struct GNUNET_CONFIGURATION_Handle *c,
80 struct GNUNET_CONTAINER_MultiHashMap *sensors); 80 struct GNUNET_CONTAINER_MultiHashMap *s);
81 81
82 82
83/** 83/**
@@ -128,3 +128,22 @@ SENSOR_update_stop ();
128int 128int
129SENSOR_update_start (const struct GNUNET_CONFIGURATION_Handle *c, 129SENSOR_update_start (const struct GNUNET_CONFIGURATION_Handle *c,
130 struct GNUNET_CONTAINER_MultiHashMap *s, void (*cb) ()); 130 struct GNUNET_CONTAINER_MultiHashMap *s, void (*cb) ());
131
132
133/**
134 * Stop the sensor monitoring module
135 */
136void
137SENSOR_monitoring_stop ();
138
139
140/**
141 * Start the sensor monitoring module
142 *
143 * @param c our service configuration
144 * @param sensors multihashmap of loaded sensors
145 * @return #GNUNET_OK if started successfully, #GNUNET_SYSERR otherwise
146 */
147int
148SENSOR_monitoring_start (const struct GNUNET_CONFIGURATION_Handle *c,
149 struct GNUNET_CONTAINER_MultiHashMap *s);