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 * Path to sensor definition directory
136 static char *sensor_dir;
139 * Hashmap of known sensors
141 static struct GNUNET_CONTAINER_MultiHashMap *sensors;
144 * Head of update points DLL.
146 static struct UpdatePoint *up_head;
149 * Tail of update points DLL.
151 static struct UpdatePoint *up_tail;
154 * The current default update point to use.
156 static struct UpdatePoint *up_default;
159 * Handle to CADET service
161 static struct GNUNET_CADET_Handle *cadet;
164 * Are we in the process of checking and updating sensors?
169 * GNUnet scheduler task that starts the update check process.
171 static GNUNET_SCHEDULER_TaskIdentifier update_task;
174 * Pointer to service reset function called when we have new sensor updates.
176 static void (*reset_cb) ();
180 * Contact update points to check for new updates
183 * @param tc GNUnet scheduler task context
186 check_for_updates (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
190 * Trigger sending next pending message to the default update point if any.
194 trigger_send_next_msg ();
198 * Cleanup update point context. This does not destroy the struct itself.
200 * @param up UpdatePoint struct
203 cleanup_updatepoint (struct UpdatePoint *up)
205 struct PendingMessage *pm;
207 up->expecting_sensor_list = GNUNET_NO;
208 up->expected_sensor_updates = 0;
211 GNUNET_CADET_notify_transmit_ready_cancel (up->th);
217 GNUNET_CONTAINER_DLL_remove (up->pm_head, up->pm_tail, pm);
218 GNUNET_free (pm->msg);
224 GNUNET_CADET_channel_destroy (up->ch);
231 * Stop the sensor update module.
234 SENSOR_update_stop ()
236 struct UpdatePoint *up;
240 if (GNUNET_SCHEDULER_NO_TASK != update_task)
242 GNUNET_SCHEDULER_cancel (update_task);
243 update_task = GNUNET_SCHEDULER_NO_TASK;
247 GNUNET_CONTAINER_DLL_remove (up_head, up_tail, up);
248 cleanup_updatepoint (up);
254 GNUNET_CADET_disconnect (cadet);
257 if (NULL != sensor_dir)
259 GNUNET_free (sensor_dir);
262 LOG (GNUNET_ERROR_TYPE_DEBUG, "Sensor update module stopped.\n");
267 * A failure occured in connecting/retrieval/verification with current default
268 * update point. This method will try to find another update point, do cleanup
269 * and reschedule update check.
274 struct UpdatePoint *up;
276 cleanup_updatepoint (up_default);
277 if (up_default == up_tail)
279 LOG (GNUNET_ERROR_TYPE_WARNING,
280 "All defined update points failed. Will retry again in %s.\n",
281 GNUNET_STRINGS_relative_time_to_string (SENSOR_UPDATE_CHECK_INTERVAL,
286 up->failed = GNUNET_NO;
290 GNUNET_SCHEDULER_add_delayed (SENSOR_UPDATE_CHECK_INTERVAL,
291 &check_for_updates, NULL);
294 LOG (GNUNET_ERROR_TYPE_WARNING,
295 "Update point `%s' failed, trying next one now.\n",
296 GNUNET_i2s (&up_default->peer_id));
297 up_default = up_default->next;
298 update_task = GNUNET_SCHEDULER_add_now (&check_for_updates, NULL);
303 * Function called to notify a client about the connection begin ready
304 * to queue more data. @a buf will be NULL and @a size zero if the
305 * connection was closed for writing in the meantime.
307 * Perform the actual sending of the message to update point.
309 * @param cls closure (unused)
310 * @param size number of bytes available in @a buf
311 * @param buf where the callee should write the message
312 * @return number of bytes written to @a buf
315 do_send_msg (void *cls, size_t size, void *buf)
317 struct PendingMessage *pm;
320 up_default->th = NULL;
321 pm = up_default->pm_head;
322 msg_size = ntohs (pm->msg->size);
323 GNUNET_CONTAINER_DLL_remove (up_default->pm_head, up_default->pm_tail, pm);
324 if (NULL == buf || size < msg_size)
326 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
327 _("Error trying to send a message to update point `%s'.\n"),
328 GNUNET_i2s (&up_default->peer_id));
332 memcpy (buf, pm->msg, msg_size);
333 GNUNET_free (pm->msg);
335 trigger_send_next_msg ();
341 * Trigger sending next pending message to the default update point if any.
345 trigger_send_next_msg ()
347 struct PendingMessage *pm;
349 if (NULL == up_default->pm_head)
351 if (NULL != up_default->th)
353 pm = up_default->pm_head;
355 GNUNET_CADET_notify_transmit_ready (up_default->ch, GNUNET_YES,
356 GNUNET_TIME_UNIT_FOREVER_REL,
357 ntohs (pm->msg->size), &do_send_msg,
363 * Add a message to the queue to be sent to the current default update point.
365 * @param msg Message to be queued
368 queue_msg (struct GNUNET_MessageHeader *msg)
370 struct PendingMessage *pm;
372 pm = GNUNET_new (struct PendingMessage);
375 GNUNET_CONTAINER_DLL_insert_tail (up_default->pm_head, up_default->pm_tail,
377 trigger_send_next_msg ();
382 * Contact update points to check for new updates
385 * @param tc GNUnet scheduler task context
388 check_for_updates (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
390 struct GNUNET_MessageHeader *msg;
393 update_task = GNUNET_SCHEDULER_NO_TASK;
394 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
396 if (GNUNET_YES == updating)
398 LOG (GNUNET_ERROR_TYPE_WARNING,
399 "Update process still running and update interval already exhausted."
401 GNUNET_STRINGS_relative_time_to_string (SENSOR_UPDATE_CHECK_RETRY,
404 GNUNET_SCHEDULER_add_delayed (SENSOR_UPDATE_CHECK_RETRY,
405 &check_for_updates, NULL);
408 updating = GNUNET_YES;
409 LOG (GNUNET_ERROR_TYPE_DEBUG, "Checking for sensor updates.\n");
410 GNUNET_assert (NULL != up_default);
412 GNUNET_CADET_channel_create (cadet, up_default, &up_default->peer_id,
413 GNUNET_APPLICATION_TYPE_SENSORUPDATE,
414 GNUNET_CADET_OPTION_DEFAULT);
415 if (NULL == up_default->ch)
417 LOG (GNUNET_ERROR_TYPE_ERROR,
418 _("Failed to connect to update point `%s'.\n"),
419 GNUNET_i2s (&up_default->peer_id));
423 /* Start by requesting list of sensors available from update point */
424 up_default->expecting_sensor_list = GNUNET_YES;
425 msg = GNUNET_new (struct GNUNET_MessageHeader);
426 msg_size = sizeof (struct GNUNET_MessageHeader);
427 msg->size = htons (msg_size);
428 msg->type = htons (GNUNET_MESSAGE_TYPE_SENSOR_LIST_REQ);
431 GNUNET_SCHEDULER_add_delayed (SENSOR_UPDATE_CHECK_INTERVAL,
432 &check_for_updates, NULL);
437 * Function that reads and validates (correctness not connectivity) of available
438 * sensor update points.
440 * @return number of update points loaded successfully
443 load_update_points ()
450 struct GNUNET_CRYPTO_EddsaPublicKey public_key;
451 struct UpdatePoint *up;
455 GNUNET_CONFIGURATION_get_value_string (cfg, "sensor-update",
456 "UPDATE_POINTS", &points_list))
460 points_list_len = strlen (points_list) + 1;
461 for (i = 0; i < points_list_len; i++)
463 if (' ' == points_list[i])
467 while (' ' != points_list[i] && '\0' != points_list[i])
473 GNUNET_CRYPTO_eddsa_public_key_from_string (points_list + start, len,
476 LOG (GNUNET_ERROR_TYPE_ERROR,
477 "Invalid EDDSA public key `%.*s' for update point.\n", len,
481 up = GNUNET_new (struct UpdatePoint);
483 up->peer_id.public_key = public_key;
486 up->expecting_sensor_list = GNUNET_NO;
487 up->expected_sensor_updates = 0;
488 up->failed = GNUNET_NO;
489 GNUNET_CONTAINER_DLL_insert (up_head, up_tail, up);
491 LOG (GNUNET_ERROR_TYPE_DEBUG, "Loaded update point `%s'.\n",
492 GNUNET_i2s_full (&up->peer_id));
494 GNUNET_free (points_list);
500 * Checks if the given sensor name and version (retrieved from an update point)
501 * is new for us and we would like to install it. This is the case if we don't
502 * have this sensor or we have an old version of it.
504 * @param sensorname Sensor name
505 * @param sensorversion_major First part of version number
506 * @param sensorversion_minor Second part of version number
507 * @return #GNUNET_YES if we don't have this sensor
508 * #GNUNET_NO if we have it
511 update_required (char *sensorname, uint16_t sensorversion_major,
512 uint16_t sensorversion_minor)
514 struct GNUNET_HashCode key;
515 struct GNUNET_SENSOR_SensorInfo *local_sensor;
517 GNUNET_CRYPTO_hash (sensorname, strlen (sensorname) + 1, &key);
518 local_sensor = GNUNET_CONTAINER_multihashmap_get (sensors, &key);
519 if (NULL == local_sensor)
521 if (GNUNET_SENSOR_version_compare
522 (local_sensor->version_major, local_sensor->version_minor,
523 sensorversion_major, sensorversion_minor) < 0)
530 * Handler of a sensor list message received from an update point.
532 * @param cls Closure (unused).
533 * @param channel Connection to the other end.
534 * @param channel_ctx Place to store local state associated with the channel.
535 * @param message The actual message.
536 * @return #GNUNET_OK to keep the channel open,
537 * #GNUNET_SYSERR to close it (signal serious error).
540 handle_sensor_brief (void *cls, struct GNUNET_CADET_Channel *channel,
542 const struct GNUNET_MessageHeader *message)
544 struct GNUNET_SENSOR_SensorBriefMessage *sbm;
545 struct GNUNET_MessageHeader *pull_req;
546 uint16_t version_major;
547 uint16_t version_minor;
550 GNUNET_assert (*channel_ctx == up_default);
551 if (GNUNET_YES != up_default->expecting_sensor_list)
557 if (GNUNET_MESSAGE_TYPE_SENSOR_END == ntohs (message->type))
559 LOG (GNUNET_ERROR_TYPE_DEBUG,
560 "Received end of sensor list msg. We already requested %d updates.\n",
561 up_default->expected_sensor_updates);
562 up_default->expecting_sensor_list = GNUNET_NO;
563 if (0 == up_default->expected_sensor_updates)
565 updating = GNUNET_NO;
566 cleanup_updatepoint (up_default);
572 sbm = (struct GNUNET_SENSOR_SensorBriefMessage *) message;
573 version_major = ntohs (sbm->version_major);
574 version_minor = ntohs (sbm->version_minor);
576 update_required ((char *) &sbm[1], version_major, version_minor))
578 LOG (GNUNET_ERROR_TYPE_INFO,
579 "Requesting sensor %s %d.%d from update point.\n", &sbm[1],
580 version_major, version_minor);
581 /* We duplicate the same msg received but change the type and send it
582 * back to update point to ask for full sensor information. */
583 msg_size = ntohs (message->size);
584 pull_req = GNUNET_malloc (msg_size);
585 memcpy (pull_req, message, msg_size);
586 pull_req->type = htons (GNUNET_MESSAGE_TYPE_SENSOR_FULL_REQ);
587 queue_msg (pull_req);
588 up_default->expected_sensor_updates++;
591 GNUNET_CADET_receive_done (channel);
597 * Update local sensor definitions with a sensor retrieved from an update point.
599 * @param sensorname Sensor name
600 * @param sensorfile Buffer containing the sensor definition file
601 * @param sensorfile_size Size of @e sensorfile
602 * @param scriptname Name of associated script file, NULL if no script
603 * @param scriptfile Buffer containing the script file, NULL if no script
604 * @param scriptfile_size Size of @e scriptfile, 0 if no script
605 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
608 update_sensor (char *sensorname, void *sensorfile, uint16_t sensorfile_size,
609 char *scriptname, void *scriptfile, uint16_t scriptfile_size)
614 LOG (GNUNET_ERROR_TYPE_INFO,
615 "Received new sensor information:\n" "Name: %s\n"
616 "Sensor file size: %d\n" "Script name: %s\n" "Script file size: %d.\n",
617 sensorname, sensorfile_size, (NULL == scriptname) ? "None" : scriptname,
619 GNUNET_asprintf (&sensor_path, "%s%s", sensor_dir, sensorname);
620 GNUNET_DISK_fn_write (sensor_path, sensorfile, sensorfile_size,
621 GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_GROUP_READ
622 | GNUNET_DISK_PERM_OTHER_READ |
623 GNUNET_DISK_PERM_USER_WRITE);
624 if (NULL != scriptname)
626 GNUNET_asprintf (&script_path, "%s-files%s%s", sensor_path,
627 DIR_SEPARATOR_STR, scriptname);
628 GNUNET_DISK_fn_write (script_path, scriptfile, scriptfile_size,
629 GNUNET_DISK_PERM_USER_READ |
630 GNUNET_DISK_PERM_GROUP_READ |
631 GNUNET_DISK_PERM_OTHER_READ |
632 GNUNET_DISK_PERM_USER_WRITE |
633 GNUNET_DISK_PERM_GROUP_WRITE |
634 GNUNET_DISK_PERM_USER_EXEC |
635 GNUNET_DISK_PERM_GROUP_EXEC);
636 GNUNET_free (script_path);
638 GNUNET_free (sensor_path);
644 * Resets the service after we are done with an update.
650 reset (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
657 * Handler of a sensor list message received from an update point.
659 * @param cls Closure (unused).
660 * @param channel Connection to the other end.
661 * @param channel_ctx Place to store local state associated with the channel.
662 * @param message The actual message.
663 * @return #GNUNET_OK to keep the channel open,
664 * #GNUNET_SYSERR to close it (signal serious error).
667 handle_sensor_full (void *cls, struct GNUNET_CADET_Channel *channel,
669 const struct GNUNET_MessageHeader *message)
671 struct GNUNET_SENSOR_SensorFullMessage *sfm;
673 uint16_t sensorfile_size;
674 uint16_t scriptfile_size;
675 char *sensorname_ptr;
676 void *sensorfile_ptr;
677 char *scriptname_ptr;
678 void *scriptfile_ptr;
681 GNUNET_assert (*channel_ctx == up_default);
682 msg_size = ntohs (message->size);
683 if (up_default->expected_sensor_updates <= 0 ||
684 msg_size < sizeof (struct GNUNET_SENSOR_SensorFullMessage))
690 /* parse received msg */
691 sfm = (struct GNUNET_SENSOR_SensorFullMessage *) message;
692 sensorname_ptr = (char *) &sfm[1];
693 sensorfile_ptr = sensorname_ptr + ntohs (sfm->sensorname_size);
694 sensorfile_size = ntohs (sfm->sensorfile_size);
695 scriptfile_size = ntohs (sfm->scriptfile_size);
696 if (scriptfile_size > 0)
698 scriptname_ptr = sensorfile_ptr + sensorfile_size;
699 scriptfile_ptr = scriptname_ptr + ntohs (sfm->scriptname_size);
703 scriptname_ptr = NULL;
704 scriptfile_ptr = NULL;
706 update_sensor ((char *) &sfm[1], sensorfile_ptr, sensorfile_size,
707 scriptname_ptr, scriptfile_ptr, scriptfile_size);
708 up_default->expected_sensor_updates--;
709 if (0 == up_default->expected_sensor_updates)
711 updating = GNUNET_NO;
712 cleanup_updatepoint (up_default);
713 GNUNET_SCHEDULER_add_continuation (&reset, NULL, 0);
716 GNUNET_CADET_receive_done (channel);
722 * Function called whenever a channel is destroyed. Should clean up
723 * any associated state.
725 * It must NOT call #GNUNET_CADET_channel_destroy on the channel.
727 * @param cls closure (set from #GNUNET_CADET_connect)
728 * @param channel connection to the other end (henceforth invalid)
729 * @param channel_ctx place where local state associated
730 * with the channel is stored
733 cadet_channel_destroyed (void *cls, const struct GNUNET_CADET_Channel *channel,
736 struct UpdatePoint *up = channel_ctx;
739 if (GNUNET_YES == updating)
744 cleanup_updatepoint (up);
749 * Start the sensor update module
751 * @param c our service configuration
752 * @param s multihashmap of loaded sensors
753 * @param cb callback to reset service components when we have new updates
754 * @return #GNUNET_OK if started successfully, #GNUNET_SYSERR otherwise
757 SENSOR_update_start (const struct GNUNET_CONFIGURATION_Handle *c,
758 struct GNUNET_CONTAINER_MultiHashMap *s, void (*cb) ())
760 static struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
761 {&handle_sensor_brief, GNUNET_MESSAGE_TYPE_SENSOR_BRIEF, 0},
762 {&handle_sensor_brief, GNUNET_MESSAGE_TYPE_SENSOR_END, 0},
763 {&handle_sensor_full, GNUNET_MESSAGE_TYPE_SENSOR_FULL, 0},
768 GNUNET_assert (NULL != s);
773 GNUNET_CONFIGURATION_get_value_filename (cfg, "SENSOR", "SENSOR_DIR",
775 sensor_dir = GNUNET_SENSOR_get_default_sensor_dir ();
777 GNUNET_CADET_connect (cfg, NULL, NULL, &cadet_channel_destroyed,
778 cadet_handlers, NULL);
781 LOG (GNUNET_ERROR_TYPE_ERROR, _("Failed to connect to CADET service.\n"));
782 SENSOR_update_stop ();
783 return GNUNET_SYSERR;
785 up_count = load_update_points ();
786 LOG (GNUNET_ERROR_TYPE_DEBUG, "Loaded %d update points.\n", up_count);
789 SENSOR_update_stop ();
790 return GNUNET_SYSERR;
792 up_default = up_head;
793 updating = GNUNET_NO;
795 GNUNET_SCHEDULER_add_delayed (SENSOR_UPDATE_CHECK_INTERVAL,
796 &check_for_updates, NULL);
797 LOG (GNUNET_ERROR_TYPE_DEBUG, "Sensor update module started.\n");
801 /* end of gnunet-service-sensor_update.c */