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_update.c
23 * @brief sensor service update functionality
24 * @author Omar Tarabai
27 #include "gnunet_util_lib.h"
29 #include "gnunet_cadet_service.h"
30 #include "gnunet_sensor_model_plugin.h"
31 #include "gnunet_applications.h"
33 #define LOG(kind,...) GNUNET_log_from (kind, "sensor-update",__VA_ARGS__)
36 * Interval at which to contact update points for new sensor updates.
38 #define SENSOR_UPDATE_CHECK_INTERVAL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_DAYS, 1)
41 * Interval at which to retry contacting update point if we were busy.
43 #define SENSOR_UPDATE_CHECK_RETRY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
47 * Message queued to be sent to an update point stored in a DLL
55 struct PendingMessage *prev;
60 struct PendingMessage *next;
63 * Actual queued message
65 struct GNUNET_MessageHeader *msg;
70 * Sensors update point
78 struct UpdatePoint *prev;
83 struct UpdatePoint *next;
86 * Identity of peer running update point
88 struct GNUNET_PeerIdentity peer_id;
91 * CADET channel to update point
93 struct GNUNET_CADET_Channel *ch;
96 * CADET transmit handle for a message to be sent to update point.
98 struct GNUNET_CADET_TransmitHandle *th;
101 * Head of DLL of pending requests to be sent to update point.
103 struct PendingMessage *pm_head;
106 * Tail of DLL of pending requests to be sent to update point.
108 struct PendingMessage *pm_tail;
111 * Are we waiting for a sensor list?
113 int expecting_sensor_list;
116 * How many sensor updates did we request and are waiting for.
118 int expected_sensor_updates;
121 * Did a failure occur while dealing with this update point before?
131 static const struct GNUNET_CONFIGURATION_Handle *cfg;
134 * Hashmap of known sensors
136 static struct GNUNET_CONTAINER_MultiHashMap *sensors;
139 * Head of update points DLL.
141 static struct UpdatePoint *up_head;
144 * Tail of update points DLL.
146 static struct UpdatePoint *up_tail;
149 * The current default update point to use.
151 static struct UpdatePoint *up_default;
154 * Handle to CADET service
156 static struct GNUNET_CADET_Handle *cadet;
159 * Are we in the process of checking and updating sensors?
164 * GNUnet scheduler task that starts the update check process.
166 GNUNET_SCHEDULER_TaskIdentifier update_task;
169 * Pointer to service reset function called when we have new sensor updates.
175 * Contact update points to check for new updates
178 * @param tc GNUnet scheduler task context
181 check_for_updates (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
185 * Trigger sending next pending message to the default update point if any.
189 trigger_send_next_msg ();
193 * Cleanup update point context. This does not destroy the struct itself.
195 * @param up UpdatePoint struct
198 cleanup_updatepoint (struct UpdatePoint *up)
200 struct PendingMessage *pm;
202 up->expecting_sensor_list = GNUNET_NO;
203 up->expected_sensor_updates = 0;
206 GNUNET_CADET_notify_transmit_ready_cancel (up->th);
212 GNUNET_CONTAINER_DLL_remove (up->pm_head, up->pm_tail, pm);
213 GNUNET_free (pm->msg);
219 GNUNET_CADET_channel_destroy (up->ch);
226 * Stop the sensor update module.
229 SENSOR_update_stop ()
231 struct UpdatePoint *up;
235 if (GNUNET_SCHEDULER_NO_TASK != update_task)
237 GNUNET_SCHEDULER_cancel (update_task);
238 update_task = GNUNET_SCHEDULER_NO_TASK;
242 GNUNET_CONTAINER_DLL_remove (up_head, up_tail, up);
243 cleanup_updatepoint (up);
249 GNUNET_CADET_disconnect (cadet);
252 LOG (GNUNET_ERROR_TYPE_DEBUG, "Sensor update module stopped.\n");
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.
264 struct UpdatePoint *up;
266 cleanup_updatepoint (up_default);
267 if (up_default == up_tail)
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,
276 up->failed = GNUNET_NO;
280 GNUNET_SCHEDULER_add_delayed (SENSOR_UPDATE_CHECK_INTERVAL,
281 &check_for_updates, NULL);
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);
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.
297 * Perform the actual sending of the message to update point.
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
305 do_send_msg (void *cls, size_t size, void *buf)
307 struct PendingMessage *pm;
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)
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));
322 memcpy (buf, pm->msg, msg_size);
323 GNUNET_free (pm->msg);
325 trigger_send_next_msg ();
331 * Trigger sending next pending message to the default update point if any.
335 trigger_send_next_msg ()
337 struct PendingMessage *pm;
339 if (NULL == up_default->pm_head)
341 if (NULL != up_default->th)
343 pm = up_default->pm_head;
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,
353 * Add a message to the queue to be sent to the current default update point.
355 * @param msg Message to be queued
358 queue_msg (struct GNUNET_MessageHeader *msg)
360 struct PendingMessage *pm;
362 pm = GNUNET_new (struct PendingMessage);
365 GNUNET_CONTAINER_DLL_insert_tail (up_default->pm_head, up_default->pm_tail,
367 trigger_send_next_msg ();
372 * Contact update points to check for new updates
375 * @param tc GNUnet scheduler task context
378 check_for_updates (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
380 struct GNUNET_MessageHeader *msg;
383 update_task = GNUNET_SCHEDULER_NO_TASK;
384 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
386 if (GNUNET_YES == updating)
388 LOG (GNUNET_ERROR_TYPE_WARNING,
389 "Update process still running and update interval already exhausted."
391 GNUNET_STRINGS_relative_time_to_string (SENSOR_UPDATE_CHECK_RETRY,
394 GNUNET_SCHEDULER_add_delayed (SENSOR_UPDATE_CHECK_RETRY,
395 &check_for_updates, NULL);
398 updating = GNUNET_YES;
399 LOG (GNUNET_ERROR_TYPE_DEBUG, "Checking for sensor updates.\n");
400 GNUNET_assert (NULL != up_default);
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)
407 LOG (GNUNET_ERROR_TYPE_ERROR,
408 _("Failed to connect to update point `%s'.\n"),
409 GNUNET_i2s (&up_default->peer_id));
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);
421 GNUNET_SCHEDULER_add_delayed (SENSOR_UPDATE_CHECK_INTERVAL,
422 &check_for_updates, NULL);
427 * Function that reads and validates (correctness not connectivity) of available
428 * sensor update points.
430 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
433 load_update_points ()
440 struct GNUNET_CRYPTO_EddsaPublicKey public_key;
441 struct UpdatePoint *up;
444 GNUNET_CONFIGURATION_get_value_string (cfg, "sensor", "UPDATE_POINTS",
447 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "sensor",
449 return GNUNET_SYSERR;
451 points_list_len = strlen (points_list) + 1;
452 for (i = 0; i < points_list_len; i++)
454 if (' ' == points_list[i])
458 while (' ' != points_list[i] && '\0' != points_list[i])
464 GNUNET_CRYPTO_eddsa_public_key_from_string (points_list + start, len,
467 LOG (GNUNET_ERROR_TYPE_ERROR,
468 "Invalid EDDSA public key `%.*s' for update point.\n", len,
472 up = GNUNET_new (struct UpdatePoint);
474 up->peer_id.public_key = public_key;
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));
484 GNUNET_free (points_list);
485 return (NULL == up_head) ? GNUNET_SYSERR : GNUNET_OK;
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.
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
501 update_required (char *sensorname, uint16_t sensorversion_major,
502 uint16_t sensorversion_minor)
504 struct GNUNET_HashCode key;
505 struct GNUNET_SENSOR_SensorInfo *local_sensor;
507 GNUNET_CRYPTO_hash (sensorname, strlen (sensorname) + 1, &key);
508 local_sensor = GNUNET_CONTAINER_multihashmap_get (sensors, &key);
509 if (NULL == local_sensor)
511 if (GNUNET_SENSOR_version_compare
512 (local_sensor->version_major, local_sensor->version_minor,
513 sensorversion_major, sensorversion_minor) < 0)
520 * Handler of a sensor list message received from an update point.
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).
530 handle_sensor_brief (void *cls, struct GNUNET_CADET_Channel *channel,
532 const struct GNUNET_MessageHeader *message)
534 struct GNUNET_SENSOR_SensorBriefMessage *sbm;
535 struct GNUNET_MessageHeader *pull_req;
536 uint16_t version_major;
537 uint16_t version_minor;
540 GNUNET_assert (*channel_ctx == up_default);
541 if (GNUNET_YES != up_default->expecting_sensor_list)
547 if (GNUNET_MESSAGE_TYPE_SENSOR_END == ntohs (message->type))
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)
555 updating = GNUNET_NO;
556 cleanup_updatepoint (up_default);
562 sbm = (struct GNUNET_SENSOR_SensorBriefMessage *) message;
563 version_major = ntohs (sbm->version_major);
564 version_minor = ntohs (sbm->version_minor);
566 update_required ((char *) &sbm[1], version_major, version_minor))
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++;
581 GNUNET_CADET_receive_done (channel);
587 * Update local sensor definitions with a sensor retrieved from an update point.
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
598 update_sensor (char *sensorname, void *sensorfile, uint16_t sensorfile_size,
599 char *scriptname, void *scriptfile, uint16_t scriptfile_size)
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,
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)
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);
630 GNUNET_free (sensors_dir);
631 GNUNET_free (sensor_path);
637 * Resets the service after we are done with an update.
643 reset (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
650 * Handler of a sensor list message received from an update point.
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).
660 handle_sensor_full (void *cls, struct GNUNET_CADET_Channel *channel,
662 const struct GNUNET_MessageHeader *message)
664 struct GNUNET_SENSOR_SensorFullMessage *sfm;
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;
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))
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)
691 scriptname_ptr = sensorfile_ptr + sensorfile_size;
692 scriptfile_ptr = scriptname_ptr + ntohs (sfm->scriptname_size);
696 scriptname_ptr = NULL;
697 scriptfile_ptr = NULL;
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)
704 updating = GNUNET_NO;
705 cleanup_updatepoint (up_default);
706 GNUNET_SCHEDULER_add_continuation (&reset, NULL, 0);
709 GNUNET_CADET_receive_done (channel);
715 * Function called whenever a channel is destroyed. Should clean up
716 * any associated state.
718 * It must NOT call #GNUNET_CADET_channel_destroy on the channel.
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
726 cadet_channel_destroyed (void *cls, const struct GNUNET_CADET_Channel *channel,
729 struct UpdatePoint *up = channel_ctx;
732 if (GNUNET_YES == updating)
737 cleanup_updatepoint (up);
742 * Start the sensor update module
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
750 SENSOR_update_start (const struct GNUNET_CONFIGURATION_Handle *c,
751 struct GNUNET_CONTAINER_MultiHashMap *s, void (*cb) ())
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},
760 GNUNET_assert (NULL != s);
765 GNUNET_CADET_connect (cfg, NULL, NULL, &cadet_channel_destroyed,
766 cadet_handlers, NULL);
769 LOG (GNUNET_ERROR_TYPE_ERROR, _("Failed to connect to CADET service.\n"));
770 SENSOR_update_stop ();
771 return GNUNET_SYSERR;
773 if (GNUNET_OK != load_update_points ())
775 LOG (GNUNET_ERROR_TYPE_ERROR, "Failed to load update points.\n");
776 SENSOR_update_stop ();
777 return GNUNET_SYSERR;
779 up_default = up_head;
780 updating = GNUNET_NO;
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");
788 /* end of gnunet-service-sensor_update.c */