sensor: towards anomaly reporting
[oweals/gnunet.git] / src / sensor / gnunet-service-sensor_update.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_update.c
23  * @brief sensor service update functionality
24  * @author Omar Tarabai
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "sensor.h"
29 #include "gnunet_cadet_service.h"
30 #include "gnunet_sensor_model_plugin.h"
31 #include "gnunet_applications.h"
32
33 #define LOG(kind,...) GNUNET_log_from (kind, "sensor-update",__VA_ARGS__)
34
35 /**
36  * Interval at which to contact update points for new sensor updates.
37  */
38 #define SENSOR_UPDATE_CHECK_INTERVAL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_DAYS, 1)
39
40 /**
41  * Interval at which to retry contacting update point if we were busy.
42  */
43 #define SENSOR_UPDATE_CHECK_RETRY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
44
45
46 /**
47  * Message queued to be sent to an update point stored in a DLL
48  */
49 struct PendingMessage
50 {
51
52   /**
53    * DLL
54    */
55   struct PendingMessage *prev;
56
57   /**
58    * DLL
59    */
60   struct PendingMessage *next;
61
62   /**
63    * Actual queued message
64    */
65   struct GNUNET_MessageHeader *msg;
66
67 };
68
69 /**
70  * Sensors update point
71  */
72 struct UpdatePoint
73 {
74
75   /**
76    * DLL
77    */
78   struct UpdatePoint *prev;
79
80   /**
81    * DLL
82    */
83   struct UpdatePoint *next;
84
85   /**
86    * Identity of peer running update point
87    */
88   struct GNUNET_PeerIdentity peer_id;
89
90   /**
91    * CADET channel to update point
92    */
93   struct GNUNET_CADET_Channel *ch;
94
95   /**
96    * CADET transmit handle for a message to be sent to update point.
97    */
98   struct GNUNET_CADET_TransmitHandle *th;
99
100   /**
101    * Head of DLL of pending requests to be sent to update point.
102    */
103   struct PendingMessage *pm_head;
104
105   /**
106    * Tail of DLL of pending requests to be sent to update point.
107    */
108   struct PendingMessage *pm_tail;
109
110   /**
111    * Are we waiting for a sensor list?
112    */
113   int expecting_sensor_list;
114
115   /**
116    * How many sensor updates did we request and are waiting for.
117    */
118   int expected_sensor_updates;
119
120   /**
121    * Did a failure occur while dealing with this update point before?
122    */
123   int failed;
124
125 };
126
127
128 /**
129  * Our configuration.
130  */
131 static const struct GNUNET_CONFIGURATION_Handle *cfg;
132
133 /**
134  * Hashmap of known sensors
135  */
136 static struct GNUNET_CONTAINER_MultiHashMap *sensors;
137
138 /**
139  * Head of update points DLL.
140  */
141 static struct UpdatePoint *up_head;
142
143 /**
144  * Tail of update points DLL.
145  */
146 static struct UpdatePoint *up_tail;
147
148 /**
149  * The current default update point to use.
150  */
151 static struct UpdatePoint *up_default;
152
153 /**
154  * Handle to CADET service
155  */
156 static struct GNUNET_CADET_Handle *cadet;
157
158 /**
159  * Are we in the process of checking and updating sensors?
160  */
161 static int updating;
162
163 /**
164  * GNUnet scheduler task that starts the update check process.
165  */
166 GNUNET_SCHEDULER_TaskIdentifier update_task;
167
168 /**
169  * Pointer to service reset function called when we have new sensor updates.
170  */
171 void (*reset_cb) ();
172
173
174 /**
175  * Contact update points to check for new updates
176  *
177  * @param cls unused
178  * @param tc GNUnet scheduler task context
179  */
180 static void
181 check_for_updates (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
182
183
184 /**
185  * Trigger sending next pending message to the default update point if any.
186  *
187  */
188 static void
189 trigger_send_next_msg ();
190
191
192 /**
193  * Cleanup update point context. This does not destroy the struct itself.
194  *
195  * @param up UpdatePoint struct
196  */
197 static void
198 cleanup_updatepoint (struct UpdatePoint *up)
199 {
200   struct PendingMessage *pm;
201
202   up->expecting_sensor_list = GNUNET_NO;
203   up->expected_sensor_updates = 0;
204   if (NULL != up->th)
205   {
206     GNUNET_CADET_notify_transmit_ready_cancel (up->th);
207     up->th = NULL;
208   }
209   pm = up->pm_head;
210   while (NULL != pm)
211   {
212     GNUNET_CONTAINER_DLL_remove (up->pm_head, up->pm_tail, pm);
213     GNUNET_free (pm->msg);
214     GNUNET_free (pm);
215     pm = up->pm_head;
216   }
217   if (NULL != up->ch)
218   {
219     GNUNET_CADET_channel_destroy (up->ch);
220     up->ch = NULL;
221   }
222 }
223
224
225 /**
226  * Stop the sensor update module.
227  */
228 void
229 SENSOR_update_stop ()
230 {
231   struct UpdatePoint *up;
232
233   up_default = NULL;
234   up = up_head;
235   if (GNUNET_SCHEDULER_NO_TASK != update_task)
236   {
237     GNUNET_SCHEDULER_cancel (update_task);
238     update_task = GNUNET_SCHEDULER_NO_TASK;
239   }
240   while (NULL != up)
241   {
242     GNUNET_CONTAINER_DLL_remove (up_head, up_tail, up);
243     cleanup_updatepoint (up);
244     GNUNET_free (up);
245     up = up_head;
246   }
247   if (NULL != cadet)
248   {
249     GNUNET_CADET_disconnect (cadet);
250     cadet = NULL;
251   }
252   LOG (GNUNET_ERROR_TYPE_DEBUG, "Sensor update module stopped.\n");
253 }
254
255
256 /**
257  * A failure occured in connecting/retrieval/verification with current default
258  * update point. This method will try to find another update point, do cleanup
259  * and reschedule update check.
260  */
261 static void
262 fail ()
263 {
264   struct UpdatePoint *up;
265
266   cleanup_updatepoint (up_default);
267   if (up_default == up_tail)
268   {
269     LOG (GNUNET_ERROR_TYPE_WARNING,
270          "All defined update points failed. Will retry again in %s.\n",
271          GNUNET_STRINGS_relative_time_to_string (SENSOR_UPDATE_CHECK_INTERVAL,
272                                                  GNUNET_NO));
273     up = up_head;
274     while (NULL != up)
275     {
276       up->failed = GNUNET_NO;
277       up = up->next;
278     }
279     update_task =
280         GNUNET_SCHEDULER_add_delayed (SENSOR_UPDATE_CHECK_INTERVAL,
281                                       &check_for_updates, NULL);
282     return;
283   }
284   LOG (GNUNET_ERROR_TYPE_WARNING,
285        "Update point `%s' failed, trying next one now.\n",
286        GNUNET_i2s (&up_default->peer_id));
287   up_default = up_default->next;
288   update_task = GNUNET_SCHEDULER_add_now (&check_for_updates, NULL);
289 }
290
291
292 /**
293  * Function called to notify a client about the connection begin ready
294  * to queue more data.  @a buf will be NULL and @a size zero if the
295  * connection was closed for writing in the meantime.
296  *
297  * Perform the actual sending of the message to update point.
298  *
299  * @param cls closure (unused)
300  * @param size number of bytes available in @a buf
301  * @param buf where the callee should write the message
302  * @return number of bytes written to @a buf
303  */
304 static size_t
305 do_send_msg (void *cls, size_t size, void *buf)
306 {
307   struct PendingMessage *pm;
308   size_t msg_size;
309
310   up_default->th = NULL;
311   pm = up_default->pm_head;
312   msg_size = ntohs (pm->msg->size);
313   GNUNET_CONTAINER_DLL_remove (up_default->pm_head, up_default->pm_tail, pm);
314   if (NULL == buf || size < msg_size)
315   {
316     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
317                 _("Error trying to send a message to update point `%s'.\n"),
318                 GNUNET_i2s (&up_default->peer_id));
319     fail ();
320     return 0;
321   }
322   memcpy (buf, pm->msg, msg_size);
323   GNUNET_free (pm->msg);
324   GNUNET_free (pm);
325   trigger_send_next_msg ();
326   return msg_size;
327 }
328
329
330 /**
331  * Trigger sending next pending message to the default update point if any.
332  *
333  */
334 static void
335 trigger_send_next_msg ()
336 {
337   struct PendingMessage *pm;
338
339   if (NULL == up_default->pm_head)
340     return;
341   if (NULL != up_default->th)
342     return;
343   pm = up_default->pm_head;
344   up_default->th =
345       GNUNET_CADET_notify_transmit_ready (up_default->ch, GNUNET_YES,
346                                           GNUNET_TIME_UNIT_FOREVER_REL,
347                                           ntohs (pm->msg->size), &do_send_msg,
348                                           NULL);
349 }
350
351
352 /**
353  * Add a message to the queue to be sent to the current default update point.
354  *
355  * @param msg Message to be queued
356  */
357 static void
358 queue_msg (struct GNUNET_MessageHeader *msg)
359 {
360   struct PendingMessage *pm;
361
362   pm = GNUNET_new (struct PendingMessage);
363
364   pm->msg = msg;
365   GNUNET_CONTAINER_DLL_insert_tail (up_default->pm_head, up_default->pm_tail,
366                                     pm);
367   trigger_send_next_msg ();
368 }
369
370
371 /**
372  * Contact update points to check for new updates
373  *
374  * @param cls unused
375  * @param tc GNUnet scheduler task context
376  */
377 static void
378 check_for_updates (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
379 {
380   struct GNUNET_MessageHeader *msg;
381   size_t msg_size;
382
383   update_task = GNUNET_SCHEDULER_NO_TASK;
384   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
385     return;
386   if (GNUNET_YES == updating)
387   {
388     LOG (GNUNET_ERROR_TYPE_WARNING,
389          "Update process still running and update interval already exhausted."
390          "Retrying in %s.\n",
391          GNUNET_STRINGS_relative_time_to_string (SENSOR_UPDATE_CHECK_RETRY,
392                                                  GNUNET_NO));
393     update_task =
394         GNUNET_SCHEDULER_add_delayed (SENSOR_UPDATE_CHECK_RETRY,
395                                       &check_for_updates, NULL);
396     return;
397   }
398   updating = GNUNET_YES;
399   LOG (GNUNET_ERROR_TYPE_DEBUG, "Checking for sensor updates.\n");
400   GNUNET_assert (NULL != up_default);
401   up_default->ch =
402       GNUNET_CADET_channel_create (cadet, up_default, &up_default->peer_id,
403                                    GNUNET_APPLICATION_TYPE_SENSORUPDATE,
404                                    GNUNET_CADET_OPTION_DEFAULT);
405   if (NULL == up_default->ch)
406   {
407     LOG (GNUNET_ERROR_TYPE_ERROR,
408          _("Failed to connect to update point `%s'.\n"),
409          GNUNET_i2s (&up_default->peer_id));
410     fail ();
411     return;
412   }
413   /* Start by requesting list of sensors available from update point */
414   up_default->expecting_sensor_list = GNUNET_YES;
415   msg = GNUNET_new (struct GNUNET_MessageHeader);
416   msg_size = sizeof (struct GNUNET_MessageHeader);
417   msg->size = htons (msg_size);
418   msg->type = htons (GNUNET_MESSAGE_TYPE_SENSOR_LIST_REQ);
419   queue_msg (msg);
420   update_task =
421       GNUNET_SCHEDULER_add_delayed (SENSOR_UPDATE_CHECK_INTERVAL,
422                                     &check_for_updates, NULL);
423 }
424
425
426 /**
427  * Function that reads and validates (correctness not connectivity) of available
428  * sensor update points.
429  *
430  * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
431  */
432 static int
433 load_update_points ()
434 {
435   char *points_list;
436   int points_list_len;
437   int i;
438   int start;
439   int len;
440   struct GNUNET_CRYPTO_EddsaPublicKey public_key;
441   struct UpdatePoint *up;
442
443   if (GNUNET_OK !=
444       GNUNET_CONFIGURATION_get_value_string (cfg, "sensor", "UPDATE_POINTS",
445                                              &points_list))
446   {
447     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "sensor",
448                                "UPDATE_POINTS");
449     return GNUNET_SYSERR;
450   }
451   points_list_len = strlen (points_list) + 1;
452   for (i = 0; i < points_list_len; i++)
453   {
454     if (' ' == points_list[i])
455       continue;
456     start = i;
457     len = 0;
458     while (' ' != points_list[i] && '\0' != points_list[i])
459     {
460       len++;
461       i++;
462     }
463     if (GNUNET_OK !=
464         GNUNET_CRYPTO_eddsa_public_key_from_string (points_list + start, len,
465                                                     &public_key))
466     {
467       LOG (GNUNET_ERROR_TYPE_ERROR,
468            "Invalid EDDSA public key `%.*s' for update point.\n", len,
469            points_list + len);
470       continue;
471     }
472     up = GNUNET_new (struct UpdatePoint);
473
474     up->peer_id.public_key = public_key;
475     up->ch = NULL;
476     up->th = NULL;
477     up->expecting_sensor_list = GNUNET_NO;
478     up->expected_sensor_updates = 0;
479     up->failed = GNUNET_NO;
480     GNUNET_CONTAINER_DLL_insert (up_head, up_tail, up);
481     LOG (GNUNET_ERROR_TYPE_DEBUG, "Loaded update point `%s'.\n",
482          GNUNET_i2s_full (&up->peer_id));
483   }
484   GNUNET_free (points_list);
485   return (NULL == up_head) ? GNUNET_SYSERR : GNUNET_OK;
486 }
487
488
489 /**
490  * Checks if the given sensor name and version (retrieved from an update point)
491  * is new for us and we would like to install it. This is the case if we don't
492  * have this sensor or we have an old version of it.
493  *
494  * @param sensorname Sensor name
495  * @param sensorversion_major First part of version number
496  * @param sensorversion_minor Second part of version number
497  * @return #GNUNET_YES if we don't have this sensor
498  *         #GNUNET_NO if we have it
499  */
500 static int
501 update_required (char *sensorname, uint16_t sensorversion_major,
502                  uint16_t sensorversion_minor)
503 {
504   struct GNUNET_HashCode key;
505   struct GNUNET_SENSOR_SensorInfo *local_sensor;
506
507   GNUNET_CRYPTO_hash (sensorname, strlen (sensorname) + 1, &key);
508   local_sensor = GNUNET_CONTAINER_multihashmap_get (sensors, &key);
509   if (NULL == local_sensor)
510     return GNUNET_YES;
511   if (GNUNET_SENSOR_version_compare
512       (local_sensor->version_major, local_sensor->version_minor,
513        sensorversion_major, sensorversion_minor) < 0)
514     return GNUNET_YES;
515   return GNUNET_NO;
516 }
517
518
519 /**
520  * Handler of a sensor list message received from an update point.
521  *
522  * @param cls Closure (unused).
523  * @param channel Connection to the other end.
524  * @param channel_ctx Place to store local state associated with the channel.
525  * @param message The actual message.
526  * @return #GNUNET_OK to keep the channel open,
527  *         #GNUNET_SYSERR to close it (signal serious error).
528  */
529 static int
530 handle_sensor_brief (void *cls, struct GNUNET_CADET_Channel *channel,
531                      void **channel_ctx,
532                      const struct GNUNET_MessageHeader *message)
533 {
534   struct GNUNET_SENSOR_SensorBriefMessage *sbm;
535   struct GNUNET_MessageHeader *pull_req;
536   uint16_t version_major;
537   uint16_t version_minor;
538   uint16_t msg_size;
539
540   GNUNET_assert (*channel_ctx == up_default);
541   if (GNUNET_YES != up_default->expecting_sensor_list)
542   {
543     GNUNET_break_op (0);
544     fail ();
545     return GNUNET_OK;
546   }
547   if (GNUNET_MESSAGE_TYPE_SENSOR_END == ntohs (message->type))
548   {
549     LOG (GNUNET_ERROR_TYPE_DEBUG,
550          "Received end of sensor list msg. We already requested %d updates.\n",
551          up_default->expected_sensor_updates);
552     up_default->expecting_sensor_list = GNUNET_NO;
553     if (0 == up_default->expected_sensor_updates)
554     {
555       updating = GNUNET_NO;
556       cleanup_updatepoint (up_default);
557       return GNUNET_OK;
558     }
559   }
560   else
561   {
562     sbm = (struct GNUNET_SENSOR_SensorBriefMessage *) message;
563     version_major = ntohs (sbm->version_major);
564     version_minor = ntohs (sbm->version_minor);
565     if (GNUNET_YES ==
566         update_required ((char *) &sbm[1], version_major, version_minor))
567     {
568       LOG (GNUNET_ERROR_TYPE_INFO,
569            "Requesting sensor %s %d.%d from update point.\n", &sbm[1],
570            version_major, version_minor);
571       /* We duplicate the same msg received but change the type and send it
572        * back to update point to ask for full sensor information. */
573       msg_size = ntohs (message->size);
574       pull_req = GNUNET_malloc (msg_size);
575       memcpy (pull_req, message, msg_size);
576       pull_req->type = htons (GNUNET_MESSAGE_TYPE_SENSOR_FULL_REQ);
577       queue_msg (pull_req);
578       up_default->expected_sensor_updates++;
579     }
580   }
581   GNUNET_CADET_receive_done (channel);
582   return GNUNET_OK;
583 }
584
585
586 /**
587  * Update local sensor definitions with a sensor retrieved from an update point.
588  *
589  * @param sensorname Sensor name
590  * @param sensorfile Buffer containing the sensor definition file
591  * @param sensorfile_size Size of @e sensorfile
592  * @param scriptname Name of associated script file, NULL if no script
593  * @param scriptfile Buffer containing the script file, NULL if no script
594  * @param scriptfile_size Size of @e scriptfile, 0 if no script
595  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
596  */
597 static int
598 update_sensor (char *sensorname, void *sensorfile, uint16_t sensorfile_size,
599                char *scriptname, void *scriptfile, uint16_t scriptfile_size)
600 {
601   char *sensors_dir;
602   char *sensor_path;
603   char *script_path;
604
605   LOG (GNUNET_ERROR_TYPE_INFO,
606        "Received new sensor information:\n" "Name: %s\n"
607        "Sensor file size: %d\n" "Script name: %s\n" "Script file size: %d.\n",
608        sensorname, sensorfile_size, (NULL == scriptname) ? "None" : scriptname,
609        scriptfile_size);
610   sensors_dir = GNUNET_SENSOR_get_sensor_dir ();
611   GNUNET_asprintf (&sensor_path, "%s%s", sensors_dir, sensorname);
612   GNUNET_DISK_fn_write (sensor_path, sensorfile, sensorfile_size,
613                         GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_GROUP_READ
614                         | GNUNET_DISK_PERM_OTHER_READ |
615                         GNUNET_DISK_PERM_USER_WRITE);
616   if (NULL != scriptname)
617   {
618     GNUNET_asprintf (&script_path, "%s-files%s%s", sensor_path,
619                      DIR_SEPARATOR_STR, scriptname);
620     GNUNET_DISK_fn_write (script_path, scriptfile, scriptfile_size,
621                           GNUNET_DISK_PERM_USER_READ |
622                           GNUNET_DISK_PERM_GROUP_READ |
623                           GNUNET_DISK_PERM_OTHER_READ |
624                           GNUNET_DISK_PERM_USER_WRITE |
625                           GNUNET_DISK_PERM_GROUP_WRITE |
626                           GNUNET_DISK_PERM_USER_EXEC |
627                           GNUNET_DISK_PERM_GROUP_EXEC);
628     GNUNET_free (script_path);
629   }
630   GNUNET_free (sensors_dir);
631   GNUNET_free (sensor_path);
632   return GNUNET_OK;
633 }
634
635
636 /**
637  * Resets the service after we are done with an update.
638  *
639  * @param cls unused
640  * @param tc unused
641  */
642 void
643 reset (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
644 {
645   reset_cb ();
646 }
647
648
649 /**
650  * Handler of a sensor list message received from an update point.
651  *
652  * @param cls Closure (unused).
653  * @param channel Connection to the other end.
654  * @param channel_ctx Place to store local state associated with the channel.
655  * @param message The actual message.
656  * @return #GNUNET_OK to keep the channel open,
657  *         #GNUNET_SYSERR to close it (signal serious error).
658  */
659 static int
660 handle_sensor_full (void *cls, struct GNUNET_CADET_Channel *channel,
661                     void **channel_ctx,
662                     const struct GNUNET_MessageHeader *message)
663 {
664   struct GNUNET_SENSOR_SensorFullMessage *sfm;
665   uint16_t msg_size;
666   uint16_t sensorfile_size;
667   uint16_t scriptfile_size;
668   char *sensorname_ptr;
669   void *sensorfile_ptr;
670   char *scriptname_ptr;
671   void *scriptfile_ptr;
672
673   /* error check */
674   GNUNET_assert (*channel_ctx == up_default);
675   msg_size = ntohs (message->size);
676   if (up_default->expected_sensor_updates <= 0 ||
677       msg_size < sizeof (struct GNUNET_SENSOR_SensorFullMessage))
678   {
679     GNUNET_break_op (0);
680     fail ();
681     return GNUNET_OK;
682   }
683   /* parse received msg */
684   sfm = (struct GNUNET_SENSOR_SensorFullMessage *) message;
685   sensorname_ptr = (char *) &sfm[1];
686   sensorfile_ptr = sensorname_ptr + ntohs (sfm->sensorname_size);
687   sensorfile_size = ntohs (sfm->sensorfile_size);
688   scriptfile_size = ntohs (sfm->scriptfile_size);
689   if (scriptfile_size > 0)
690   {
691     scriptname_ptr = sensorfile_ptr + sensorfile_size;
692     scriptfile_ptr = scriptname_ptr + ntohs (sfm->scriptname_size);
693   }
694   else
695   {
696     scriptname_ptr = NULL;
697     scriptfile_ptr = NULL;
698   }
699   update_sensor ((char *) &sfm[1], sensorfile_ptr, sensorfile_size,
700                  scriptname_ptr, scriptfile_ptr, scriptfile_size);
701   up_default->expected_sensor_updates--;
702   if (0 == up_default->expected_sensor_updates)
703   {
704     updating = GNUNET_NO;
705     cleanup_updatepoint (up_default);
706     GNUNET_SCHEDULER_add_continuation (&reset, NULL, 0);
707   }
708   else
709     GNUNET_CADET_receive_done (channel);
710   return GNUNET_OK;
711 }
712
713
714 /**
715  * Function called whenever a channel is destroyed.  Should clean up
716  * any associated state.
717  *
718  * It must NOT call #GNUNET_CADET_channel_destroy on the channel.
719  *
720  * @param cls closure (set from #GNUNET_CADET_connect)
721  * @param channel connection to the other end (henceforth invalid)
722  * @param channel_ctx place where local state associated
723  *                   with the channel is stored
724  */
725 static void
726 cadet_channel_destroyed (void *cls, const struct GNUNET_CADET_Channel *channel,
727                          void *channel_ctx)
728 {
729   struct UpdatePoint *up = channel_ctx;
730
731   up->ch = NULL;
732   if (GNUNET_YES == updating)
733   {
734     fail ();
735     return;
736   }
737   cleanup_updatepoint (up);
738 }
739
740
741 /**
742  * Start the sensor update module
743  *
744  * @param c our service configuration
745  * @param s multihashmap of loaded sensors
746  * @param cb callback to reset service components when we have new updates
747  * @return #GNUNET_OK if started successfully, #GNUNET_SYSERR otherwise
748  */
749 int
750 SENSOR_update_start (const struct GNUNET_CONFIGURATION_Handle *c,
751                      struct GNUNET_CONTAINER_MultiHashMap *s, void (*cb) ())
752 {
753   static struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
754     {&handle_sensor_brief, GNUNET_MESSAGE_TYPE_SENSOR_BRIEF, 0},
755     {&handle_sensor_brief, GNUNET_MESSAGE_TYPE_SENSOR_END, 0},
756     {&handle_sensor_full, GNUNET_MESSAGE_TYPE_SENSOR_FULL, 0},
757     {NULL, 0, 0}
758   };
759
760   GNUNET_assert (NULL != s);
761   cfg = c;
762   sensors = s;
763   reset_cb = cb;
764   cadet =
765       GNUNET_CADET_connect (cfg, NULL, NULL, &cadet_channel_destroyed,
766                             cadet_handlers, NULL);
767   if (NULL == cadet)
768   {
769     LOG (GNUNET_ERROR_TYPE_ERROR, _("Failed to connect to CADET service.\n"));
770     SENSOR_update_stop ();
771     return GNUNET_SYSERR;
772   }
773   if (GNUNET_OK != load_update_points ())
774   {
775     LOG (GNUNET_ERROR_TYPE_ERROR, "Failed to load update points.\n");
776     SENSOR_update_stop ();
777     return GNUNET_SYSERR;
778   }
779   up_default = up_head;
780   updating = GNUNET_NO;
781   update_task =
782       GNUNET_SCHEDULER_add_delayed (SENSOR_UPDATE_CHECK_INTERVAL,
783                                     &check_for_updates, NULL);
784   LOG (GNUNET_ERROR_TYPE_DEBUG, "Sensor update module started.\n");
785   return GNUNET_OK;
786 }
787
788 /* end of gnunet-service-sensor_update.c */