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, Matthias Wachs
28 #include "hostlist-client.h"
29 #include "gnunet_core_service.h"
30 #include "gnunet_hello_lib.h"
31 #include "gnunet_statistics_service.h"
32 #include "gnunet_transport_service.h"
33 #include "gnunet-daemon-hostlist.h"
34 #include <curl/curl.h>
35 #include "gnunet_common.h"
36 #include "gnunet_bio_lib.h"
38 #define DEBUG_HOSTLIST_CLIENT GNUNET_YES
41 * Number of connections that we must have to NOT download
44 #define MIN_CONNECTIONS 4
49 static const struct GNUNET_CONFIGURATION_Handle *cfg;
54 static struct GNUNET_SCHEDULER_Handle *sched;
59 struct GNUNET_STATISTICS_Handle *stats;
64 struct GNUNET_TRANSPORT_Handle *transport;
67 * Proxy that we are using (can be NULL).
72 * Buffer for data downloaded via HTTP.
74 static char download_buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE];
77 * Number of bytes valid in 'download_buffer'.
79 static size_t download_pos;
82 * Current URL that we are using.
84 static char *current_url;
87 * Current CURL handle.
92 * Current multi-CURL handle.
97 * ID of the current task scheduled.
99 static GNUNET_SCHEDULER_TaskIdentifier current_task;
102 * Amount of time we wait between hostlist downloads.
104 static struct GNUNET_TIME_Relative hostlist_delay;
107 * Set to GNUNET_YES if the current URL had some problems.
109 static int bogus_url;
112 * Number of active connections (according to core service).
114 static unsigned int connection_count;
117 * Set if the user allows us to learn about new hostlists
123 * At what time MUST the current hostlist request be done?
125 static struct GNUNET_TIME_Absolute end_time;
127 struct GNUNET_Hostlist * dll_head;
128 struct GNUNET_Hostlist * dll_tail;
132 * Process downloaded bits by calling callback on each HELLO.
134 * @param ptr buffer with downloaded data
135 * @param size size of a record
136 * @param nmemb number of records downloaded
138 * @return number of bytes that were processed (always size*nmemb)
141 download_hostlist_processor (void *ptr,
146 const char * cbuf = ptr;
147 const struct GNUNET_MessageHeader *msg;
153 total = size * nmemb;
154 if ( (total == 0) || (bogus_url) )
156 return total; /* ok, no data or bogus data */
158 GNUNET_STATISTICS_update (stats,
159 gettext_noop ("# bytes downloaded from hostlist servers"),
163 while ( (left > 0) ||
166 cpy = GNUNET_MIN (left, GNUNET_SERVER_MAX_MESSAGE_SIZE - download_pos);
167 memcpy (&download_buffer[download_pos],
173 if (download_pos < sizeof(struct GNUNET_MessageHeader))
175 GNUNET_assert (left == 0);
178 msg = (const struct GNUNET_MessageHeader *) download_buffer;
179 msize = ntohs(msg->size);
180 if (msize < sizeof(struct GNUNET_MessageHeader))
182 GNUNET_STATISTICS_update (stats,
183 gettext_noop ("# invalid HELLOs downloaded from hostlist servers"),
186 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
187 _("Invalid `%s' message received from hostlist at `%s'\n"),
193 if (download_pos < msize)
195 GNUNET_assert (left == 0);
198 if (GNUNET_HELLO_size ((const struct GNUNET_HELLO_Message*)msg) == msize)
200 #if DEBUG_HOSTLIST_CLIENT
201 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
202 "Received valid `%s' message from hostlist server.\n",
205 GNUNET_STATISTICS_update (stats,
206 gettext_noop ("# valid HELLOs downloaded from hostlist servers"),
209 GNUNET_TRANSPORT_offer_hello (transport, msg);
213 GNUNET_STATISTICS_update (stats,
214 gettext_noop ("# invalid HELLOs downloaded from hostlist servers"),
217 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
218 _("Invalid `%s' message received from hostlist at `%s'\n"),
221 bogus_url = GNUNET_YES;
224 memmove (download_buffer,
225 &download_buffer[msize],
226 download_pos - msize);
227 download_pos -= msize;
234 * Obtain a hostlist URL that we should use.
236 * @return NULL if there is no URL available
247 GNUNET_CONFIGURATION_get_value_string (cfg,
252 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
253 _("No `%s' specified in `%s' configuration, will not bootstrap.\n"),
254 "SERVERS", "HOSTLIST");
259 if (strlen (servers) > 0)
262 pos = strlen (servers) - 1;
265 if (servers[pos] == ' ')
272 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
273 _("No `%s' specified in `%s' configuration, will not bootstrap.\n"),
274 "SERVERS", "HOSTLIST");
275 GNUNET_free (servers);
279 urls = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, urls) + 1;
280 pos = strlen (servers) - 1;
283 if (servers[pos] == ' ')
295 ret = GNUNET_strdup (&servers[pos]);
296 GNUNET_free (servers);
301 #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);
305 * Schedule the background task that will (possibly)
306 * download a hostlist.
309 schedule_hostlist_task (void);
313 * Clean up the state from the task that downloaded the
314 * hostlist and schedule the next task.
323 mret = curl_multi_remove_handle (multi, curl);
324 if (mret != CURLM_OK)
326 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
327 _("%s failed at %s:%d: `%s'\n"),
328 "curl_multi_remove_handle", __FILE__, __LINE__,
329 curl_multi_strerror (mret));
331 mret = curl_multi_cleanup (multi);
332 if (mret != CURLM_OK)
333 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
334 _("%s failed at %s:%d: `%s'\n"),
335 "curl_multi_cleanup", __FILE__, __LINE__,
336 curl_multi_strerror (mret));
341 curl_easy_cleanup (curl);
344 GNUNET_free_non_null (current_url);
346 schedule_hostlist_task ();
351 * Ask CURL for the select set and then schedule the
352 * receiving task with the scheduler.
359 * Task that is run when we are ready to receive more data from the hostlist
362 * @param cls closure, unused
363 * @param tc task context, unused
366 multi_ready (void *cls,
367 const struct GNUNET_SCHEDULER_TaskContext *tc)
373 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
375 #if DEBUG_HOSTLIST_CLIENT
376 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
377 "Shutdown requested while trying to download hostlist from `%s'\n",
383 if (GNUNET_TIME_absolute_get_remaining (end_time).value == 0)
385 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
386 _("Timeout trying to download hostlist from `%s'\n"),
391 #if DEBUG_HOSTLIST_CLIENT
392 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
393 "Ready for processing hostlist client request\n");
398 mret = curl_multi_perform (multi, &running);
403 msg = curl_multi_info_read (multi, &running);
404 GNUNET_break (msg != NULL);
410 if ( (msg->data.result != CURLE_OK) &&
411 (msg->data.result != CURLE_GOT_NOTHING) )
412 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
413 _("%s failed for `%s' at %s:%d: `%s'\n"),
414 "curl_multi_perform",
418 curl_easy_strerror (msg->data.result));
420 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
421 _("Download of hostlist `%s' completed.\n"),
432 while (mret == CURLM_CALL_MULTI_PERFORM);
433 if (mret != CURLM_OK)
435 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
436 _("%s failed at %s:%d: `%s'\n"),
437 "curl_multi_perform", __FILE__, __LINE__,
438 curl_multi_strerror (mret));
446 * Ask CURL for the select set and then schedule the
447 * receiving task with the scheduler.
457 struct GNUNET_NETWORK_FDSet *grs;
458 struct GNUNET_NETWORK_FDSet *gws;
460 struct GNUNET_TIME_Relative rtime;
466 mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
467 if (mret != CURLM_OK)
469 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
470 _("%s failed at %s:%d: `%s'\n"),
471 "curl_multi_fdset", __FILE__, __LINE__,
472 curl_multi_strerror (mret));
476 mret = curl_multi_timeout (multi, &timeout);
477 if (mret != CURLM_OK)
479 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
480 _("%s failed at %s:%d: `%s'\n"),
481 "curl_multi_timeout", __FILE__, __LINE__,
482 curl_multi_strerror (mret));
486 rtime = GNUNET_TIME_relative_min (GNUNET_TIME_absolute_get_remaining (end_time),
487 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
489 grs = GNUNET_NETWORK_fdset_create ();
490 gws = GNUNET_NETWORK_fdset_create ();
491 GNUNET_NETWORK_fdset_copy_native (grs, &rs, max + 1);
492 GNUNET_NETWORK_fdset_copy_native (gws, &ws, max + 1);
493 #if DEBUG_HOSTLIST_CLIENT
494 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
495 "Scheduling task for hostlist download using cURL\n");
498 = GNUNET_SCHEDULER_add_select (sched,
499 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
500 GNUNET_SCHEDULER_NO_TASK,
506 GNUNET_NETWORK_fdset_destroy (gws);
507 GNUNET_NETWORK_fdset_destroy (grs);
512 * Main function that will download a hostlist and process its
521 curl = curl_easy_init ();
529 current_url = get_url ();
530 GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
531 _("Bootstrapping using hostlist at `%s'.\n"),
533 GNUNET_STATISTICS_update (stats,
534 gettext_noop ("# hostlist downloads initiated"),
538 CURL_EASY_SETOPT (curl, CURLOPT_PROXY, proxy);
541 CURL_EASY_SETOPT (curl,
542 CURLOPT_WRITEFUNCTION,
543 &download_hostlist_processor);
549 CURL_EASY_SETOPT (curl,
557 CURL_EASY_SETOPT (curl, CURLOPT_FOLLOWLOCATION, 1);
558 CURL_EASY_SETOPT (curl, CURLOPT_MAXREDIRS, 4);
559 /* no need to abort if the above failed */
560 CURL_EASY_SETOPT (curl,
568 CURL_EASY_SETOPT (curl,
572 CURL_EASY_SETOPT (curl,
576 CURL_EASY_SETOPT (curl,
578 GNUNET_SERVER_MAX_MESSAGE_SIZE);
579 if (0 == strncmp (current_url, "http", 4))
580 CURL_EASY_SETOPT (curl, CURLOPT_USERAGENT, "GNUnet");
581 CURL_EASY_SETOPT (curl,
582 CURLOPT_CONNECTTIMEOUT,
584 CURL_EASY_SETOPT (curl,
588 /* this should no longer be needed; we're now single-threaded! */
589 CURL_EASY_SETOPT (curl,
593 multi = curl_multi_init ();
600 mret = curl_multi_add_handle (multi, curl);
601 if (mret != CURLM_OK)
603 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
604 _("%s failed at %s:%d: `%s'\n"),
605 "curl_multi_add_handle", __FILE__, __LINE__,
606 curl_multi_strerror (mret));
607 mret = curl_multi_cleanup (multi);
608 if (mret != CURLM_OK)
609 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
610 _("%s failed at %s:%d: `%s'\n"),
611 "curl_multi_cleanup", __FILE__, __LINE__,
612 curl_multi_strerror (mret));
617 end_time = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES);
623 * Task that checks if we should try to download a hostlist.
624 * If so, we initiate the download, otherwise we schedule
625 * this task again for a later time.
628 check_task (void *cls,
629 const struct GNUNET_SCHEDULER_TaskContext *tc)
631 current_task = GNUNET_SCHEDULER_NO_TASK;
632 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
634 if (connection_count < MIN_CONNECTIONS)
635 download_hostlist ();
637 schedule_hostlist_task ();
642 * Compute when we should check the next time about downloading
643 * a hostlist; then schedule the task accordingly.
646 schedule_hostlist_task ()
649 struct GNUNET_TIME_Relative delay;
653 curl_global_cleanup ();
654 return; /* in shutdown */
656 delay = hostlist_delay;
657 if (hostlist_delay.value == 0)
658 hostlist_delay = GNUNET_TIME_UNIT_SECONDS;
660 hostlist_delay = GNUNET_TIME_relative_multiply (hostlist_delay, 2);
661 if (hostlist_delay.value > GNUNET_TIME_UNIT_HOURS.value * (1 + connection_count))
662 hostlist_delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS,
663 (1 + connection_count));
664 GNUNET_STATISTICS_set (stats,
665 gettext_noop("# seconds between hostlist downloads"),
666 hostlist_delay.value,
670 delay = GNUNET_TIME_UNIT_ZERO;
673 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
674 _("Have %u/%u connections. Will consider downloading hostlist in %llums\n"),
677 (unsigned long long) delay.value);
678 current_task = GNUNET_SCHEDULER_add_delayed (sched,
686 * Method called whenever a given peer connects.
689 * @param peer peer identity this notification is about
690 * @param latency reported latency of the connection with 'other'
691 * @param distance reported distance (DV) to 'other'
694 connect_handler (void *cls,
696 GNUNET_PeerIdentity * peer,
697 struct GNUNET_TIME_Relative latency,
701 GNUNET_STATISTICS_update (stats,
702 gettext_noop ("# active connections"),
709 * Method called whenever a given peer disconnects.
712 * @param peer peer identity this notification is about
715 disconnect_handler (void *cls,
717 GNUNET_PeerIdentity * peer)
720 GNUNET_STATISTICS_update (stats,
721 gettext_noop ("# active connections"),
726 static int dll_contains ( char * uri)
728 struct GNUNET_Hostlist * actual = dll_head;
736 if ( 0 == strcmp(actual->hostlist_uri,uri) ) return GNUNET_YES;
737 if (actual == dll_tail) break;
738 actual = actual->next;
744 struct GNUNET_Hostlist * dll_get ( char * uri )
746 struct GNUNET_Hostlist * actual = dll_head;
754 if ( 0 == strcmp(actual->hostlist_uri,uri) ) return actual;
755 if (actual == dll_tail) break;
756 actual = actual->next;
762 struct GNUNET_Hostlist * dll_get_lowest_quality ( )
764 struct GNUNET_Hostlist * actual = dll_head;
765 struct GNUNET_Hostlist * lowest = NULL;
775 if ( actual->quality < lowest->quality) lowest = actual;
776 if (actual == dll_tail) break;
777 actual = actual->next;
783 static int dll_insert ( struct GNUNET_Hostlist * elem)
785 if (dll_size <= MAX_NUMBER_HOSTLISTS)
787 GNUNET_CONTAINER_DLL_insert(dll_head, dll_tail,elem);
791 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
792 "Maximum number of %u for hostlist entries reached, \n", MAX_NUMBER_HOSTLISTS );
793 return GNUNET_SYSERR;
796 static int dll_remove ( struct GNUNET_Hostlist * elem)
798 if ( GNUNET_YES == dll_contains (elem->hostlist_uri))
800 GNUNET_CONTAINER_DLL_remove(dll_head, dll_tail,elem);
804 return GNUNET_SYSERR;
807 void create_dummy_entries ()
811 struct GNUNET_Hostlist * hostlist1;
812 hostlist1 = GNUNET_malloc ( sizeof (struct GNUNET_Hostlist) );
813 char * str = "uri_1";
815 GNUNET_CRYPTO_hash_create_random ( GNUNET_CRYPTO_QUALITY_WEAK , &hostlist1->peer.hashPubKey);
816 hostlist1->hello_count = 0;
817 hostlist1->hostlist_uri = GNUNET_malloc ( strlen(str) +1 );
818 strcpy(hostlist1->hostlist_uri,str);
819 hostlist1->time_creation = GNUNET_TIME_absolute_get();
820 hostlist1->time_last_usage = GNUNET_TIME_absolute_get_zero();
821 hostlist1->quality = HOSTLIST_INITIAL - 100;
822 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
823 "Adding test peer '%s' with URI %s and quality %u to dll \n", GNUNET_h2s (&hostlist1->peer.hashPubKey) , hostlist1->hostlist_uri, hostlist1->quality);
824 dll_insert (hostlist1);
826 struct GNUNET_Hostlist * hostlist2;
827 hostlist2 = GNUNET_malloc ( sizeof (struct GNUNET_Hostlist) );
828 char * str2 = "uri_2";
830 GNUNET_CRYPTO_hash_create_random ( GNUNET_CRYPTO_QUALITY_WEAK , &hostlist2->peer.hashPubKey);
831 hostlist2->hello_count = 0;
832 hostlist2->hostlist_uri = GNUNET_malloc ( strlen(str2) +1 );
833 strcpy(hostlist2->hostlist_uri,str2);
834 hostlist2->time_creation = GNUNET_TIME_absolute_get();
835 hostlist2->time_last_usage = GNUNET_TIME_absolute_get_zero();
836 hostlist2->quality = HOSTLIST_INITIAL - 200;
837 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
838 "Adding test peer '%s' with URI %s and quality %u to dll \n", GNUNET_h2s (&hostlist2->peer.hashPubKey) , hostlist2->hostlist_uri, hostlist2->quality);
839 dll_insert (hostlist2);
841 struct GNUNET_Hostlist * hostlist3;
842 hostlist3 = GNUNET_malloc ( sizeof (struct GNUNET_Hostlist) );
843 char * str3 = "uri_3";
845 GNUNET_CRYPTO_hash_create_random ( GNUNET_CRYPTO_QUALITY_WEAK , &hostlist3->peer.hashPubKey);
846 hostlist3->hello_count = 0;
847 hostlist3->hostlist_uri = GNUNET_malloc ( strlen(str3) +1 );
848 strcpy(hostlist3->hostlist_uri,str3);
849 hostlist3->time_creation = GNUNET_TIME_absolute_get();
850 hostlist3->time_last_usage = GNUNET_TIME_absolute_get_zero();
851 hostlist3->quality = HOSTLIST_INITIAL - 300;
852 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
853 "Adding test peer '%s' with URI %s and quality %u to dll \n", GNUNET_h2s (&hostlist3->peer.hashPubKey) , hostlist3->hostlist_uri, hostlist3->quality);
854 dll_insert (hostlist3);
857 struct GNUNET_Hostlist * hostlist4;
858 hostlist4 = GNUNET_malloc ( sizeof (struct GNUNET_Hostlist) );
859 char * str4 = "uri_4";
861 GNUNET_CRYPTO_hash_create_random ( GNUNET_CRYPTO_QUALITY_WEAK , &hostlist4->peer.hashPubKey);
862 hostlist4->hello_count = 0;
863 hostlist4->hostlist_uri = GNUNET_malloc ( strlen(str4) +1 );
864 strcpy(hostlist4->hostlist_uri,str4);
865 hostlist4->time_creation = GNUNET_TIME_absolute_get();
866 hostlist4->time_last_usage = GNUNET_TIME_absolute_get_zero();
867 hostlist4->quality = HOSTLIST_INITIAL - 400;
868 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
869 "Adding test peer '%s' with URI %s and quality %u to dll \n", GNUNET_h2s (&hostlist4->peer.hashPubKey) , hostlist4->hostlist_uri, hostlist4->quality);
870 dll_insert (hostlist4);
874 * Method called whenever an advertisement message arrives.
876 * @param cls closure (always NULL)
877 * @param client identification of the client
878 * @param message the actual message
879 * @return GNUNET_OK to keep the connection open,
880 * GNUNET_SYSERR to close it (signal serious error)
883 advertisement_handler (void *cls,
884 const struct GNUNET_PeerIdentity * peer,
885 const struct GNUNET_MessageHeader * message,
886 struct GNUNET_TIME_Relative latency,
892 int size = ntohs (message->size);
893 int uri_size = size - sizeof ( struct GNUNET_HOSTLIST_ADV_Message );
894 char * uri = GNUNET_malloc ( uri_size );
895 struct GNUNET_Hostlist * hostlist;
897 if ( ntohs (message->type) != GNUNET_MESSAGE_TYPE_HOSTLIST_ADVERTISEMENT)
900 const struct GNUNET_HOSTLIST_ADV_Message * incoming = (const struct GNUNET_HOSTLIST_ADV_Message *) message;
901 memcpy ( uri, &incoming[1], uri_size );
902 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
903 "Hostlist client recieved advertisement from '%s' containing URI %s\n", GNUNET_i2s (peer), uri );
905 create_dummy_entries();
907 hostlist = GNUNET_malloc ( sizeof (struct GNUNET_Hostlist) );
909 hostlist->peer = (*peer);
910 hostlist->hello_count = 0;
911 hostlist->hostlist_uri = GNUNET_malloc ( uri_size);
912 memcpy ( hostlist->hostlist_uri, &incoming[1], uri_size );
913 hostlist->time_creation = GNUNET_TIME_absolute_get();
914 hostlist->time_last_usage = GNUNET_TIME_absolute_get_zero();
915 hostlist->times_used = 0;
916 hostlist->quality = HOSTLIST_INITIAL;
918 if ( GNUNET_YES != dll_contains (hostlist->hostlist_uri) )
920 if ( MAX_NUMBER_HOSTLISTS > dll_size )
922 /* Entries available, add hostlist to dll */
923 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
924 "Adding uri '%s' to dll\n", hostlist->hostlist_uri );
925 dll_insert ( hostlist );
930 /* No free entries available, replace existing entry */
931 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
932 "No free slots for hostlist available, searching for hostlist to replace\n" );
934 struct GNUNET_Hostlist * lowest_quality = dll_get_lowest_quality();
936 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
937 "Hostlist with URI %s has the worst quality of all with value %u \n", lowest_quality->hostlist_uri, lowest_quality->quality );
938 /* replacing the entry with worst quality, if quality is below initial quality value */
939 if ( lowest_quality->quality < HOSTLIST_INITIAL)
941 dll_remove(lowest_quality);
942 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
943 "URI '%s' removed \n",lowest_quality->hostlist_uri);
944 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
945 "URI '%s' added %s\n", hostlist->hostlist_uri);
946 dll_insert ( hostlist );
953 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
954 "Hostlist URI already in database\n");
957 /* since hostlist already existed in hashmap, object can be destroyed */
958 GNUNET_free ( hostlist->hostlist_uri );
959 GNUNET_free ( hostlist );
965 * Continuation called by the statistics code once
966 * we go the stat. Initiates hostlist download scheduling.
969 * @param success GNUNET_OK if statistics were
970 * successfully obtained, GNUNET_SYSERR if not.
973 primary_task (void *cls, int success)
976 return; /* in shutdown */
977 #if DEBUG_HOSTLIST_CLIENT
978 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
979 "Statistics request done, scheduling hostlist download\n");
981 schedule_hostlist_task ();
986 process_stat (void *cls,
987 const char *subsystem,
992 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
993 _("Initial time between hostlist downloads is %llums\n"),
994 (unsigned long long) value);
995 hostlist_delay.value = value;
1000 * Method to load persistent hostlist file during hostlist client startup
1001 * param c configuration to use
1003 static int load_hostlist_file ()
1008 GNUNET_CONFIGURATION_get_value_string (cfg,
1013 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1014 _("No `%s' specified in `%s' configuration, cannot load hostlists from file.\n"),
1015 "HOSTLISTFILE", "HOSTLIST");
1016 return GNUNET_SYSERR;
1019 struct GNUNET_BIO_ReadHandle * rh = GNUNET_BIO_read_open (filename);
1022 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1023 ("Could not open file %s for reading to load hostlists\n"), filename);
1024 return GNUNET_SYSERR;
1027 /* add code to read hostlists to file using bio */
1028 char * buffer = GNUNET_malloc (100 * sizeof (char));
1029 GNUNET_BIO_read_string (rh, NULL , &buffer, 100);
1030 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1031 ("Read from file %s : %s \n"), filename, buffer);
1033 if ( GNUNET_OK != GNUNET_BIO_read_close ( rh , &buffer) )
1034 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1035 ("Error while closing file %s\n"), filename);
1040 * Method to load persistent hostlist file during hostlist client shutdown
1041 * param c configuration to use
1043 static int save_hostlist_file ()
1048 GNUNET_CONFIGURATION_get_value_string (cfg,
1053 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1054 _("No `%s' specified in `%s' configuration, cannot save hostlists to file.\n"),
1055 "HOSTLISTFILE", "HOSTLIST");
1056 return GNUNET_SYSERR;
1059 struct GNUNET_BIO_WriteHandle * wh = GNUNET_BIO_write_open (filename);
1062 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1063 ("Could not open file %s for writing to save hostlists\n"),
1065 return GNUNET_SYSERR;
1068 /* add code to write hostlists to file using bio */
1070 /* iterate over all entries in dll */
1072 if ( GNUNET_OK != GNUNET_BIO_write_close ( wh ) )
1073 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1074 ("Error while closing file %s\n"),
1080 * Start downloading hostlists from hostlist servers as necessary.
1083 GNUNET_HOSTLIST_client_start (const struct GNUNET_CONFIGURATION_Handle *c,
1084 struct GNUNET_SCHEDULER_Handle *s,
1085 struct GNUNET_STATISTICS_Handle *st,
1086 GNUNET_CORE_ConnectEventHandler *ch,
1087 GNUNET_CORE_DisconnectEventHandler *dh,
1088 GNUNET_CORE_MessageCallback *msgh,
1091 if (0 != curl_global_init (CURL_GLOBAL_WIN32))
1094 return GNUNET_SYSERR;
1096 transport = GNUNET_TRANSPORT_connect (s, c, NULL, NULL, NULL, NULL);
1097 if (NULL == transport)
1099 curl_global_cleanup ();
1100 return GNUNET_SYSERR;
1106 GNUNET_CONFIGURATION_get_value_string (cfg,
1111 *ch = &connect_handler;
1112 *dh = &disconnect_handler;
1113 *msgh = &advertisement_handler;
1118 load_hostlist_file ();
1120 GNUNET_STATISTICS_get (stats,
1122 gettext_noop("# seconds between hostlist downloads"),
1123 GNUNET_TIME_UNIT_MINUTES,
1132 * Stop downloading hostlists from hostlist servers as necessary.
1135 GNUNET_HOSTLIST_client_stop ()
1137 #if DEBUG_HOSTLIST_CLIENT
1138 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1139 "Hostlist client shutdown\n");
1141 save_hostlist_file ();
1143 if (current_task != GNUNET_SCHEDULER_NO_TASK)
1145 GNUNET_SCHEDULER_cancel (sched,
1147 curl_global_cleanup ();
1149 if (transport != NULL)
1151 GNUNET_TRANSPORT_disconnect (transport);
1154 GNUNET_assert (NULL == transport);
1155 GNUNET_free_non_null (proxy);
1161 /* end of hostlist-client.c */