sensor: merged reporting module
[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 #include "gnunet_statistics_service.h"
31 #include "gnunet_peerstore_service.h"
32
33 /**
34  * Our configuration.
35  */
36 static const struct GNUNET_CONFIGURATION_Handle *cfg;
37
38 /**
39  * Path to sensor definitions directory
40  */
41 static char *sensor_dir;
42
43 /**
44  * Hashmap of loaded sensor definitions
45  */
46 static struct GNUNET_CONTAINER_MultiHashMap *sensors;
47
48 /**
49  * Handle to statistics service
50  */
51 static struct GNUNET_STATISTICS_Handle *statistics;
52
53 /**
54  * Handle to peerstore service
55  */
56 static struct GNUNET_PEERSTORE_Handle *peerstore;
57
58 /**
59  * Service name
60  */
61 static char *subsystem = "sensor";
62
63 /**
64  * My peer id
65  */
66 static struct GNUNET_PeerIdentity peerid;
67
68
69 /**
70  * Resets the service by stopping components, reloading sensors and starting
71  * components. This is needed when we receive new sensor updates.
72  */
73 static void
74 reset ();
75
76
77 /**
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  */
84 static void
85 set_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
99  */
100 static void
101 stop ()
102 {
103   SENSOR_update_stop ();
104   SENSOR_analysis_stop ();
105   SENSOR_reporting_stop ();
106   GNUNET_SENSOR_destroy_sensors (sensors);
107 }
108
109
110 /**
111  * Task run during shutdown.
112  *
113  * @param cls unused
114  * @param tc unused
115  */
116 static void
117 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
118 {
119   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)
131   {
132     GNUNET_free (sensor_dir);
133     sensor_dir = NULL;
134   }
135   GNUNET_SCHEDULER_shutdown ();
136 }
137
138
139 /**
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  */
145 static void
146 handle_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.
153  *
154  * @param sensor sensor information
155  * @return message ready to be sent to client
156  */
157 static struct SensorInfoMessage *
158 create_sensor_info_msg (struct GNUNET_SENSOR_SensorInfo *sensor)
159 {
160   struct SensorInfoMessage *msg;
161   uint16_t len;
162   size_t name_len;
163   size_t desc_len;
164   char *str_ptr;
165
166   name_len = strlen (sensor->name);
167   if (NULL == sensor->description)
168     desc_len = 0;
169   else
170     desc_len = strlen (sensor->description) + 1;
171   len = 0;
172   len += sizeof (struct SensorInfoMessage);
173   len += name_len;
174   len += desc_len;
175   msg = GNUNET_malloc (len);
176   msg->header.size = htons (len);
177   msg->header.type = htons (GNUNET_MESSAGE_TYPE_SENSOR_INFO);
178   msg->name_len = htons (name_len);
179   msg->description_len = htons (desc_len);
180   msg->version_major = htons (sensor->version_major);
181   msg->version_minor = htons (sensor->version_minor);
182   str_ptr = (char *) &msg[1];
183   memcpy (str_ptr, sensor->name, name_len);
184   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending sensor name (%d): %.*s\n",
185               name_len, name_len, str_ptr);
186   str_ptr += name_len;
187   memcpy (str_ptr, sensor->description, desc_len);
188   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
189               "Sending sensor description (%d): %.*s\n", desc_len, desc_len,
190               str_ptr);
191   return msg;
192 }
193
194
195 /**
196  * Handle GET SENSOR message.
197  *
198  * @param cls closure
199  * @param client identification of the client
200  * @param message the actual message
201  */
202 static void
203 handle_get_sensor (void *cls, struct GNUNET_SERVER_Client *client,
204                    const struct GNUNET_MessageHeader *message)
205 {
206   struct GNUNET_SERVER_TransmitContext *tc;
207   char *sensorname;
208   size_t sensorname_len;
209   struct GNUNET_HashCode key;
210   struct GNUNET_SENSOR_SensorInfo *sensorinfo;
211   struct SensorInfoMessage *msg;
212
213   sensorname = (char *) &message[1];
214   sensorname_len = ntohs (message->size) - sizeof (struct GNUNET_MessageHeader);
215   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
216               "`%s' message received for sensor (%d) `%.*s'\n", "GET SENSOR",
217               sensorname_len, sensorname_len, sensorname);
218   tc = GNUNET_SERVER_transmit_context_create (client);
219   GNUNET_CRYPTO_hash (sensorname, sensorname_len, &key);
220   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
221               "Created key hash for requested sensor\n");
222   sensorinfo =
223       (struct GNUNET_SENSOR_SensorInfo *)
224       GNUNET_CONTAINER_multihashmap_get (sensors, &key);
225   if (NULL != sensorinfo)
226   {
227     msg = create_sensor_info_msg (sensorinfo);
228     GNUNET_SERVER_transmit_context_append_message (tc,
229                                                    (struct GNUNET_MessageHeader
230                                                     *) msg);
231     GNUNET_free (msg);
232   }
233   else
234     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
235                 "Requested sensor `%.*s' was not found\n", sensorname_len,
236                 sensorname);
237   GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
238                                               GNUNET_MESSAGE_TYPE_SENSOR_END);
239   GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
240 }
241
242
243 /**
244  * Iterator for sensors and adds them to transmit context
245  *
246  * @param cls a `struct GNUNET_SERVER_TransmitContext *`
247  * @param key hash of sensor name, key to hashmap
248  * @param value a `struct GNUNET_SENSOR_SensorInfo *`
249  */
250 static int
251 add_sensor_to_tc (void *cls, const struct GNUNET_HashCode *key, void *value)
252 {
253   struct GNUNET_SERVER_TransmitContext *tc = cls;
254   struct GNUNET_SENSOR_SensorInfo *sensorinfo = value;
255   struct SensorInfoMessage *msg;
256
257   msg = create_sensor_info_msg (sensorinfo);
258   GNUNET_SERVER_transmit_context_append_message (tc,
259                                                  (struct GNUNET_MessageHeader *)
260                                                  msg);
261
262   GNUNET_free (msg);
263   return GNUNET_YES;
264 }
265
266
267 /**
268  * Handle GET ALL SENSORS message.
269  *
270  * @param cls closure
271  * @param client identification of the client
272  * @param message the actual message
273  */
274 static void
275 handle_get_all_sensors (void *cls, struct GNUNET_SERVER_Client *client,
276                         const struct GNUNET_MessageHeader *message)
277 {
278   struct GNUNET_SERVER_TransmitContext *tc;
279
280   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "`%s' message received.\n",
281               "GET ALL SENSOR");
282   tc = GNUNET_SERVER_transmit_context_create (client);
283   GNUNET_CONTAINER_multihashmap_iterate (sensors, &add_sensor_to_tc, tc);
284   GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
285                                               GNUNET_MESSAGE_TYPE_SENSOR_END);
286   GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
287 }
288
289
290 /**
291  * Do a series of checks to determine if sensor should execute
292  *
293  * @return #GNUNET_YES / #GNUNET_NO
294  */
295 static int
296 should_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  */
337 static int
338 sensor_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  */
363 static void
364 end_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  */
382 static size_t
383 parse_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  */
420 static void
421 sensor_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  */
464 static int
465 is_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  */
486 static void
487 sensor_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  */
580 static int
581 schedule_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  */
608 static void
609 schedule_all_sensors ()
610 {
611   GNUNET_CONTAINER_multihashmap_iterate (sensors, &schedule_sensor, NULL);
612 }
613
614
615 /**
616  * Loads sensors and starts different service components
617  */
618 static void
619 start ()
620 {
621   sensors = GNUNET_SENSOR_load_all_sensors (sensor_dir);
622   schedule_all_sensors ();
623   SENSOR_reporting_start (cfg, sensors);
624   SENSOR_analysis_start (cfg, sensors);
625   SENSOR_update_start (cfg, sensors, &reset);
626 }
627
628
629 /**
630  * Process statistics requests.
631  *
632  * @param cls closure
633  * @param server the initialized server
634  * @param c configuration to use
635  */
636 static void
637 run (void *cls, struct GNUNET_SERVER_Handle *server,
638      const struct GNUNET_CONFIGURATION_Handle *c)
639 {
640   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
641     {&handle_get_sensor, NULL, GNUNET_MESSAGE_TYPE_SENSOR_GET,
642      0},
643     {&handle_get_all_sensors, NULL, GNUNET_MESSAGE_TYPE_SENSOR_GETALL,
644      sizeof (struct GNUNET_MessageHeader)},
645     {NULL, NULL, 0, 0}
646   };
647
648   cfg = c;
649   if (GNUNET_OK !=
650       GNUNET_CONFIGURATION_get_value_filename (cfg, "SENSOR", "SENSOR_DIR",
651                                                &sensor_dir))
652     sensor_dir = GNUNET_SENSOR_get_default_sensor_dir ();
653   statistics = GNUNET_STATISTICS_create ("sensor", cfg);
654   GNUNET_CRYPTO_get_peer_identity (cfg, &peerid);
655   peerstore = GNUNET_PEERSTORE_connect (cfg);
656   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,
659                                 NULL);
660   start ();
661 }
662
663
664 /**
665  * Resets the service by stopping components, reloading sensors and starting
666  * components. This is needed when we receive new sensor updates.
667  */
668 static void
669 reset ()
670 {
671   stop ();
672   start ();
673 }
674
675
676 /**
677  * The main function for the sensor service.
678  *
679  * @param argc number of arguments from the command line
680  * @param argv command line arguments
681  * @return 0 ok, 1 on error
682  */
683 int
684 main (int argc, char *const *argv)
685 {
686   return (GNUNET_OK ==
687           GNUNET_SERVICE_run (argc, argv, "sensor", GNUNET_SERVICE_OPTION_NONE,
688                               &run, NULL)) ? 0 : 1;
689 }
690
691 /* end of gnunet-service-sensor.c */