fix in sensor scheduling
[oweals/gnunet.git] / src / sensor / gnunet-service-sensor.c
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.c
23  * @brief sensor service implementation
24  * @author Omar Tarabai
25  */
26 #include <inttypes.h>
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29 #include "sensor.h"
30
31 /**
32  * Structure containing sensor definition
33  */
34 struct SensorInfo
35 {
36
37   /*
38    * Sensor name
39    */
40   char *name;
41
42   /*
43    * Path to definition file
44    */
45   char *def_file;
46
47   /*
48    * First part of version number
49    */
50   uint16_t version_major;
51
52   /*
53    * Second part of version number
54    */
55   uint16_t version_minor;
56
57   /*
58    * Sensor description
59    */
60   char *description;
61
62   /*
63    * Sensor currently enabled
64    */
65   int enabled;
66
67   /*
68    * Category under which the sensor falls (e.g. tcp, datastore)
69    */
70   char *category;
71
72   /*
73    * When does the sensor become active
74    */
75   struct GNUNET_TIME_Absolute *start_time;
76
77   /*
78    * When does the sensor expire
79    */
80   struct GNUNET_TIME_Absolute *end_time;
81
82   /*
83    * Time interval to collect sensor information (e.g. every 1 min)
84    */
85   struct GNUNET_TIME_Relative interval;
86
87   /*
88    * Lifetime of an information sample after which it is deleted from storage
89    */
90   struct GNUNET_TIME_Relative *lifetime;
91
92   /*
93    * A set of required peer capabilities for the sensor to collect meaningful information (e.g. ipv6)
94    */
95   char *capabilities;
96
97   /*
98    * Either "gnunet-statistics" or external "process"
99    */
100   char *source;
101
102   /*
103    * Name of the GNUnet service that is the source for the gnunet-statistics entry
104    */
105   char *gnunet_stat_service;
106
107   /*
108    * Name of the gnunet-statistics entry
109    */
110   char *gnunet_stat_name;
111
112   /*
113    * Name of the external process to be executed
114    */
115   char *ext_process;
116
117   /*
118    * Arguments to be passed to the external process
119    */
120   char *ext_args;
121
122   /*
123    * The output datatype to be expected
124    */
125   char *expected_datatype;
126
127   /*
128    * Peer-identity of peer running collection point
129    */
130   struct GNUNET_PeerIdentity *collection_point;
131
132   /*
133    * Time interval to send sensor information to collection point (e.g. every 30 mins)
134    */
135   struct GNUNET_TIME_Relative *collection_interval;
136
137   /*
138    * Flag specifying if value is to be communicated to the p2p network
139    */
140   int p2p_report;
141
142   /*
143    * Time interval to communicate value to the p2p network
144    */
145   struct GNUNET_TIME_Relative *p2p_interval;
146
147   /**
148    * Execution task (OR GNUNET_SCHEDULER_NO_TASK)
149    */
150   GNUNET_SCHEDULER_TaskIdentifier execution_task;
151
152 };
153
154 /**
155  * Our configuration.
156  */
157 static const struct GNUNET_CONFIGURATION_Handle *cfg;
158
159 /**
160  * Hashmap of loaded sensor definitions
161  */
162 struct GNUNET_CONTAINER_MultiHashMap *sensors;
163
164 /**
165  * Remove sensor execution from scheduler
166  *
167  * @param cls unused
168  * @param key hash of sensor name, key to hashmap
169  * @param value a 'struct SensorInfo *'
170  * @return #GNUNET_YES if we should continue to
171  *         iterate,
172  *         #GNUNET_NO if not.
173  */
174 int unschedule_sensor(void *cls,
175     const struct GNUNET_HashCode *key, void *value)
176 {
177   struct SensorInfo *sensorinfo = value;
178
179   if(GNUNET_SCHEDULER_NO_TASK != sensorinfo->execution_task)
180   {
181     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Unscheduling sensor `%s'\n", sensorinfo->name);
182     GNUNET_SCHEDULER_cancel(sensorinfo->execution_task);
183   }
184   return GNUNET_YES;
185 }
186
187 /**
188  * Task run during shutdown.
189  *
190  * @param cls unused
191  * @param tc unused
192  */
193 static void
194 shutdown_task (void *cls,
195                const struct GNUNET_SCHEDULER_TaskContext *tc)
196 {
197   GNUNET_CONTAINER_multihashmap_iterate(sensors, &unschedule_sensor, NULL);
198   GNUNET_SCHEDULER_shutdown();
199 }
200
201
202 /**
203  * A client disconnected.  Remove all of its data structure entries.
204  *
205  * @param cls closure, NULL
206  * @param client identification of the client
207  */
208 static void
209 handle_client_disconnect (void *cls,
210                           struct GNUNET_SERVER_Client
211                           * client)
212 {
213 }
214
215 /**
216  * Parses a version number string into major and minor
217  *
218  * @param version full version string
219  * @param major pointer to parsed major value
220  * @param minor pointer to parsed minor value
221  * @return #GNUNET_OK if parsing went ok, #GNUNET_SYSERROR in case of error
222  */
223 static int
224 version_parse(char *version, uint16_t *major, uint16_t *minor)
225 {
226   int majorval = 0;
227   int minorval = 0;
228
229   for(; isdigit(*version); version++)
230   {
231     majorval *= 10;
232     majorval += *version - '0';
233   }
234   if(*version != '.')
235     return GNUNET_SYSERR;
236   version++;
237   for(; isdigit(*version); version++)
238   {
239     minorval *= 10;
240     minorval += *version - '0';
241   }
242   if(*version != 0)
243     return GNUNET_SYSERR;
244   *major = majorval;
245   *minor = minorval;
246
247   return GNUNET_OK;
248 }
249
250 /**
251  * Load sensor definition from configuration
252  *
253  * @param cfg configuration handle
254  * @param sectionname configuration section containing definition
255  */
256 static struct SensorInfo *
257 load_sensor_from_cfg(struct GNUNET_CONFIGURATION_Handle *cfg, const char *sectionname)
258 {
259   struct SensorInfo *sensor;
260   char *version_str;
261   char *starttime_str;
262   char *endtime_str;
263   unsigned long long interval_sec;
264
265   sensor = GNUNET_new(struct SensorInfo);
266   //name
267   sensor->name = GNUNET_strdup(sectionname);
268   //version
269   if(GNUNET_OK != GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "VERSION", &version_str))
270   {
271     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor version\n"));
272     GNUNET_free(sensor);
273     return NULL;
274   }
275   if(GNUNET_OK != version_parse(version_str, &(sensor->version_major), &(sensor->version_minor)))
276   {
277     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Invalid sensor version number, format should be major.minor\n"));
278     GNUNET_free(sensor);
279     GNUNET_free(version_str);
280     return NULL;
281   }
282   GNUNET_free(version_str);
283   //description
284   GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "DESCRIPTION", &sensor->description);
285   //category
286   if(GNUNET_OK != GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "CATEGORY", &sensor->category) ||
287         NULL == sensor->category)
288   {
289     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor category\n"));
290     GNUNET_free(sensor);
291     return NULL;
292   }
293   //enabled
294   if(GNUNET_NO == GNUNET_CONFIGURATION_get_value_yesno(cfg, sectionname, "ENABLED"))
295     sensor->enabled = GNUNET_NO;
296   else
297     sensor->enabled = GNUNET_YES;
298   //start time
299   sensor->start_time = NULL;
300   if(GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "START_TIME", &starttime_str))
301   {
302     GNUNET_STRINGS_fancy_time_to_absolute(starttime_str, sensor->start_time);
303     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Start time loaded: `%s'. Parsed: %d\n", starttime_str, (NULL != sensor->start_time));
304     GNUNET_free(starttime_str);
305   }
306   //end time
307   sensor->end_time = NULL;
308   if(GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, sectionname, "END_TIME", &endtime_str))
309   {
310     GNUNET_STRINGS_fancy_time_to_absolute(endtime_str, sensor->end_time);
311     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "End time loaded: `%s'. Parsed: %d\n", endtime_str, (NULL != sensor->end_time));
312     GNUNET_free(endtime_str);
313   }
314   //interval
315   if(GNUNET_OK != GNUNET_CONFIGURATION_get_value_number(cfg, sectionname, "INTERVAL", &interval_sec))
316   {
317     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Error reading sensor run interval\n"));
318     GNUNET_free(sensor);
319     return NULL;
320   }
321   sensor->interval = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, interval_sec);
322   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Interval loaded: %" PRIu64 "\n", sensor->interval.rel_value_us);
323   //execution task
324   sensor->execution_task = GNUNET_SCHEDULER_NO_TASK;
325
326   return sensor;
327 }
328
329 /**
330  * Load sensor definition from file
331  *
332  * @param filename full path to file containing sensor definition
333  */
334 static struct SensorInfo *
335 load_sensor_from_file(const char *filename)
336 {
337   struct GNUNET_CONFIGURATION_Handle *sensorcfg;
338   const char *filebasename;
339   struct SensorInfo *sensor;
340
341   //test file
342   if(GNUNET_YES != GNUNET_DISK_file_test(filename))
343   {
344     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Failed to access sensor file: %s\n"), filename);
345     return NULL;
346   }
347   //load file as configuration
348   sensorcfg = GNUNET_CONFIGURATION_create();
349   if(GNUNET_SYSERR == GNUNET_CONFIGURATION_parse(sensorcfg, filename))
350   {
351     GNUNET_CONFIGURATION_destroy(sensorcfg);
352     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Failed to load sensor definition: %s\n"), filename);
353     return NULL;
354   }
355   //configuration section should be the same as filename
356   filebasename = GNUNET_STRINGS_get_short_name(filename);
357   sensor = load_sensor_from_cfg(sensorcfg, filebasename);
358   sensor->def_file = GNUNET_strdup(filename);
359
360   GNUNET_CONFIGURATION_destroy(sensorcfg);
361
362   return sensor;
363 }
364
365 /**
366  * Compares version numbers of two sensors
367  *
368  * @param s1 first sensor
369  * @param s2 second sensor
370  * @return 1: s1 > s2, 0: s1 == s2, -1: s1 < s2
371  */
372 static int
373 sensor_version_compare(struct SensorInfo *s1, struct SensorInfo *s2)
374 {
375   if(s1->version_major == s2->version_major)
376     return (s1->version_minor < s2->version_minor) ? -1 : (s1->version_minor > s2->version_minor);
377   else
378     return (s1->version_major < s2->version_major) ? -1 : (s1->version_major > s2->version_major);
379 }
380
381 /**
382  * Adds a new sensor to given hashmap.
383  * If the same name exist, compares versions and update if old.
384  *
385  * @param sensor Sensor structure to add
386  * @param map Hashmap to add to
387  * @return #GNUNET_YES if added, #GNUNET_NO if not added which is not necessarily an error
388  */
389 static int
390 add_sensor_to_hashmap(struct SensorInfo *sensor, struct GNUNET_CONTAINER_MultiHashMap *map)
391 {
392   struct GNUNET_HashCode key;
393   struct SensorInfo *existing;
394
395   GNUNET_CRYPTO_hash(sensor->name, strlen(sensor->name), &key);
396   existing = GNUNET_CONTAINER_multihashmap_get(map, &key);
397   if(NULL != existing) //sensor with same name already exists
398   {
399     if(sensor_version_compare(existing, sensor) >= 0) //same or newer version already exist
400     {
401       GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Sensor `%s' already exists with same or newer version\n"), sensor->name);
402       return GNUNET_NO;
403     }
404     else
405     {
406       GNUNET_CONTAINER_multihashmap_remove(map, &key, existing); //remove the old version
407       GNUNET_free(existing);
408       GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Upgrading sensor `%s' to a newer version\n"), sensor->name);
409     }
410   }
411   if(GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_put(map, &key, sensor, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
412   {
413     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Error adding new sensor `%s' to global hashmap, this should not happen\n"), sensor->name);
414     return GNUNET_NO;
415   }
416
417   return GNUNET_YES;
418 }
419
420 /**
421  * Iterating over files in sensors directory
422  *
423  * @param cls closure
424  * @param filename complete filename (absolute path)
425  * @return #GNUNET_OK to continue to iterate,
426  *  #GNUNET_NO to stop iteration with no error,
427  *  #GNUNET_SYSERR to abort iteration with error!
428  */
429 static int
430 reload_sensors_dir_cb(void *cls, const char *filename)
431 {
432   struct SensorInfo *sensor;
433
434   sensor = load_sensor_from_file(filename);
435   if(NULL == sensor)
436   {
437     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Error loading sensor from file: %s\n"), filename);
438     return GNUNET_OK;
439   }
440   if(GNUNET_YES == add_sensor_to_hashmap(sensor, sensors))
441     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, _("Sensor `%s' added to global hashmap\n"), sensor->name);
442   else
443     GNUNET_log(GNUNET_ERROR_TYPE_WARNING, ("Could not add sensor `%s' to global hashmap\n"), sensor->name);
444
445   return GNUNET_OK;
446 }
447
448 /*
449  * Get path to the directory containing the sensor definition files
450  *
451  * @return sensor files directory
452  */
453 static char *
454 get_sensor_dir()
455 {
456   char* datadir;
457   char* sensordir;
458
459   datadir = GNUNET_OS_installation_get_path(GNUNET_OS_IPK_DATADIR);
460   GNUNET_asprintf(&sensordir, "%ssensors%s",
461       datadir, DIR_SEPARATOR_STR);
462
463   return sensordir;
464 }
465
466 /**
467  * Reads sensor definitions from data files
468  *
469  */
470 static void
471 reload_sensors()
472 {
473   char* sensordir;
474   int filesfound;
475
476   sensordir = get_sensor_dir();
477   GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Reloading sensor definitions from directory `%s'\n"), sensordir);
478   GNUNET_assert(GNUNET_YES == GNUNET_DISK_directory_test(sensordir, GNUNET_YES));
479
480   //read all files in sensors directory
481   filesfound = GNUNET_DISK_directory_scan(sensordir, &reload_sensors_dir_cb, NULL);
482   GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Loaded %d/%d sensors from directory `%s'\n"),
483       GNUNET_CONTAINER_multihashmap_size(sensors), filesfound, sensordir);
484 }
485
486 /**
487  * Creates a structure with basic sensor info to be sent to a client
488  *
489  * @param sensor sensor information
490  * @return message ready to be sent to client
491  */
492 static struct SensorInfoMessage *
493 create_sensor_info_msg(struct SensorInfo *sensor)
494 {
495   struct SensorInfoMessage *msg;
496   uint16_t len;
497   size_t name_len;
498   size_t desc_len;
499   char *str_ptr;
500
501   name_len = strlen(sensor->name);
502   if(NULL == sensor->description)
503     desc_len = 0;
504   else
505     desc_len = strlen(sensor->description);
506   len = 0;
507   len += sizeof(struct SensorInfoMessage);
508   len += name_len;
509   len += desc_len;
510   msg = GNUNET_malloc(len);
511   msg->header.size = htons(len);
512   msg->header.type = htons(GNUNET_MESSAGE_TYPE_SENSOR_INFO);
513   msg->name_len = htons(name_len);
514   msg->description_len = htons(desc_len);
515   msg->version_major = htons(sensor->version_major);
516   msg->version_minor = htons(sensor->version_minor);
517   str_ptr = (char*) &msg[1];
518   memcpy(str_ptr, sensor->name, name_len);
519   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Sending sensor name (%d): %.*s\n",
520         name_len, name_len, str_ptr);
521   str_ptr += name_len;
522   memcpy(str_ptr, sensor->description, desc_len);
523   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Sending sensor description (%d): %.*s\n",
524           desc_len, desc_len, str_ptr);
525
526   return msg;
527 }
528
529 /**
530  * Handle GET SENSOR message.
531  *
532  * @param cls closure
533  * @param client identification of the client
534  * @param message the actual message
535  */
536 static void
537 handle_get_sensor (void *cls, struct GNUNET_SERVER_Client *client,
538             const struct GNUNET_MessageHeader *message)
539 {
540   struct GNUNET_SERVER_TransmitContext *tc;
541   char *sensorname;
542   size_t sensorname_len;
543   struct GNUNET_HashCode key;
544   struct SensorInfo *sensorinfo;
545   struct SensorInfoMessage *msg;
546
547   sensorname = (char *)&message[1];
548   sensorname_len = ntohs(message->size) - sizeof(struct GNUNET_MessageHeader);
549   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "`%s' message received for sensor (%d) `%.*s'\n",
550               "GET SENSOR", sensorname_len, sensorname_len, sensorname);
551   tc = GNUNET_SERVER_transmit_context_create (client);
552   GNUNET_CRYPTO_hash(sensorname, sensorname_len, &key);
553   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Created key hash for requested sensor\n");
554   sensorinfo = (struct SensorInfo *)GNUNET_CONTAINER_multihashmap_get(sensors, &key);
555   if(NULL != sensorinfo)
556   {
557     msg = create_sensor_info_msg(sensorinfo);
558     GNUNET_SERVER_transmit_context_append_message(tc, (struct GNUNET_MessageHeader *)msg);
559     GNUNET_free(msg);
560   }
561   else
562     GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Requested sensor `%.*s' was not found\n",
563         sensorname_len, sensorname);
564   GNUNET_SERVER_transmit_context_append_data(tc, NULL, 0, GNUNET_MESSAGE_TYPE_SENSOR_END);
565   GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
566 }
567
568 /**
569  * Iterator for sensors and adds them to transmit context
570  *
571  * @param cls a 'struct GNUNET_SERVER_TransmitContext *'
572  * @param key hash of sensor name, key to hashmap
573  * @param value a 'struct SensorInfo *'
574  */
575 int add_sensor_to_tc(void *cls,
576     const struct GNUNET_HashCode *key, void *value)
577 {
578   struct GNUNET_SERVER_TransmitContext *tc = cls;
579   struct SensorInfo *sensorinfo = value;
580   struct SensorInfoMessage *msg;
581
582   msg = create_sensor_info_msg(sensorinfo);
583   GNUNET_SERVER_transmit_context_append_message(tc, (struct GNUNET_MessageHeader *)msg);
584
585   GNUNET_free(msg);
586
587   return GNUNET_YES;
588 }
589
590 /**
591  * Handle GET ALL SENSORS message.
592  *
593  * @param cls closure
594  * @param client identification of the client
595  * @param message the actual message
596  */
597 static void
598 handle_get_all_sensors (void *cls, struct GNUNET_SERVER_Client *client,
599             const struct GNUNET_MessageHeader *message)
600 {
601   struct GNUNET_SERVER_TransmitContext *tc;
602
603   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "`%s' message received.\n",
604                 "GET ALL SENSOR");
605   tc = GNUNET_SERVER_transmit_context_create (client);
606   GNUNET_CONTAINER_multihashmap_iterate(sensors, &add_sensor_to_tc, tc);
607   GNUNET_SERVER_transmit_context_append_data(tc, NULL, 0, GNUNET_MESSAGE_TYPE_SENSOR_END);
608   GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
609 }
610
611 /**
612  * Do a series of checks to determine if sensor should execute
613  *
614  * @return #GNUNET_YES / #GNUNET_NO
615  */
616 static int
617 should_run_sensor(struct SensorInfo *sensorinfo)
618 {
619   struct GNUNET_TIME_Absolute now;
620
621   if(GNUNET_NO == sensorinfo->enabled)
622   {
623     GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Sensor `%s' is disabled, will not run\n", sensorinfo->name);
624     return GNUNET_NO;
625   }
626   now = GNUNET_TIME_absolute_get();
627   if(NULL != sensorinfo->start_time
628       && now.abs_value_us < sensorinfo->start_time->abs_value_us)
629   {
630     GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Start time for sensor `%s' not reached yet, will not run\n", sensorinfo->name);
631     return GNUNET_NO;
632   }
633   if(NULL != sensorinfo->end_time
634       && now.abs_value_us >= sensorinfo->end_time->abs_value_us)
635   {
636     GNUNET_log(GNUNET_ERROR_TYPE_INFO, "End time for sensor `%s' passed, will not run\n", sensorinfo->name);
637     return GNUNET_NO;
638   }
639   return GNUNET_YES;
640 }
641
642 /**
643  * Actual execution of a sensor
644  *
645  * @param cls 'struct SensorInfo'
646  * @param tc unsed
647  */
648 void
649 run_sensor (void *cls,
650     const struct GNUNET_SCHEDULER_TaskContext * tc)
651 {
652   struct SensorInfo *sensorinfo = cls;
653
654   sensorinfo->execution_task = GNUNET_SCHEDULER_NO_TASK;
655   if(GNUNET_NO == should_run_sensor(sensorinfo))
656     return;
657   sensorinfo->execution_task = GNUNET_SCHEDULER_add_delayed(sensorinfo->interval, &run_sensor, sensorinfo);
658   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Starting the execution of sensor `%s'\n", sensorinfo->name);
659 }
660
661 /**
662  * Starts the execution of a sensor
663  *
664  * @param cls unused
665  * @param key hash of sensor name, key to hashmap
666  * @param value a 'struct SensorInfo *'
667  * @return #GNUNET_YES if we should continue to
668  *         iterate,
669  *         #GNUNET_NO if not.
670  */
671 int schedule_sensor(void *cls,
672     const struct GNUNET_HashCode *key, void *value)
673 {
674   struct SensorInfo *sensorinfo = value;
675
676   if(GNUNET_NO == should_run_sensor(sensorinfo))
677     return GNUNET_YES;
678   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Scheduling sensor `%s' to run after %" PRIu64 " microseconds\n",
679       sensorinfo->name, sensorinfo->interval.rel_value_us);
680   if(GNUNET_SCHEDULER_NO_TASK != sensorinfo->execution_task)
681   {
682     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Sensor `%s' execution task already set, this should not happen\n", sensorinfo->name);
683     return GNUNET_NO;
684   }
685   sensorinfo->execution_task = GNUNET_SCHEDULER_add_delayed(sensorinfo->interval, &run_sensor, sensorinfo);
686   return GNUNET_YES;
687 }
688
689 /**
690  * Starts the execution of all enabled sensors
691  *
692  */
693 static void
694 schedule_all_sensors()
695 {
696   GNUNET_CONTAINER_multihashmap_iterate(sensors, &schedule_sensor, NULL);
697 }
698
699 /**
700  * Process statistics requests.
701  *
702  * @param cls closure
703  * @param server the initialized server
704  * @param c configuration to use
705  */
706 static void
707 run (void *cls,
708      struct GNUNET_SERVER_Handle *server,
709      const struct GNUNET_CONFIGURATION_Handle *c)
710 {
711   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
712     {&handle_get_sensor, NULL, GNUNET_MESSAGE_TYPE_SENSOR_GET,
713      0},
714     {&handle_get_all_sensors, NULL, GNUNET_MESSAGE_TYPE_SENSOR_GETALL,
715      sizeof (struct GNUNET_MessageHeader)},
716     {NULL, NULL, 0, 0}
717   };
718
719   cfg = c;
720   sensors = GNUNET_CONTAINER_multihashmap_create(10, GNUNET_NO);
721   reload_sensors();
722   schedule_all_sensors();
723   GNUNET_SERVER_add_handlers (server, handlers);
724   GNUNET_SERVER_disconnect_notify (server, 
725                                    &handle_client_disconnect,
726                                    NULL);
727   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
728                                 &shutdown_task,
729                                 NULL);
730 }
731
732
733 /**
734  * The main function for the sensor service.
735  *
736  * @param argc number of arguments from the command line
737  * @param argv command line arguments
738  * @return 0 ok, 1 on error
739  */
740 int
741 main (int argc, char *const *argv)
742 {
743   return (GNUNET_OK ==
744           GNUNET_SERVICE_run (argc,
745                               argv,
746                               "sensor",
747                               GNUNET_SERVICE_OPTION_NONE,
748                               &run, NULL)) ? 0 : 1;
749 }
750
751 /* end of gnunet-service-sensor.c */