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.c
23 * @brief sensor service implementation
24 * @author Omar Tarabai
28 #include "gnunet_util_lib.h"
30 #include "gnunet_statistics_service.h"
32 //TODO: GNUNET_SERVER_receive_done() ?
35 * Minimum sensor execution interval (in seconds)
37 #define MIN_INTERVAL 30
40 * Structure containing sensor definition
51 * Path to definition file
56 * First part of version number
58 uint16_t version_major;
61 * Second part of version number
63 uint16_t version_minor;
71 * Sensor currently enabled
76 * Category under which the sensor falls (e.g. tcp, datastore)
81 * When does the sensor become active
83 struct GNUNET_TIME_Absolute *start_time;
86 * When does the sensor expire
88 struct GNUNET_TIME_Absolute *end_time;
91 * Time interval to collect sensor information (e.g. every 1 min)
93 struct GNUNET_TIME_Relative interval;
96 * Lifetime of an information sample after which it is deleted from storage
98 struct GNUNET_TIME_Relative lifetime;
101 * A set of required peer capabilities for the sensor to collect meaningful information (e.g. ipv6)
106 * Either "gnunet-statistics" or external "process"
111 * Name of the GNUnet service that is the source for the gnunet-statistics entry
113 char *gnunet_stat_service;
116 * Name of the gnunet-statistics entry
118 char *gnunet_stat_name;
121 * Handle to statistics get request (OR GNUNET_SCHEDULER_NO_TASK)
123 struct GNUNET_STATISTICS_GetHandle *gnunet_stat_get_handle;
126 * Name of the external process to be executed
131 * Arguments to be passed to the external process
136 * The output datatype to be expected
138 char *expected_datatype;
141 * Peer-identity of peer running collection point
143 struct GNUNET_PeerIdentity *collection_point;
146 * Time interval to send sensor information to collection point (e.g. every 30 mins)
148 struct GNUNET_TIME_Relative *collection_interval;
151 * Flag specifying if value is to be communicated to the p2p network
156 * Time interval to communicate value to the p2p network
158 struct GNUNET_TIME_Relative *p2p_interval;
161 * Execution task (OR GNUNET_SCHEDULER_NO_TASK)
163 GNUNET_SCHEDULER_TaskIdentifier execution_task;
166 * Is the sensor being executed
175 static const struct GNUNET_CONFIGURATION_Handle *cfg;
178 * Hashmap of loaded sensor definitions
180 struct GNUNET_CONTAINER_MultiHashMap *sensors;
183 * Supported sources of sensor information
185 static const char *sources[] = { "gnunet-statistics", "process", NULL };
188 * Supported datatypes of sensor information
190 static const char *datatypes[] = { "uint64", "double", "string", NULL };
193 * Handle to statistics service
195 struct GNUNET_STATISTICS_Handle *statistics;
197 //TODO: logging macro that includes sensor info
200 * Remove sensor execution from scheduler
203 * @param key hash of sensor name, key to hashmap
204 * @param value a 'struct SensorInfo *'
205 * @return #GNUNET_YES if we should continue to
209 int unschedule_sensor(void *cls,
210 const struct GNUNET_HashCode *key, void *value)
212 struct SensorInfo *sensorinfo = value;
214 if(NULL != sensorinfo->gnunet_stat_get_handle)
216 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Canceling a statistics get request for sensor `%s'\n", sensorinfo->name);
217 GNUNET_STATISTICS_get_cancel(sensorinfo->gnunet_stat_get_handle);
219 if(GNUNET_SCHEDULER_NO_TASK != sensorinfo->execution_task)
221 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Unscheduling sensor `%s'\n", sensorinfo->name);
222 GNUNET_SCHEDULER_cancel(sensorinfo->execution_task);
228 * Task run during shutdown.
234 shutdown_task (void *cls,
235 const struct GNUNET_SCHEDULER_TaskContext *tc)
237 GNUNET_CONTAINER_multihashmap_iterate(sensors, &unschedule_sensor, NULL);
238 if(NULL != statistics)
239 GNUNET_STATISTICS_destroy(statistics, GNUNET_YES);
240 GNUNET_SCHEDULER_shutdown();
245 * A client disconnected. Remove all of its data structure entries.
247 * @param cls closure, NULL
248 * @param client identification of the client
251 handle_client_disconnect (void *cls,
252 struct GNUNET_SERVER_Client
258 * Parses a version number string into major and minor
260 * @param version full version string
261 * @param major pointer to parsed major value
262 * @param minor pointer to parsed minor value
263 * @return #GNUNET_OK if parsing went ok, #GNUNET_SYSERROR in case of error
266 version_parse(char *version, uint16_t *major, uint16_t *minor)
271 for(; isdigit(*version); version++)
274 majorval += *version - '0';
277 return GNUNET_SYSERR;
279 for(; isdigit(*version); version++)
282 minorval += *version - '0';
285 return GNUNET_SYSERR;
293 * Load sensor definition from configuration
295 * @param cfg configuration handle
296 * @param sectionname configuration section containing definition
298 static struct SensorInfo *
299 load_sensor_from_cfg(struct GNUNET_CONFIGURATION_Handle *cfg, const char *sectionname)
301 struct SensorInfo *sensor;
305 unsigned long long time_sec;
307 sensor = GNUNET_new(struct SensorInfo);
309 sensor->name = GNUNET_strdup(sectionname);
311 if(GNUNET_OK != GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "VERSION", &version_str))
313 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor version\n"));
317 if(GNUNET_OK != version_parse(version_str, &(sensor->version_major), &(sensor->version_minor)))
319 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Invalid sensor version number, format should be major.minor\n"));
321 GNUNET_free(version_str);
324 GNUNET_free(version_str);
326 GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "DESCRIPTION", &sensor->description);
328 if(GNUNET_OK != GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "CATEGORY", &sensor->category) ||
329 NULL == sensor->category)
331 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor category\n"));
336 if(GNUNET_NO == GNUNET_CONFIGURATION_get_value_yesno(cfg, sectionname, "ENABLED"))
337 sensor->enabled = GNUNET_NO;
339 sensor->enabled = GNUNET_YES;
341 sensor->start_time = NULL;
342 if(GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "START_TIME", &starttime_str))
344 GNUNET_STRINGS_fancy_time_to_absolute(starttime_str, sensor->start_time);
345 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Start time loaded: `%s'. Parsed: %d\n", starttime_str, (NULL != sensor->start_time));
346 GNUNET_free(starttime_str);
349 sensor->end_time = NULL;
350 if(GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "END_TIME", &endtime_str))
352 GNUNET_STRINGS_fancy_time_to_absolute(endtime_str, sensor->end_time);
353 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "End time loaded: `%s'. Parsed: %d\n", endtime_str, (NULL != sensor->end_time));
354 GNUNET_free(endtime_str);
357 if(GNUNET_OK != GNUNET_CONFIGURATION_get_value_number(cfg, sectionname, "INTERVAL", &time_sec))
359 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor run interval\n"));
363 if(time_sec < MIN_INTERVAL)
365 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Sensor run interval too low (%" PRIu64 " < %d)\n"),
366 time_sec, MIN_INTERVAL);
370 sensor->interval = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, time_sec);
371 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Interval loaded: %" PRIu64 "\n", sensor->interval.rel_value_us);
373 if(GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg, sectionname, "LIFETIME", &time_sec))
375 sensor->lifetime = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, time_sec);
376 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Lifetime loaded: %" PRIu64 "\n", sensor->lifetime.rel_value_us);
379 sensor->lifetime = GNUNET_TIME_UNIT_FOREVER_REL;
382 if(GNUNET_OK != GNUNET_CONFIGURATION_get_value_choice(cfg, sectionname, "SOURCE", sources, (const char **)&sensor->source))
384 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor source\n"));
388 if(sources[0] == sensor->source) //gnunet-statistics
390 if(GNUNET_OK != GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "GNUNET_STAT_SERVICE", &sensor->gnunet_stat_service) ||
391 GNUNET_OK != GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "GNUNET_STAT_NAME", &sensor->gnunet_stat_name))
393 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor gnunet-statistics source information\n"));
397 sensor->gnunet_stat_get_handle = NULL;
399 else if(sources[1] == sensor->source) //process
401 if(GNUNET_OK != GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "EXT_PROCESS", &sensor->ext_process))
403 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor process name\n"));
407 GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "EXT_ARGS", &sensor->ext_args);
410 if(GNUNET_OK != GNUNET_CONFIGURATION_get_value_choice(cfg, sectionname, "EXPECTED_DATATYPE", datatypes, (const char **)&sensor->expected_datatype))
412 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor expected datatype\n"));
416 if(sources[0] == sensor->source && datatypes[0] != sensor->expected_datatype)
418 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Invalid expected datatype, gnunet-statistics returns uint64 values\n"));
422 //TODO: reporting mechanism
424 sensor->execution_task = GNUNET_SCHEDULER_NO_TASK;
426 sensor->running = GNUNET_NO;
432 * Load sensor definition from file
434 * @param filename full path to file containing sensor definition
436 static struct SensorInfo *
437 load_sensor_from_file(const char *filename)
439 struct GNUNET_CONFIGURATION_Handle *sensorcfg;
440 const char *filebasename;
441 struct SensorInfo *sensor;
444 if(GNUNET_YES != GNUNET_DISK_file_test(filename))
446 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Failed to access sensor file: %s\n"), filename);
449 //load file as configuration
450 sensorcfg = GNUNET_CONFIGURATION_create();
451 if(GNUNET_SYSERR == GNUNET_CONFIGURATION_parse(sensorcfg, filename))
453 GNUNET_CONFIGURATION_destroy(sensorcfg);
454 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Failed to load sensor definition: %s\n"), filename);
457 //configuration section should be the same as filename
458 filebasename = GNUNET_STRINGS_get_short_name(filename);
459 sensor = load_sensor_from_cfg(sensorcfg, filebasename);
460 sensor->def_file = GNUNET_strdup(filename);
462 GNUNET_CONFIGURATION_destroy(sensorcfg);
468 * Compares version numbers of two sensors
470 * @param s1 first sensor
471 * @param s2 second sensor
472 * @return 1: s1 > s2, 0: s1 == s2, -1: s1 < s2
475 sensor_version_compare(struct SensorInfo *s1, struct SensorInfo *s2)
477 if(s1->version_major == s2->version_major)
478 return (s1->version_minor < s2->version_minor) ? -1 : (s1->version_minor > s2->version_minor);
480 return (s1->version_major < s2->version_major) ? -1 : (s1->version_major > s2->version_major);
484 * Adds a new sensor to given hashmap.
485 * If the same name exist, compares versions and update if old.
487 * @param sensor Sensor structure to add
488 * @param map Hashmap to add to
489 * @return #GNUNET_YES if added, #GNUNET_NO if not added which is not necessarily an error
492 add_sensor_to_hashmap(struct SensorInfo *sensor, struct GNUNET_CONTAINER_MultiHashMap *map)
494 struct GNUNET_HashCode key;
495 struct SensorInfo *existing;
497 GNUNET_CRYPTO_hash(sensor->name, strlen(sensor->name), &key);
498 existing = GNUNET_CONTAINER_multihashmap_get(map, &key);
499 if(NULL != existing) //sensor with same name already exists
501 if(sensor_version_compare(existing, sensor) >= 0) //same or newer version already exist
503 GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Sensor `%s' already exists with same or newer version\n"), sensor->name);
508 GNUNET_CONTAINER_multihashmap_remove(map, &key, existing); //remove the old version
509 GNUNET_free(existing);
510 GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Upgrading sensor `%s' to a newer version\n"), sensor->name);
513 if(GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_put(map, &key, sensor, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
515 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Error adding new sensor `%s' to global hashmap, this should not happen\n"), sensor->name);
523 * Iterating over files in sensors directory
526 * @param filename complete filename (absolute path)
527 * @return #GNUNET_OK to continue to iterate,
528 * #GNUNET_NO to stop iteration with no error,
529 * #GNUNET_SYSERR to abort iteration with error!
532 reload_sensors_dir_cb(void *cls, const char *filename)
534 struct SensorInfo *sensor;
536 sensor = load_sensor_from_file(filename);
539 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Error loading sensor from file: %s\n"), filename);
542 if(GNUNET_YES == add_sensor_to_hashmap(sensor, sensors))
543 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, _("Sensor `%s' added to global hashmap\n"), sensor->name);
545 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, ("Could not add sensor `%s' to global hashmap\n"), sensor->name);
551 * Get path to the directory containing the sensor definition files
553 * @return sensor files directory
561 datadir = GNUNET_OS_installation_get_path(GNUNET_OS_IPK_DATADIR);
562 GNUNET_asprintf(&sensordir, "%ssensors%s",
563 datadir, DIR_SEPARATOR_STR);
569 * Reads sensor definitions from data files
578 sensordir = get_sensor_dir();
579 GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Reloading sensor definitions from directory `%s'\n"), sensordir);
580 GNUNET_assert(GNUNET_YES == GNUNET_DISK_directory_test(sensordir, GNUNET_YES));
582 //read all files in sensors directory
583 filesfound = GNUNET_DISK_directory_scan(sensordir, &reload_sensors_dir_cb, NULL);
584 GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Loaded %d/%d sensors from directory `%s'\n"),
585 GNUNET_CONTAINER_multihashmap_size(sensors), filesfound, sensordir);
589 * Creates a structure with basic sensor info to be sent to a client
591 * @param sensor sensor information
592 * @return message ready to be sent to client
594 static struct SensorInfoMessage *
595 create_sensor_info_msg(struct SensorInfo *sensor)
597 struct SensorInfoMessage *msg;
603 name_len = strlen(sensor->name);
604 if(NULL == sensor->description)
607 desc_len = strlen(sensor->description);
609 len += sizeof(struct SensorInfoMessage);
612 msg = GNUNET_malloc(len);
613 msg->header.size = htons(len);
614 msg->header.type = htons(GNUNET_MESSAGE_TYPE_SENSOR_INFO);
615 msg->name_len = htons(name_len);
616 msg->description_len = htons(desc_len);
617 msg->version_major = htons(sensor->version_major);
618 msg->version_minor = htons(sensor->version_minor);
619 str_ptr = (char*) &msg[1];
620 memcpy(str_ptr, sensor->name, name_len);
621 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Sending sensor name (%d): %.*s\n",
622 name_len, name_len, str_ptr);
624 memcpy(str_ptr, sensor->description, desc_len);
625 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Sending sensor description (%d): %.*s\n",
626 desc_len, desc_len, str_ptr);
632 * Handle GET SENSOR message.
635 * @param client identification of the client
636 * @param message the actual message
639 handle_get_sensor (void *cls, struct GNUNET_SERVER_Client *client,
640 const struct GNUNET_MessageHeader *message)
642 struct GNUNET_SERVER_TransmitContext *tc;
644 size_t sensorname_len;
645 struct GNUNET_HashCode key;
646 struct SensorInfo *sensorinfo;
647 struct SensorInfoMessage *msg;
649 sensorname = (char *)&message[1];
650 sensorname_len = ntohs(message->size) - sizeof(struct GNUNET_MessageHeader);
651 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "`%s' message received for sensor (%d) `%.*s'\n",
652 "GET SENSOR", sensorname_len, sensorname_len, sensorname);
653 tc = GNUNET_SERVER_transmit_context_create (client);
654 GNUNET_CRYPTO_hash(sensorname, sensorname_len, &key);
655 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Created key hash for requested sensor\n");
656 sensorinfo = (struct SensorInfo *)GNUNET_CONTAINER_multihashmap_get(sensors, &key);
657 if(NULL != sensorinfo)
659 msg = create_sensor_info_msg(sensorinfo);
660 GNUNET_SERVER_transmit_context_append_message(tc, (struct GNUNET_MessageHeader *)msg);
664 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Requested sensor `%.*s' was not found\n",
665 sensorname_len, sensorname);
666 GNUNET_SERVER_transmit_context_append_data(tc, NULL, 0, GNUNET_MESSAGE_TYPE_SENSOR_END);
667 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
671 * Iterator for sensors and adds them to transmit context
673 * @param cls a 'struct GNUNET_SERVER_TransmitContext *'
674 * @param key hash of sensor name, key to hashmap
675 * @param value a 'struct SensorInfo *'
677 int add_sensor_to_tc(void *cls,
678 const struct GNUNET_HashCode *key, void *value)
680 struct GNUNET_SERVER_TransmitContext *tc = cls;
681 struct SensorInfo *sensorinfo = value;
682 struct SensorInfoMessage *msg;
684 msg = create_sensor_info_msg(sensorinfo);
685 GNUNET_SERVER_transmit_context_append_message(tc, (struct GNUNET_MessageHeader *)msg);
693 * Handle GET ALL SENSORS message.
696 * @param client identification of the client
697 * @param message the actual message
700 handle_get_all_sensors (void *cls, struct GNUNET_SERVER_Client *client,
701 const struct GNUNET_MessageHeader *message)
703 struct GNUNET_SERVER_TransmitContext *tc;
705 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "`%s' message received.\n",
707 tc = GNUNET_SERVER_transmit_context_create (client);
708 GNUNET_CONTAINER_multihashmap_iterate(sensors, &add_sensor_to_tc, tc);
709 GNUNET_SERVER_transmit_context_append_data(tc, NULL, 0, GNUNET_MESSAGE_TYPE_SENSOR_END);
710 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
714 * Do a series of checks to determine if sensor should execute
716 * @return #GNUNET_YES / #GNUNET_NO
719 should_run_sensor(struct SensorInfo *sensorinfo)
721 //FIXME: some checks should disable the sensor (e.g. expired)
722 struct GNUNET_TIME_Absolute now;
724 if(GNUNET_NO == sensorinfo->enabled)
726 GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Sensor `%s' is disabled, will not run\n", sensorinfo->name);
729 now = GNUNET_TIME_absolute_get();
730 if(NULL != sensorinfo->start_time
731 && now.abs_value_us < sensorinfo->start_time->abs_value_us)
733 GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Start time for sensor `%s' not reached yet, will not run\n", sensorinfo->name);
736 if(NULL != sensorinfo->end_time
737 && now.abs_value_us >= sensorinfo->end_time->abs_value_us)
739 GNUNET_log(GNUNET_ERROR_TYPE_INFO, "End time for sensor `%s' passed, will not run\n", sensorinfo->name);
746 * Callback function to process statistic values
748 * @param cls 'struct SensorInfo *'
749 * @param subsystem name of subsystem that created the statistic
750 * @param name the name of the datum
751 * @param value the current value
752 * @param is_persistent #GNUNET_YES if the value is persistent, #GNUNET_NO if not
753 * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
755 int sensor_statistics_iterator (void *cls,
756 const char *subsystem,
761 struct SensorInfo *sensorinfo = cls;
763 GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Received a value for sensor `%s': %" PRIu64 "\n", sensorinfo->name, value);
768 * Continuation called after sensor gets all gnunet statistics values
770 * @param cls 'struct SensorInfo *'
771 * @param success #GNUNET_OK if statistics were
772 * successfully obtained, #GNUNET_SYSERR if not.
774 void end_sensor_run_stat (void *cls, int success)
776 struct SensorInfo *sensorinfo = cls;
778 sensorinfo->gnunet_stat_get_handle = NULL;
779 sensorinfo->running = GNUNET_NO;
783 * Callback for output of executed sensor process
785 * @param cls 'struct SensorInfo *'
786 * @param line line of output from a command, NULL for the end
788 void sensor_process_callback (void *cls, const char *line)
790 struct SensorInfo *sensorinfo = cls;
794 sensorinfo->running = GNUNET_NO;
797 GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Received a value for sensor `%s': %s\n", sensorinfo->name, line);
801 * Actual execution of a sensor
803 * @param cls 'struct SensorInfo'
807 sensor_run (void *cls,
808 const struct GNUNET_SCHEDULER_TaskContext * tc)
810 struct SensorInfo *sensorinfo = cls;
815 sensorinfo->execution_task = GNUNET_SCHEDULER_add_delayed(sensorinfo->interval, &sensor_run, sensorinfo);
816 if(GNUNET_YES == sensorinfo->running) //FIXME: should we try to kill?
818 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Sensor `%s' running for too long, will try again next interval\n", sensorinfo->name);
821 if(GNUNET_NO == should_run_sensor(sensorinfo))
823 sensorinfo->running = GNUNET_YES;
824 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Starting the execution of sensor `%s'\n", sensorinfo->name);
825 if(sources[0] == sensorinfo->source) //gnunet-statistics
827 if(NULL == statistics)
829 statistics = GNUNET_STATISTICS_create("sensor", cfg);
831 sensorinfo->gnunet_stat_get_handle = GNUNET_STATISTICS_get(statistics,
832 sensorinfo->gnunet_stat_service,
833 sensorinfo->gnunet_stat_name,
834 sensorinfo->interval, //try to get values only for the interval of the sensor
835 &end_sensor_run_stat,
836 &sensor_statistics_iterator,
839 else if(sources[1] == sensorinfo->source)
841 //FIXME: break execution if process is a path
842 //check if the process exists in $PATH
843 process_path = GNUNET_strdup(sensorinfo->ext_process);
845 GNUNET_OS_check_helper_binary(sensorinfo->ext_process, GNUNET_NO, NULL); //search in $PATH
846 if(GNUNET_SYSERR == check_result)
848 //search in sensor directory
849 sensors_dir = get_sensor_dir();
850 GNUNET_free(process_path);
851 GNUNET_asprintf(&process_path, "%s%s-files%s%s",
855 sensorinfo->ext_process);
856 GNUNET_free(sensors_dir);
858 GNUNET_OS_check_helper_binary(process_path, GNUNET_NO, NULL);
860 if(GNUNET_SYSERR == check_result)
862 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Sensor `%s' process `%s' problem: binary doesn't exist or not executable\n",
864 sensorinfo->ext_process);
865 //FIXME: disable sensor here?
866 sensorinfo->running = GNUNET_NO;
867 GNUNET_free(process_path);
870 GNUNET_OS_command_run(&sensor_process_callback,
872 GNUNET_TIME_UNIT_FOREVER_REL,
874 sensorinfo->ext_process,
875 sensorinfo->ext_args,
877 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Process started for sensor `%s'\n", sensorinfo->name);
881 sensorinfo->running = GNUNET_NO;
882 GNUNET_break(0); //shouldn't happen
887 * Starts the execution of a sensor
890 * @param key hash of sensor name, key to hashmap (unused)
891 * @param value a 'struct SensorInfo *'
892 * @return #GNUNET_YES if we should continue to
896 int schedule_sensor(void *cls,
897 const struct GNUNET_HashCode *key, void *value)
899 struct SensorInfo *sensorinfo = value;
901 if(GNUNET_NO == should_run_sensor(sensorinfo))
903 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Scheduling sensor `%s' to run after %" PRIu64 " microseconds\n",
904 sensorinfo->name, sensorinfo->interval.rel_value_us);
905 if(GNUNET_SCHEDULER_NO_TASK != sensorinfo->execution_task)
907 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Sensor `%s' execution task already set, this should not happen\n", sensorinfo->name);
910 sensorinfo->execution_task = GNUNET_SCHEDULER_add_delayed(sensorinfo->interval, &sensor_run, sensorinfo);
915 * Starts the execution of all enabled sensors
919 schedule_all_sensors()
921 GNUNET_CONTAINER_multihashmap_iterate(sensors, &schedule_sensor, NULL);
925 * Process statistics requests.
928 * @param server the initialized server
929 * @param c configuration to use
933 struct GNUNET_SERVER_Handle *server,
934 const struct GNUNET_CONFIGURATION_Handle *c)
936 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
937 {&handle_get_sensor, NULL, GNUNET_MESSAGE_TYPE_SENSOR_GET,
939 {&handle_get_all_sensors, NULL, GNUNET_MESSAGE_TYPE_SENSOR_GETALL,
940 sizeof (struct GNUNET_MessageHeader)},
945 sensors = GNUNET_CONTAINER_multihashmap_create(10, GNUNET_NO);
947 schedule_all_sensors();
948 GNUNET_SERVER_add_handlers (server, handlers);
949 GNUNET_SERVER_disconnect_notify (server,
950 &handle_client_disconnect,
952 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
959 * The main function for the sensor service.
961 * @param argc number of arguments from the command line
962 * @param argv command line arguments
963 * @return 0 ok, 1 on error
966 main (int argc, char *const *argv)
969 GNUNET_SERVICE_run (argc,
972 GNUNET_SERVICE_OPTION_NONE,
973 &run, NULL)) ? 0 : 1;
976 /* end of gnunet-service-sensor.c */