2 This file is part of GNUnet.
3 (C) 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2010 Christian Grothoff (and other contributing authors)
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 2, 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 hostlist/hostlist-client.c
23 * @brief hostlist support. Downloads HELLOs via HTTP.
24 * @author Christian Grothoff
25 * @author Matthias Wachs
29 #include "hostlist-client.h"
30 #include "gnunet_core_service.h"
31 #include "gnunet_hello_lib.h"
32 #include "gnunet_statistics_service.h"
33 #include "gnunet_transport_service.h"
34 #include "gnunet-daemon-hostlist.h"
35 #include <curl/curl.h>
36 #include "gnunet_common.h"
37 #include "gnunet_bio_lib.h"
39 #define DEBUG_HOSTLIST_CLIENT GNUNET_YES
41 #define MAX_URL_LEN 1000
44 * Number of connections that we must have to NOT download
47 #define MIN_CONNECTIONS 4
50 * A single hostlist obtained by hostlist advertisements
55 * previous entry, used to manage entries in a double linked list
57 struct Hostlist * prev;
60 * next entry, used to manage entries in a double linked list
62 struct Hostlist * next;
65 * URI where hostlist can be obtained
67 const char *hostlist_uri;
70 * Value describing the quality of the hostlist, the bigger the better but (should) never < 0
71 * used for deciding which hostlist is replaced if MAX_NUMBER_HOSTLISTS in data structure is reached
72 * intial value = HOSTLIST_INITIAL
73 * increased every successful download by HOSTLIST_SUCCESSFULL_DOWNLOAD
74 * increased every successful download by number of obtained HELLO messages
75 * decreased every failed download by HOSTLIST_SUCCESSFULL_DOWNLOAD
80 * Time the hostlist advertisement was recieved and the entry was created
82 struct GNUNET_TIME_Absolute time_creation;
85 * Last time the hostlist was obtained
87 struct GNUNET_TIME_Absolute time_last_usage;
90 * Number of HELLO messages obtained during last download
95 * Number of times the hostlist was obtained
105 static const struct GNUNET_CONFIGURATION_Handle *cfg;
110 static struct GNUNET_SCHEDULER_Handle *sched;
115 struct GNUNET_STATISTICS_Handle *stats;
120 struct GNUNET_TRANSPORT_Handle *transport;
123 * Proxy that we are using (can be NULL).
128 * Buffer for data downloaded via HTTP.
130 static char download_buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE];
133 * Number of bytes valid in 'download_buffer'.
135 static size_t download_pos;
138 * Current URL that we are using.
140 static char *current_url;
143 * Current CURL handle.
148 * Current multi-CURL handle.
153 * ID of the current task scheduled.
155 static GNUNET_SCHEDULER_TaskIdentifier current_task;
158 * ID of the current hostlist saving task scheduled.
160 static GNUNET_SCHEDULER_TaskIdentifier saving_task;
163 * Amount of time we wait between hostlist downloads.
165 static struct GNUNET_TIME_Relative hostlist_delay;
168 * Set to GNUNET_YES if the current URL had some problems.
170 static int bogus_url;
173 * Number of active connections (according to core service).
175 static unsigned int connection_count;
178 * At what time MUST the current hostlist request be done?
180 static struct GNUNET_TIME_Absolute end_time;
183 * Head of the linked list used to store hostlists
185 static struct Hostlist * linked_list_head;
188 * Tail of the linked list used to store hostlists
190 static struct Hostlist * linked_list_tail;
193 * Size of the linke list used to store hostlists
195 static unsigned int linked_list_size;
198 * Value saying if preconfigured is used
200 static unsigned int use_preconfigured_list;
203 * Process downloaded bits by calling callback on each HELLO.
205 * @param ptr buffer with downloaded data
206 * @param size size of a record
207 * @param nmemb number of records downloaded
209 * @return number of bytes that were processed (always size*nmemb)
212 download_hostlist_processor (void *ptr,
217 const char * cbuf = ptr;
218 const struct GNUNET_MessageHeader *msg;
224 total = size * nmemb;
225 if ( (total == 0) || (bogus_url) )
227 return total; /* ok, no data or bogus data */
229 GNUNET_STATISTICS_update (stats,
230 gettext_noop ("# bytes downloaded from hostlist servers"),
234 while ( (left > 0) ||
237 cpy = GNUNET_MIN (left, GNUNET_SERVER_MAX_MESSAGE_SIZE - download_pos);
238 memcpy (&download_buffer[download_pos],
244 if (download_pos < sizeof(struct GNUNET_MessageHeader))
246 GNUNET_assert (left == 0);
249 msg = (const struct GNUNET_MessageHeader *) download_buffer;
250 msize = ntohs(msg->size);
251 if (msize < sizeof(struct GNUNET_MessageHeader))
253 GNUNET_STATISTICS_update (stats,
254 gettext_noop ("# invalid HELLOs downloaded from hostlist servers"),
257 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
258 _("Invalid `%s' message received from hostlist at `%s'\n"),
264 if (download_pos < msize)
266 GNUNET_assert (left == 0);
269 if (GNUNET_HELLO_size ((const struct GNUNET_HELLO_Message*)msg) == msize)
271 #if DEBUG_HOSTLIST_CLIENT
272 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
273 "Received valid `%s' message from hostlist server.\n",
276 GNUNET_STATISTICS_update (stats,
277 gettext_noop ("# valid HELLOs downloaded from hostlist servers"),
280 GNUNET_TRANSPORT_offer_hello (transport, msg);
284 GNUNET_STATISTICS_update (stats,
285 gettext_noop ("# invalid HELLOs downloaded from hostlist servers"),
288 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
289 _("Invalid `%s' message received from hostlist at `%s'\n"),
292 bogus_url = GNUNET_YES;
295 memmove (download_buffer,
296 &download_buffer[msize],
297 download_pos - msize);
298 download_pos -= msize;
305 * Obtain a hostlist URL that we should use.
307 * @return NULL if there is no URL available
318 GNUNET_CONFIGURATION_get_value_string (cfg,
323 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
324 _("No `%s' specified in `%s' configuration, will not bootstrap.\n"),
325 "SERVERS", "HOSTLIST");
330 if (strlen (servers) > 0)
333 pos = strlen (servers) - 1;
336 if (servers[pos] == ' ')
343 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
344 _("No `%s' specified in `%s' configuration, will not bootstrap.\n"),
345 "SERVERS", "HOSTLIST");
346 GNUNET_free (servers);
350 urls = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, urls) + 1;
351 pos = strlen (servers) - 1;
354 if (servers[pos] == ' ')
366 ret = GNUNET_strdup (&servers[pos]);
367 GNUNET_free (servers);
372 * Method deciding if a preconfigured or advertisied hostlist is used on a 50:50 ratio
373 * @return uri to use, NULL if there is no URL available
379 unsigned int counter;
380 struct Hostlist * pos;
382 if ( (GNUNET_YES == use_preconfigured_list) ||
383 (linked_list_size == 0) )
385 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
386 "Using preconfigured bootstrap server\n");
387 use_preconfigured_list = GNUNET_NO;
388 return get_bootstrap_url();
390 index = GNUNET_CRYPTO_random_u32 ( GNUNET_CRYPTO_QUALITY_WEAK, linked_list_size);
392 pos = linked_list_head;
393 while ( counter < index )
398 use_preconfigured_list = GNUNET_YES;
399 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
400 "Using learned hostlist `%s'\n", pos->hostlist_uri);
401 return strdup(pos->hostlist_uri);
405 #define CURL_EASY_SETOPT(c, a, b) do { ret = curl_easy_setopt(c, a, b); if (ret != CURLE_OK) GNUNET_log(GNUNET_ERROR_TYPE_WARNING, _("%s failed at %s:%d: `%s'\n"), "curl_easy_setopt", __FILE__, __LINE__, curl_easy_strerror(ret)); } while (0);
409 * Schedule the background task that will (possibly)
410 * download a hostlist.
413 schedule_hostlist_task (void);
416 * Method to load persistent hostlist file during hostlist client shutdown
417 * @param shutdown set if called because of shutdown, entries in linked list will be destroyed
419 static void save_hostlist_file ( int shutdown );
422 * Clean up the state from the task that downloaded the
423 * hostlist and schedule the next task.
432 mret = curl_multi_remove_handle (multi, curl);
433 if (mret != CURLM_OK)
435 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
436 _("%s failed at %s:%d: `%s'\n"),
437 "curl_multi_remove_handle", __FILE__, __LINE__,
438 curl_multi_strerror (mret));
440 mret = curl_multi_cleanup (multi);
441 if (mret != CURLM_OK)
442 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
443 _("%s failed at %s:%d: `%s'\n"),
444 "curl_multi_cleanup", __FILE__, __LINE__,
445 curl_multi_strerror (mret));
450 curl_easy_cleanup (curl);
453 GNUNET_free_non_null (current_url);
455 schedule_hostlist_task ();
460 * Ask CURL for the select set and then schedule the
461 * receiving task with the scheduler.
468 * Task that is run when we are ready to receive more data from the hostlist
471 * @param cls closure, unused
472 * @param tc task context, unused
475 multi_ready (void *cls,
476 const struct GNUNET_SCHEDULER_TaskContext *tc)
482 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
484 #if DEBUG_HOSTLIST_CLIENT
485 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
486 "Shutdown requested while trying to download hostlist from `%s'\n",
492 if (GNUNET_TIME_absolute_get_remaining (end_time).value == 0)
494 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
495 _("Timeout trying to download hostlist from `%s'\n"),
500 #if DEBUG_HOSTLIST_CLIENT
501 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
502 "Ready for processing hostlist client request\n");
507 mret = curl_multi_perform (multi, &running);
512 msg = curl_multi_info_read (multi, &running);
513 GNUNET_break (msg != NULL);
519 if ( (msg->data.result != CURLE_OK) &&
520 (msg->data.result != CURLE_GOT_NOTHING) )
521 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
522 _("%s failed for `%s' at %s:%d: `%s'\n"),
523 "curl_multi_perform",
527 curl_easy_strerror (msg->data.result));
529 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
530 _("Download of hostlist `%s' completed.\n"),
541 while (mret == CURLM_CALL_MULTI_PERFORM);
542 if (mret != CURLM_OK)
544 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
545 _("%s failed at %s:%d: `%s'\n"),
546 "curl_multi_perform", __FILE__, __LINE__,
547 curl_multi_strerror (mret));
555 * Ask CURL for the select set and then schedule the
556 * receiving task with the scheduler.
566 struct GNUNET_NETWORK_FDSet *grs;
567 struct GNUNET_NETWORK_FDSet *gws;
569 struct GNUNET_TIME_Relative rtime;
575 mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
576 if (mret != CURLM_OK)
578 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
579 _("%s failed at %s:%d: `%s'\n"),
580 "curl_multi_fdset", __FILE__, __LINE__,
581 curl_multi_strerror (mret));
585 mret = curl_multi_timeout (multi, &timeout);
586 if (mret != CURLM_OK)
588 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
589 _("%s failed at %s:%d: `%s'\n"),
590 "curl_multi_timeout", __FILE__, __LINE__,
591 curl_multi_strerror (mret));
595 rtime = GNUNET_TIME_relative_min (GNUNET_TIME_absolute_get_remaining (end_time),
596 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
598 grs = GNUNET_NETWORK_fdset_create ();
599 gws = GNUNET_NETWORK_fdset_create ();
600 GNUNET_NETWORK_fdset_copy_native (grs, &rs, max + 1);
601 GNUNET_NETWORK_fdset_copy_native (gws, &ws, max + 1);
602 #if DEBUG_HOSTLIST_CLIENT
603 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
604 "Scheduling task for hostlist download using cURL\n");
607 = GNUNET_SCHEDULER_add_select (sched,
608 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
609 GNUNET_SCHEDULER_NO_TASK,
615 GNUNET_NETWORK_fdset_destroy (gws);
616 GNUNET_NETWORK_fdset_destroy (grs);
621 * Main function that will download a hostlist and process its
630 current_url = get_list_url ();
631 if (current_url == NULL)
633 curl = curl_easy_init ();
641 GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
642 _("Bootstrapping using hostlist at `%s'.\n"),
644 GNUNET_STATISTICS_update (stats,
645 gettext_noop ("# hostlist downloads initiated"),
649 CURL_EASY_SETOPT (curl, CURLOPT_PROXY, proxy);
652 CURL_EASY_SETOPT (curl,
653 CURLOPT_WRITEFUNCTION,
654 &download_hostlist_processor);
660 CURL_EASY_SETOPT (curl,
668 CURL_EASY_SETOPT (curl, CURLOPT_FOLLOWLOCATION, 1);
669 CURL_EASY_SETOPT (curl, CURLOPT_MAXREDIRS, 4);
670 /* no need to abort if the above failed */
671 CURL_EASY_SETOPT (curl,
679 CURL_EASY_SETOPT (curl,
683 CURL_EASY_SETOPT (curl,
687 CURL_EASY_SETOPT (curl,
689 GNUNET_SERVER_MAX_MESSAGE_SIZE);
690 if (0 == strncmp (current_url, "http", 4))
691 CURL_EASY_SETOPT (curl, CURLOPT_USERAGENT, "GNUnet");
692 CURL_EASY_SETOPT (curl,
693 CURLOPT_CONNECTTIMEOUT,
695 CURL_EASY_SETOPT (curl,
699 /* this should no longer be needed; we're now single-threaded! */
700 CURL_EASY_SETOPT (curl,
704 multi = curl_multi_init ();
711 mret = curl_multi_add_handle (multi, curl);
712 if (mret != CURLM_OK)
714 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
715 _("%s failed at %s:%d: `%s'\n"),
716 "curl_multi_add_handle", __FILE__, __LINE__,
717 curl_multi_strerror (mret));
718 mret = curl_multi_cleanup (multi);
719 if (mret != CURLM_OK)
720 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
721 _("%s failed at %s:%d: `%s'\n"),
722 "curl_multi_cleanup", __FILE__, __LINE__,
723 curl_multi_strerror (mret));
728 end_time = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES);
734 * Task that checks if we should try to download a hostlist.
735 * If so, we initiate the download, otherwise we schedule
736 * this task again for a later time.
739 check_task (void *cls,
740 const struct GNUNET_SCHEDULER_TaskContext *tc)
742 current_task = GNUNET_SCHEDULER_NO_TASK;
743 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
745 if (connection_count < MIN_CONNECTIONS)
746 download_hostlist ();
748 schedule_hostlist_task ();
753 * Compute when we should check the next time about downloading
754 * a hostlist; then schedule the task accordingly.
757 schedule_hostlist_task ()
760 struct GNUNET_TIME_Relative delay;
764 curl_global_cleanup ();
765 return; /* in shutdown */
767 delay = hostlist_delay;
768 if (hostlist_delay.value == 0)
769 hostlist_delay = GNUNET_TIME_UNIT_SECONDS;
771 hostlist_delay = GNUNET_TIME_relative_multiply (hostlist_delay, 2);
772 if (hostlist_delay.value > GNUNET_TIME_UNIT_HOURS.value * (1 + connection_count))
773 hostlist_delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS,
774 (1 + connection_count));
775 GNUNET_STATISTICS_set (stats,
776 gettext_noop("# seconds between hostlist downloads"),
777 hostlist_delay.value,
781 delay = GNUNET_TIME_UNIT_ZERO;
784 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
785 _("Have %u/%u connections. Will consider downloading hostlist in %llums\n"),
788 (unsigned long long) delay.value);
789 current_task = GNUNET_SCHEDULER_add_delayed (sched,
796 * Task that writes hostlist entries to a file on a regular base
801 hostlist_saving_task (void *cls,
802 const struct GNUNET_SCHEDULER_TaskContext *tc)
804 saving_task = GNUNET_SCHEDULER_NO_TASK;
805 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
807 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
808 _("Scheduled saving of hostlists\n"));
809 save_hostlist_file ( GNUNET_NO );
811 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
812 _("Hostlists will be saved to file again in %llums\n"),
813 (unsigned long long) SAVING_INTERVALL.value);
814 saving_task = GNUNET_SCHEDULER_add_delayed (sched,
816 &hostlist_saving_task,
821 * Method called whenever a given peer connects.
824 * @param peer peer identity this notification is about
825 * @param latency reported latency of the connection with 'other'
826 * @param distance reported distance (DV) to 'other'
829 connect_handler (void *cls,
831 GNUNET_PeerIdentity * peer,
832 struct GNUNET_TIME_Relative latency,
836 GNUNET_STATISTICS_update (stats,
837 gettext_noop ("# active connections"),
844 * Method called whenever a given peer disconnects.
847 * @param peer peer identity this notification is about
850 disconnect_handler (void *cls,
852 GNUNET_PeerIdentity * peer)
855 GNUNET_STATISTICS_update (stats,
856 gettext_noop ("# active connections"),
863 * Method to check if URI is in hostlist linked list
864 * @param uri uri to check
865 * @return GNUNET_YES if existing in linked list, GNUNET_NO if not
868 linked_list_contains (const char * uri)
870 struct Hostlist * pos;
872 pos = linked_list_head;
875 if (0 == strcmp(pos->hostlist_uri, uri) )
884 static struct Hostlist *
885 linked_list_get_lowest_quality ( )
887 struct Hostlist * pos;
888 struct Hostlist * lowest;
890 if (linked_list_size == 0)
892 lowest = linked_list_head;
893 pos = linked_list_head->next;
896 if (pos->quality < lowest->quality)
905 * Method called whenever an advertisement message arrives.
907 * @param cls closure (always NULL)
908 * @param client identification of the client
909 * @param message the actual message
910 * @return GNUNET_OK to keep the connection open,
911 * GNUNET_SYSERR to close it (signal serious error)
914 advertisement_handler (void *cls,
915 const struct GNUNET_PeerIdentity * peer,
916 const struct GNUNET_MessageHeader * message,
917 struct GNUNET_TIME_Relative latency,
922 const struct GNUNET_MessageHeader * incoming;
924 struct Hostlist * hostlist;
926 GNUNET_assert (ntohs (message->type) == GNUNET_MESSAGE_TYPE_HOSTLIST_ADVERTISEMENT);
927 size = ntohs (message->size);
928 if (size <= sizeof(struct GNUNET_MessageHeader))
931 return GNUNET_SYSERR;
933 incoming = (const struct GNUNET_MessageHeader *) message;
934 uri = (const char*) &incoming[1];
935 uri_size = size - sizeof (struct GNUNET_MessageHeader);
936 if (uri [uri_size - 1] != '\0')
939 return GNUNET_SYSERR;
941 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
942 "Hostlist client recieved advertisement from `%s' containing URI `%s'\n",
945 if (GNUNET_NO != linked_list_contains (uri))
947 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
948 "URI `%s' is already known\n",
952 hostlist = GNUNET_malloc (sizeof (struct Hostlist) + uri_size);
953 hostlist->hostlist_uri = (const char*) &hostlist[1];
954 memcpy (&hostlist[1], uri, uri_size);
955 hostlist->time_creation = GNUNET_TIME_absolute_get();
956 hostlist->time_last_usage = GNUNET_TIME_absolute_get_zero();
957 hostlist->quality = HOSTLIST_INITIAL;
959 GNUNET_CONTAINER_DLL_insert(linked_list_head, linked_list_tail, hostlist);
962 if (MAX_NUMBER_HOSTLISTS >= linked_list_size)
965 /* No free entries available, replace existing entry */
966 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
967 "Removing lowest quality entry\n" );
968 struct Hostlist * lowest_quality = linked_list_get_lowest_quality();
969 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
970 "Hostlist with URI `%s' has the worst quality of all with value %llu\n",
971 lowest_quality->hostlist_uri,
972 (unsigned long long) lowest_quality->quality);
973 GNUNET_CONTAINER_DLL_remove (linked_list_head, linked_list_tail, lowest_quality);
975 GNUNET_free (lowest_quality);
981 * Continuation called by the statistics code once
982 * we go the stat. Initiates hostlist download scheduling.
985 * @param success GNUNET_OK if statistics were
986 * successfully obtained, GNUNET_SYSERR if not.
989 primary_task (void *cls, int success)
992 return; /* in shutdown */
993 #if DEBUG_HOSTLIST_CLIENT
994 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
995 "Statistics request done, scheduling hostlist download\n");
997 schedule_hostlist_task ();
1002 process_stat (void *cls,
1003 const char *subsystem,
1008 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1009 _("Initial time between hostlist downloads is %llums\n"),
1010 (unsigned long long) value);
1011 hostlist_delay.value = value;
1016 * Method to load persistent hostlist file during hostlist client startup
1019 load_hostlist_file ()
1024 struct Hostlist * hostlist;
1026 uint32_t times_used;
1027 uint32_t hellos_returned;
1034 GNUNET_CONFIGURATION_get_value_string (cfg,
1039 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1040 _("No `%s' specified in `%s' configuration, cannot load hostlists from file.\n"),
1041 "HOSTLISTFILE", "HOSTLIST");
1045 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1046 _("Loading saved hostlist entries from file `%s' \n"), filename);
1048 struct GNUNET_BIO_ReadHandle * rh = GNUNET_BIO_read_open (filename);
1051 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1052 _("Could not open file `%s' for reading to load hostlists: %s\n"),
1055 GNUNET_free (filename);
1060 while ( (GNUNET_OK == GNUNET_BIO_read_string (rh, "url" , &uri, MAX_URL_LEN)) &&
1061 (GNUNET_OK == GNUNET_BIO_read_int32 (rh, ×_used)) &&
1062 (GNUNET_OK == GNUNET_BIO_read_int64 (rh, &quality)) &&
1063 (GNUNET_OK == GNUNET_BIO_read_int64 (rh, &last_used)) &&
1064 (GNUNET_OK == GNUNET_BIO_read_int64 (rh, &created)) &&
1065 (GNUNET_OK == GNUNET_BIO_read_int32 (rh, &hellos_returned)) )
1067 hostlist = GNUNET_malloc (sizeof (struct Hostlist) + strlen (uri) + 1);
1068 hostlist->hello_count = hellos_returned;
1069 hostlist->hostlist_uri = (const char *) &hostlist[1];
1070 memcpy (&hostlist[1], uri, strlen(uri)+1);
1071 hostlist->quality = quality;
1072 hostlist->time_creation.value = created;
1073 hostlist->time_last_usage.value = last_used;
1074 GNUNET_CONTAINER_DLL_insert(linked_list_head, linked_list_tail, hostlist);
1076 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1077 "Added hostlist entry eith URI `%s' \n", hostlist->hostlist_uri);
1081 if ( counter >= MAX_NUMBER_HOSTLISTS ) break;
1084 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1085 _("%u hostlist URIs loaded from file\n"), counter);
1086 GNUNET_STATISTICS_set (stats,
1087 gettext_noop("# hostlis URIs read from file"),
1091 GNUNET_free_non_null (uri);
1093 GNUNET_BIO_read_close (rh, &emsg);
1096 GNUNET_free (filename);
1101 * Method to load persistent hostlist file during hostlist client shutdown
1102 * @param shutdown set if called because of shutdown, entries in linked list will be destroyed
1104 static void save_hostlist_file ( int shutdown )
1107 struct Hostlist *pos;
1108 struct GNUNET_BIO_WriteHandle * wh;
1113 GNUNET_CONFIGURATION_get_value_string (cfg,
1118 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1119 _("No `%s' specified in `%s' configuration, cannot save hostlists to file.\n"),
1120 "HOSTLISTFILE", "HOSTLIST");
1121 GNUNET_free (filename);
1124 wh = GNUNET_BIO_write_open (filename);
1127 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1128 _("Could not open file `%s' for writing to save hostlists: %s\n"),
1131 GNUNET_free (filename);
1134 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1135 _("Writing %u hostlist URIs to `%s'\n" ),
1136 linked_list_size, filename);
1138 /* add code to write hostlists to file using bio */
1141 while (NULL != (pos = linked_list_head))
1143 if ( GNUNET_YES == shutdown)
1145 GNUNET_CONTAINER_DLL_remove (linked_list_head, linked_list_tail, pos);
1148 if (GNUNET_YES == ok)
1151 GNUNET_BIO_write_string (wh, pos->hostlist_uri)) ||
1153 GNUNET_BIO_write_int32 (wh, pos->times_used)) ||
1155 GNUNET_BIO_write_int64 (wh, pos->quality)) ||
1157 GNUNET_BIO_write_int64 (wh, pos->time_last_usage.value)) ||
1159 GNUNET_BIO_write_int64 (wh, pos->time_creation.value)) ||
1161 GNUNET_BIO_write_int32 (wh, pos->hello_count)))
1163 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1164 _("Error writing hostlist URIs to file `%s'\n"),
1170 if ( GNUNET_YES == shutdown)
1173 if ( counter >= MAX_NUMBER_HOSTLISTS) break;
1175 GNUNET_STATISTICS_set (stats,
1176 gettext_noop("# hostlist URIs written to file"),
1180 if ( GNUNET_OK != GNUNET_BIO_write_close ( wh ) )
1181 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1182 _("Error writing hostlist URIs to file `%s'\n"),
1184 GNUNET_free (filename);
1188 * Start downloading hostlists from hostlist servers as necessary.
1191 GNUNET_HOSTLIST_client_start (const struct GNUNET_CONFIGURATION_Handle *c,
1192 struct GNUNET_SCHEDULER_Handle *s,
1193 struct GNUNET_STATISTICS_Handle *st,
1194 GNUNET_CORE_ConnectEventHandler *ch,
1195 GNUNET_CORE_DisconnectEventHandler *dh,
1196 GNUNET_CORE_MessageCallback *msgh,
1199 if (0 != curl_global_init (CURL_GLOBAL_WIN32))
1202 return GNUNET_SYSERR;
1204 transport = GNUNET_TRANSPORT_connect (s, c, NULL, NULL, NULL, NULL);
1205 if (NULL == transport)
1207 curl_global_cleanup ();
1208 return GNUNET_SYSERR;
1214 GNUNET_CONFIGURATION_get_value_string (cfg,
1219 *ch = &connect_handler;
1220 *dh = &disconnect_handler;
1222 *msgh = &advertisement_handler;
1225 linked_list_head = NULL;
1226 linked_list_tail = NULL;
1227 use_preconfigured_list = GNUNET_YES;
1228 load_hostlist_file ();
1230 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1231 _("Hostlists will be saved to file again in %llums\n"),
1232 (unsigned long long) SAVING_INTERVALL.value);
1233 saving_task = GNUNET_SCHEDULER_add_delayed (sched,
1235 &hostlist_saving_task,
1238 GNUNET_STATISTICS_get (stats,
1240 gettext_noop("# seconds between hostlist downloads"),
1241 GNUNET_TIME_UNIT_MINUTES,
1250 * Stop downloading hostlists from hostlist servers as necessary.
1253 GNUNET_HOSTLIST_client_stop ()
1255 #if DEBUG_HOSTLIST_CLIENT
1256 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1257 "Hostlist client shutdown\n");
1259 save_hostlist_file ( GNUNET_YES );
1261 if (current_task != GNUNET_SCHEDULER_NO_TASK)
1263 GNUNET_SCHEDULER_cancel (sched,
1265 curl_global_cleanup ();
1267 if (transport != NULL)
1269 GNUNET_TRANSPORT_disconnect (transport);
1272 GNUNET_assert (NULL == transport);
1273 GNUNET_free_non_null (proxy);
1279 /* end of hostlist-client.c */