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);
223 sensorinfo->execution_task = GNUNET_SCHEDULER_NO_TASK;
229 * Task run during shutdown.
235 shutdown_task (void *cls,
236 const struct GNUNET_SCHEDULER_TaskContext *tc)
238 GNUNET_CONTAINER_multihashmap_iterate(sensors, &unschedule_sensor, NULL);
239 /* Free sensor information */
240 if(NULL != statistics)
241 GNUNET_STATISTICS_destroy(statistics, GNUNET_YES);
242 /* Destroy sensor hashmap */
243 GNUNET_SCHEDULER_shutdown();
248 * A client disconnected. Remove all of its data structure entries.
250 * @param cls closure, NULL
251 * @param client identification of the client
254 handle_client_disconnect (void *cls,
255 struct GNUNET_SERVER_Client
261 * Parses a version number string into major and minor
263 * @param version full version string
264 * @param major pointer to parsed major value
265 * @param minor pointer to parsed minor value
266 * @return #GNUNET_OK if parsing went ok, #GNUNET_SYSERROR in case of error
269 version_parse(char *version, uint16_t *major, uint16_t *minor)
274 for(; isdigit(*version); version++)
277 majorval += *version - '0';
280 return GNUNET_SYSERR;
282 for(; isdigit(*version); version++)
285 minorval += *version - '0';
288 return GNUNET_SYSERR;
296 * Load sensor definition from configuration
298 * @param cfg configuration handle
299 * @param sectionname configuration section containing definition
301 static struct SensorInfo *
302 load_sensor_from_cfg(struct GNUNET_CONFIGURATION_Handle *cfg, const char *sectionname)
304 struct SensorInfo *sensor;
308 unsigned long long time_sec;
310 sensor = GNUNET_new(struct SensorInfo);
312 sensor->name = GNUNET_strdup(sectionname);
314 if(GNUNET_OK != GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "VERSION", &version_str))
316 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor version\n"));
320 if(GNUNET_OK != version_parse(version_str, &(sensor->version_major), &(sensor->version_minor)))
322 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Invalid sensor version number, format should be major.minor\n"));
324 GNUNET_free(version_str);
327 GNUNET_free(version_str);
329 GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "DESCRIPTION", &sensor->description);
331 if(GNUNET_OK != GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "CATEGORY", &sensor->category) ||
332 NULL == sensor->category)
334 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor category\n"));
339 if(GNUNET_NO == GNUNET_CONFIGURATION_get_value_yesno(cfg, sectionname, "ENABLED"))
340 sensor->enabled = GNUNET_NO;
342 sensor->enabled = GNUNET_YES;
344 sensor->start_time = NULL;
345 if(GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "START_TIME", &starttime_str))
347 GNUNET_STRINGS_fancy_time_to_absolute(starttime_str, sensor->start_time);
348 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Start time loaded: `%s'. Parsed: %d\n", starttime_str, (NULL != sensor->start_time));
349 GNUNET_free(starttime_str);
352 sensor->end_time = NULL;
353 if(GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "END_TIME", &endtime_str))
355 GNUNET_STRINGS_fancy_time_to_absolute(endtime_str, sensor->end_time);
356 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "End time loaded: `%s'. Parsed: %d\n", endtime_str, (NULL != sensor->end_time));
357 GNUNET_free(endtime_str);
360 if(GNUNET_OK != GNUNET_CONFIGURATION_get_value_number(cfg, sectionname, "INTERVAL", &time_sec))
362 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor run interval\n"));
366 if(time_sec < MIN_INTERVAL)
368 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Sensor run interval too low (%" PRIu64 " < %d)\n"),
369 time_sec, MIN_INTERVAL);
373 sensor->interval = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, time_sec);
374 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Interval loaded: %" PRIu64 "\n", sensor->interval.rel_value_us);
376 if(GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg, sectionname, "LIFETIME", &time_sec))
378 sensor->lifetime = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, time_sec);
379 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Lifetime loaded: %" PRIu64 "\n", sensor->lifetime.rel_value_us);
382 sensor->lifetime = GNUNET_TIME_UNIT_FOREVER_REL;
385 if(GNUNET_OK != GNUNET_CONFIGURATION_get_value_choice(cfg, sectionname, "SOURCE", sources, (const char **)&sensor->source))
387 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor source\n"));
391 if(sources[0] == sensor->source) //gnunet-statistics
393 if(GNUNET_OK != GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "GNUNET_STAT_SERVICE", &sensor->gnunet_stat_service) ||
394 GNUNET_OK != GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "GNUNET_STAT_NAME", &sensor->gnunet_stat_name))
396 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor gnunet-statistics source information\n"));
400 sensor->gnunet_stat_get_handle = NULL;
402 else if(sources[1] == sensor->source) //process
404 if(GNUNET_OK != GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "EXT_PROCESS", &sensor->ext_process))
406 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor process name\n"));
410 GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "EXT_ARGS", &sensor->ext_args);
413 if(GNUNET_OK != GNUNET_CONFIGURATION_get_value_choice(cfg, sectionname, "EXPECTED_DATATYPE", datatypes, (const char **)&sensor->expected_datatype))
415 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor expected datatype\n"));
419 if(sources[0] == sensor->source && datatypes[0] != sensor->expected_datatype)
421 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Invalid expected datatype, gnunet-statistics returns uint64 values\n"));
425 //TODO: reporting mechanism
427 sensor->execution_task = GNUNET_SCHEDULER_NO_TASK;
429 sensor->running = GNUNET_NO;
435 * Load sensor definition from file
437 * @param filename full path to file containing sensor definition
439 static struct SensorInfo *
440 load_sensor_from_file(const char *filename)
442 struct GNUNET_CONFIGURATION_Handle *sensorcfg;
443 const char *filebasename;
444 struct SensorInfo *sensor;
447 if(GNUNET_YES != GNUNET_DISK_file_test(filename))
449 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Failed to access sensor file: %s\n"), filename);
452 //load file as configuration
453 sensorcfg = GNUNET_CONFIGURATION_create();
454 if(GNUNET_SYSERR == GNUNET_CONFIGURATION_parse(sensorcfg, filename))
456 GNUNET_CONFIGURATION_destroy(sensorcfg);
457 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Failed to load sensor definition: %s\n"), filename);
460 //configuration section should be the same as filename
461 filebasename = GNUNET_STRINGS_get_short_name(filename);
462 sensor = load_sensor_from_cfg(sensorcfg, filebasename);
463 sensor->def_file = GNUNET_strdup(filename);
465 GNUNET_CONFIGURATION_destroy(sensorcfg);
471 * Compares version numbers of two sensors
473 * @param s1 first sensor
474 * @param s2 second sensor
475 * @return 1: s1 > s2, 0: s1 == s2, -1: s1 < s2
478 sensor_version_compare(struct SensorInfo *s1, struct SensorInfo *s2)
480 if(s1->version_major == s2->version_major)
481 return (s1->version_minor < s2->version_minor) ? -1 : (s1->version_minor > s2->version_minor);
483 return (s1->version_major < s2->version_major) ? -1 : (s1->version_major > s2->version_major);
487 * Adds a new sensor to given hashmap.
488 * If the same name exist, compares versions and update if old.
490 * @param sensor Sensor structure to add
491 * @param map Hashmap to add to
492 * @return #GNUNET_YES if added, #GNUNET_NO if not added which is not necessarily an error
495 add_sensor_to_hashmap(struct SensorInfo *sensor, struct GNUNET_CONTAINER_MultiHashMap *map)
497 struct GNUNET_HashCode key;
498 struct SensorInfo *existing;
500 GNUNET_CRYPTO_hash(sensor->name, strlen(sensor->name), &key);
501 existing = GNUNET_CONTAINER_multihashmap_get(map, &key);
502 if(NULL != existing) //sensor with same name already exists
504 if(sensor_version_compare(existing, sensor) >= 0) //same or newer version already exist
506 GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Sensor `%s' already exists with same or newer version\n"), sensor->name);
511 GNUNET_CONTAINER_multihashmap_remove(map, &key, existing); //remove the old version
512 GNUNET_free(existing);
513 GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Upgrading sensor `%s' to a newer version\n"), sensor->name);
516 if(GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_put(map, &key, sensor, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
518 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Error adding new sensor `%s' to global hashmap, this should not happen\n"), sensor->name);
526 * Iterating over files in sensors directory
529 * @param filename complete filename (absolute path)
530 * @return #GNUNET_OK to continue to iterate,
531 * #GNUNET_NO to stop iteration with no error,
532 * #GNUNET_SYSERR to abort iteration with error!
535 reload_sensors_dir_cb(void *cls, const char *filename)
537 struct SensorInfo *sensor;
539 sensor = load_sensor_from_file(filename);
542 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Error loading sensor from file: %s\n"), filename);
545 if(GNUNET_YES == add_sensor_to_hashmap(sensor, sensors))
546 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, _("Sensor `%s' added to global hashmap\n"), sensor->name);
548 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, ("Could not add sensor `%s' to global hashmap\n"), sensor->name);
554 * Get path to the directory containing the sensor definition files
556 * @return sensor files directory
564 datadir = GNUNET_OS_installation_get_path(GNUNET_OS_IPK_DATADIR);
565 GNUNET_asprintf(&sensordir, "%ssensors%s",
566 datadir, DIR_SEPARATOR_STR);
572 * Reads sensor definitions from data files
581 sensordir = get_sensor_dir();
582 GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Reloading sensor definitions from directory `%s'\n"), sensordir);
583 GNUNET_assert(GNUNET_YES == GNUNET_DISK_directory_test(sensordir, GNUNET_YES));
585 //read all files in sensors directory
586 filesfound = GNUNET_DISK_directory_scan(sensordir, &reload_sensors_dir_cb, NULL);
587 GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Loaded %d/%d sensors from directory `%s'\n"),
588 GNUNET_CONTAINER_multihashmap_size(sensors), filesfound, sensordir);
592 * Creates a structure with basic sensor info to be sent to a client
594 * @param sensor sensor information
595 * @return message ready to be sent to client
597 static struct SensorInfoMessage *
598 create_sensor_info_msg(struct SensorInfo *sensor)
600 struct SensorInfoMessage *msg;
606 name_len = strlen(sensor->name);
607 if(NULL == sensor->description)
610 /* FIXME strlen + 1 */
611 desc_len = strlen(sensor->description);
613 len += sizeof(struct SensorInfoMessage);
616 msg = GNUNET_malloc(len);
617 msg->header.size = htons(len);
618 msg->header.type = htons(GNUNET_MESSAGE_TYPE_SENSOR_INFO);
619 msg->name_len = htons(name_len);
620 msg->description_len = htons(desc_len);
621 msg->version_major = htons(sensor->version_major);
622 msg->version_minor = htons(sensor->version_minor);
623 str_ptr = (char*) &msg[1];
624 memcpy(str_ptr, sensor->name, name_len);
625 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Sending sensor name (%d): %.*s\n",
626 name_len, name_len, str_ptr);
628 memcpy(str_ptr, sensor->description, desc_len);
629 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Sending sensor description (%d): %.*s\n",
630 desc_len, desc_len, str_ptr);
636 * Handle GET SENSOR message.
639 * @param client identification of the client
640 * @param message the actual message
643 handle_get_sensor (void *cls, struct GNUNET_SERVER_Client *client,
644 const struct GNUNET_MessageHeader *message)
646 struct GNUNET_SERVER_TransmitContext *tc;
648 size_t sensorname_len;
649 struct GNUNET_HashCode key;
650 struct SensorInfo *sensorinfo;
651 struct SensorInfoMessage *msg;
653 sensorname = (char *)&message[1];
654 sensorname_len = ntohs(message->size) - sizeof(struct GNUNET_MessageHeader);
655 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "`%s' message received for sensor (%d) `%.*s'\n",
656 "GET SENSOR", sensorname_len, sensorname_len, sensorname);
657 tc = GNUNET_SERVER_transmit_context_create (client);
658 GNUNET_CRYPTO_hash(sensorname, sensorname_len, &key);
659 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Created key hash for requested sensor\n");
660 sensorinfo = (struct SensorInfo *)GNUNET_CONTAINER_multihashmap_get(sensors, &key);
661 if(NULL != sensorinfo)
663 msg = create_sensor_info_msg(sensorinfo);
664 GNUNET_SERVER_transmit_context_append_message(tc, (struct GNUNET_MessageHeader *)msg);
668 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Requested sensor `%.*s' was not found\n",
669 sensorname_len, sensorname);
670 GNUNET_SERVER_transmit_context_append_data(tc, NULL, 0, GNUNET_MESSAGE_TYPE_SENSOR_END);
671 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
675 * Iterator for sensors and adds them to transmit context
677 * @param cls a 'struct GNUNET_SERVER_TransmitContext *'
678 * @param key hash of sensor name, key to hashmap
679 * @param value a 'struct SensorInfo *'
681 int add_sensor_to_tc(void *cls,
682 const struct GNUNET_HashCode *key, void *value)
684 struct GNUNET_SERVER_TransmitContext *tc = cls;
685 struct SensorInfo *sensorinfo = value;
686 struct SensorInfoMessage *msg;
688 msg = create_sensor_info_msg(sensorinfo);
689 GNUNET_SERVER_transmit_context_append_message(tc, (struct GNUNET_MessageHeader *)msg);
697 * Handle GET ALL SENSORS message.
700 * @param client identification of the client
701 * @param message the actual message
704 handle_get_all_sensors (void *cls, struct GNUNET_SERVER_Client *client,
705 const struct GNUNET_MessageHeader *message)
707 struct GNUNET_SERVER_TransmitContext *tc;
709 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "`%s' message received.\n",
711 tc = GNUNET_SERVER_transmit_context_create (client);
712 GNUNET_CONTAINER_multihashmap_iterate(sensors, &add_sensor_to_tc, tc);
713 GNUNET_SERVER_transmit_context_append_data(tc, NULL, 0, GNUNET_MESSAGE_TYPE_SENSOR_END);
714 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
718 * Do a series of checks to determine if sensor should execute
720 * @return #GNUNET_YES / #GNUNET_NO
723 should_run_sensor(struct SensorInfo *sensorinfo)
725 //FIXME: some checks should disable the sensor (e.g. expired)
726 struct GNUNET_TIME_Absolute now;
728 if(GNUNET_NO == sensorinfo->enabled)
730 GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Sensor `%s' is disabled, will not run\n", sensorinfo->name);
733 now = GNUNET_TIME_absolute_get();
734 if(NULL != sensorinfo->start_time
735 && now.abs_value_us < sensorinfo->start_time->abs_value_us)
737 GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Start time for sensor `%s' not reached yet, will not run\n", sensorinfo->name);
740 if(NULL != sensorinfo->end_time
741 && now.abs_value_us >= sensorinfo->end_time->abs_value_us)
743 GNUNET_log(GNUNET_ERROR_TYPE_INFO, "End time for sensor `%s' passed, will not run\n", sensorinfo->name);
750 * Callback function to process statistic values
752 * @param cls 'struct SensorInfo *'
753 * @param subsystem name of subsystem that created the statistic
754 * @param name the name of the datum
755 * @param value the current value
756 * @param is_persistent #GNUNET_YES if the value is persistent, #GNUNET_NO if not
757 * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
759 int sensor_statistics_iterator (void *cls,
760 const char *subsystem,
765 struct SensorInfo *sensorinfo = cls;
767 GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Received a value for sensor `%s': %" PRIu64 "\n", sensorinfo->name, value);
772 * Continuation called after sensor gets all gnunet statistics values
774 * @param cls 'struct SensorInfo *'
775 * @param success #GNUNET_OK if statistics were
776 * successfully obtained, #GNUNET_SYSERR if not.
778 void end_sensor_run_stat (void *cls, int success)
780 struct SensorInfo *sensorinfo = cls;
782 sensorinfo->gnunet_stat_get_handle = NULL;
783 sensorinfo->running = GNUNET_NO;
787 * Callback for output of executed sensor process
789 * @param cls 'struct SensorInfo *'
790 * @param line line of output from a command, NULL for the end
792 void sensor_process_callback (void *cls, const char *line)
794 struct SensorInfo *sensorinfo = cls;
798 sensorinfo->running = GNUNET_NO;
801 GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Received a value for sensor `%s': %s\n", sensorinfo->name, line);
805 * Actual execution of a sensor
807 * @param cls 'struct SensorInfo'
811 sensor_run (void *cls,
812 const struct GNUNET_SCHEDULER_TaskContext * tc)
814 struct SensorInfo *sensorinfo = cls;
819 sensorinfo->execution_task = GNUNET_SCHEDULER_add_delayed(sensorinfo->interval, &sensor_run, sensorinfo);
820 if(GNUNET_YES == sensorinfo->running) //FIXME: should we try to kill?
822 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Sensor `%s' running for too long, will try again next interval\n", sensorinfo->name);
825 if(GNUNET_NO == should_run_sensor(sensorinfo))
827 sensorinfo->running = GNUNET_YES;
828 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Starting the execution of sensor `%s'\n", sensorinfo->name);
829 if(sources[0] == sensorinfo->source) //gnunet-statistics
831 if(NULL == statistics)
833 statistics = GNUNET_STATISTICS_create("sensor", cfg);
835 sensorinfo->gnunet_stat_get_handle = GNUNET_STATISTICS_get(statistics,
836 sensorinfo->gnunet_stat_service,
837 sensorinfo->gnunet_stat_name,
838 sensorinfo->interval, //try to get values only for the interval of the sensor
839 &end_sensor_run_stat,
840 &sensor_statistics_iterator,
843 else if(sources[1] == sensorinfo->source)
845 //FIXME: break execution if process is a path
846 //check if the process exists in $PATH
847 process_path = GNUNET_strdup(sensorinfo->ext_process);
849 GNUNET_OS_check_helper_binary(sensorinfo->ext_process, GNUNET_NO, NULL); //search in $PATH
850 if(GNUNET_SYSERR == check_result)
852 //search in sensor directory
853 sensors_dir = get_sensor_dir();
854 GNUNET_free(process_path);
855 GNUNET_asprintf(&process_path, "%s%s-files%s%s",
859 sensorinfo->ext_process);
860 GNUNET_free(sensors_dir);
862 GNUNET_OS_check_helper_binary(process_path, GNUNET_NO, NULL);
864 if(GNUNET_SYSERR == check_result)
866 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Sensor `%s' process `%s' problem: binary doesn't exist or not executable\n",
868 sensorinfo->ext_process);
869 //FIXME: disable sensor here?
870 sensorinfo->running = GNUNET_NO;
871 GNUNET_free(process_path);
874 GNUNET_OS_command_run(&sensor_process_callback,
876 GNUNET_TIME_UNIT_FOREVER_REL,
878 sensorinfo->ext_process,
879 sensorinfo->ext_args,
881 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Process started for sensor `%s'\n", sensorinfo->name);
885 sensorinfo->running = GNUNET_NO;
886 GNUNET_break(0); //shouldn't happen
891 * Starts the execution of a sensor
894 * @param key hash of sensor name, key to hashmap (unused)
895 * @param value a 'struct SensorInfo *'
896 * @return #GNUNET_YES if we should continue to
900 int schedule_sensor(void *cls,
901 const struct GNUNET_HashCode *key, void *value)
903 struct SensorInfo *sensorinfo = value;
905 if(GNUNET_NO == should_run_sensor(sensorinfo))
907 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Scheduling sensor `%s' to run after %" PRIu64 " microseconds\n",
908 sensorinfo->name, sensorinfo->interval.rel_value_us);
909 if(GNUNET_SCHEDULER_NO_TASK != sensorinfo->execution_task)
911 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Sensor `%s' execution task already set, this should not happen\n", sensorinfo->name);
914 sensorinfo->execution_task = GNUNET_SCHEDULER_add_delayed(sensorinfo->interval, &sensor_run, sensorinfo);
919 * Starts the execution of all enabled sensors
923 schedule_all_sensors()
925 GNUNET_CONTAINER_multihashmap_iterate(sensors, &schedule_sensor, NULL);
929 * Process statistics requests.
932 * @param server the initialized server
933 * @param c configuration to use
937 struct GNUNET_SERVER_Handle *server,
938 const struct GNUNET_CONFIGURATION_Handle *c)
940 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
941 {&handle_get_sensor, NULL, GNUNET_MESSAGE_TYPE_SENSOR_GET,
943 {&handle_get_all_sensors, NULL, GNUNET_MESSAGE_TYPE_SENSOR_GETALL,
944 sizeof (struct GNUNET_MessageHeader)},
949 sensors = GNUNET_CONTAINER_multihashmap_create(10, GNUNET_NO);
951 schedule_all_sensors();
952 GNUNET_SERVER_add_handlers (server, handlers);
953 GNUNET_SERVER_disconnect_notify (server,
954 &handle_client_disconnect,
956 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
963 * The main function for the sensor service.
965 * @param argc number of arguments from the command line
966 * @param argv command line arguments
967 * @return 0 ok, 1 on error
970 main (int argc, char *const *argv)
973 GNUNET_SERVICE_run (argc,
976 GNUNET_SERVICE_OPTION_NONE,
977 &run, NULL)) ? 0 : 1;
980 /* end of gnunet-service-sensor.c */