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
54 struct Hostlist * prev;
56 struct Hostlist * next;
59 * URI where hostlist can be obtained
61 const char *hostlist_uri;
64 * Peer offering the hostlist. TO BE REMOVED.
66 struct GNUNET_PeerIdentity peer;
69 * Value describing the quality of the hostlist, the bigger the better but (should) never < 0
70 * used for deciding which hostlist is replaced if MAX_NUMBER_HOSTLISTS in data structure is reached
71 * intial value = HOSTLIST_INITIAL
72 * increased every successful download by HOSTLIST_SUCCESSFULL_DOWNLOAD
73 * increased every successful download by number of obtained HELLO messages
74 * decreased every failed download by HOSTLIST_SUCCESSFULL_DOWNLOAD
79 * Time the hostlist advertisement was recieved and the entry was created
81 struct GNUNET_TIME_Absolute time_creation;
84 * Last time the hostlist was obtained
86 struct GNUNET_TIME_Absolute time_last_usage;
89 * Number of HELLO messages obtained during last download
94 * Number of times the hostlist was obtained
104 static const struct GNUNET_CONFIGURATION_Handle *cfg;
109 static struct GNUNET_SCHEDULER_Handle *sched;
114 struct GNUNET_STATISTICS_Handle *stats;
119 struct GNUNET_TRANSPORT_Handle *transport;
122 * Proxy that we are using (can be NULL).
127 * Buffer for data downloaded via HTTP.
129 static char download_buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE];
132 * Number of bytes valid in 'download_buffer'.
134 static size_t download_pos;
137 * Current URL that we are using.
139 static char *current_url;
142 * Current CURL handle.
147 * Current multi-CURL handle.
152 * ID of the current task scheduled.
154 static GNUNET_SCHEDULER_TaskIdentifier current_task;
157 * Amount of time we wait between hostlist downloads.
159 static struct GNUNET_TIME_Relative hostlist_delay;
162 * Set to GNUNET_YES if the current URL had some problems.
164 static int bogus_url;
167 * Number of active connections (according to core service).
169 static unsigned int connection_count;
172 * At what time MUST the current hostlist request be done?
174 static struct GNUNET_TIME_Absolute end_time;
177 static struct Hostlist * dll_head;
180 static struct Hostlist * dll_tail;
183 static unsigned int dll_size;
186 * Process downloaded bits by calling callback on each HELLO.
188 * @param ptr buffer with downloaded data
189 * @param size size of a record
190 * @param nmemb number of records downloaded
192 * @return number of bytes that were processed (always size*nmemb)
195 download_hostlist_processor (void *ptr,
200 const char * cbuf = ptr;
201 const struct GNUNET_MessageHeader *msg;
207 total = size * nmemb;
208 if ( (total == 0) || (bogus_url) )
210 return total; /* ok, no data or bogus data */
212 GNUNET_STATISTICS_update (stats,
213 gettext_noop ("# bytes downloaded from hostlist servers"),
217 while ( (left > 0) ||
220 cpy = GNUNET_MIN (left, GNUNET_SERVER_MAX_MESSAGE_SIZE - download_pos);
221 memcpy (&download_buffer[download_pos],
227 if (download_pos < sizeof(struct GNUNET_MessageHeader))
229 GNUNET_assert (left == 0);
232 msg = (const struct GNUNET_MessageHeader *) download_buffer;
233 msize = ntohs(msg->size);
234 if (msize < sizeof(struct GNUNET_MessageHeader))
236 GNUNET_STATISTICS_update (stats,
237 gettext_noop ("# invalid HELLOs downloaded from hostlist servers"),
240 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
241 _("Invalid `%s' message received from hostlist at `%s'\n"),
247 if (download_pos < msize)
249 GNUNET_assert (left == 0);
252 if (GNUNET_HELLO_size ((const struct GNUNET_HELLO_Message*)msg) == msize)
254 #if DEBUG_HOSTLIST_CLIENT
255 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
256 "Received valid `%s' message from hostlist server.\n",
259 GNUNET_STATISTICS_update (stats,
260 gettext_noop ("# valid HELLOs downloaded from hostlist servers"),
263 GNUNET_TRANSPORT_offer_hello (transport, msg);
267 GNUNET_STATISTICS_update (stats,
268 gettext_noop ("# invalid HELLOs downloaded from hostlist servers"),
271 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
272 _("Invalid `%s' message received from hostlist at `%s'\n"),
275 bogus_url = GNUNET_YES;
278 memmove (download_buffer,
279 &download_buffer[msize],
280 download_pos - msize);
281 download_pos -= msize;
288 * Obtain a hostlist URL that we should use.
290 * @return NULL if there is no URL available
301 GNUNET_CONFIGURATION_get_value_string (cfg,
306 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
307 _("No `%s' specified in `%s' configuration, will not bootstrap.\n"),
308 "SERVERS", "HOSTLIST");
313 if (strlen (servers) > 0)
316 pos = strlen (servers) - 1;
319 if (servers[pos] == ' ')
326 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
327 _("No `%s' specified in `%s' configuration, will not bootstrap.\n"),
328 "SERVERS", "HOSTLIST");
329 GNUNET_free (servers);
333 urls = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, urls) + 1;
334 pos = strlen (servers) - 1;
337 if (servers[pos] == ' ')
349 ret = GNUNET_strdup (&servers[pos]);
350 GNUNET_free (servers);
355 #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);
359 * Schedule the background task that will (possibly)
360 * download a hostlist.
363 schedule_hostlist_task (void);
367 * Clean up the state from the task that downloaded the
368 * hostlist and schedule the next task.
377 mret = curl_multi_remove_handle (multi, curl);
378 if (mret != CURLM_OK)
380 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
381 _("%s failed at %s:%d: `%s'\n"),
382 "curl_multi_remove_handle", __FILE__, __LINE__,
383 curl_multi_strerror (mret));
385 mret = curl_multi_cleanup (multi);
386 if (mret != CURLM_OK)
387 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
388 _("%s failed at %s:%d: `%s'\n"),
389 "curl_multi_cleanup", __FILE__, __LINE__,
390 curl_multi_strerror (mret));
395 curl_easy_cleanup (curl);
398 GNUNET_free_non_null (current_url);
400 schedule_hostlist_task ();
405 * Ask CURL for the select set and then schedule the
406 * receiving task with the scheduler.
413 * Task that is run when we are ready to receive more data from the hostlist
416 * @param cls closure, unused
417 * @param tc task context, unused
420 multi_ready (void *cls,
421 const struct GNUNET_SCHEDULER_TaskContext *tc)
427 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
429 #if DEBUG_HOSTLIST_CLIENT
430 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
431 "Shutdown requested while trying to download hostlist from `%s'\n",
437 if (GNUNET_TIME_absolute_get_remaining (end_time).value == 0)
439 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
440 _("Timeout trying to download hostlist from `%s'\n"),
445 #if DEBUG_HOSTLIST_CLIENT
446 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
447 "Ready for processing hostlist client request\n");
452 mret = curl_multi_perform (multi, &running);
457 msg = curl_multi_info_read (multi, &running);
458 GNUNET_break (msg != NULL);
464 if ( (msg->data.result != CURLE_OK) &&
465 (msg->data.result != CURLE_GOT_NOTHING) )
466 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
467 _("%s failed for `%s' at %s:%d: `%s'\n"),
468 "curl_multi_perform",
472 curl_easy_strerror (msg->data.result));
474 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
475 _("Download of hostlist `%s' completed.\n"),
486 while (mret == CURLM_CALL_MULTI_PERFORM);
487 if (mret != CURLM_OK)
489 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
490 _("%s failed at %s:%d: `%s'\n"),
491 "curl_multi_perform", __FILE__, __LINE__,
492 curl_multi_strerror (mret));
500 * Ask CURL for the select set and then schedule the
501 * receiving task with the scheduler.
511 struct GNUNET_NETWORK_FDSet *grs;
512 struct GNUNET_NETWORK_FDSet *gws;
514 struct GNUNET_TIME_Relative rtime;
520 mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
521 if (mret != CURLM_OK)
523 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
524 _("%s failed at %s:%d: `%s'\n"),
525 "curl_multi_fdset", __FILE__, __LINE__,
526 curl_multi_strerror (mret));
530 mret = curl_multi_timeout (multi, &timeout);
531 if (mret != CURLM_OK)
533 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
534 _("%s failed at %s:%d: `%s'\n"),
535 "curl_multi_timeout", __FILE__, __LINE__,
536 curl_multi_strerror (mret));
540 rtime = GNUNET_TIME_relative_min (GNUNET_TIME_absolute_get_remaining (end_time),
541 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
543 grs = GNUNET_NETWORK_fdset_create ();
544 gws = GNUNET_NETWORK_fdset_create ();
545 GNUNET_NETWORK_fdset_copy_native (grs, &rs, max + 1);
546 GNUNET_NETWORK_fdset_copy_native (gws, &ws, max + 1);
547 #if DEBUG_HOSTLIST_CLIENT
548 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
549 "Scheduling task for hostlist download using cURL\n");
552 = GNUNET_SCHEDULER_add_select (sched,
553 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
554 GNUNET_SCHEDULER_NO_TASK,
560 GNUNET_NETWORK_fdset_destroy (gws);
561 GNUNET_NETWORK_fdset_destroy (grs);
566 * Main function that will download a hostlist and process its
575 curl = curl_easy_init ();
583 current_url = get_url ();
584 GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
585 _("Bootstrapping using hostlist at `%s'.\n"),
587 GNUNET_STATISTICS_update (stats,
588 gettext_noop ("# hostlist downloads initiated"),
592 CURL_EASY_SETOPT (curl, CURLOPT_PROXY, proxy);
595 CURL_EASY_SETOPT (curl,
596 CURLOPT_WRITEFUNCTION,
597 &download_hostlist_processor);
603 CURL_EASY_SETOPT (curl,
611 CURL_EASY_SETOPT (curl, CURLOPT_FOLLOWLOCATION, 1);
612 CURL_EASY_SETOPT (curl, CURLOPT_MAXREDIRS, 4);
613 /* no need to abort if the above failed */
614 CURL_EASY_SETOPT (curl,
622 CURL_EASY_SETOPT (curl,
626 CURL_EASY_SETOPT (curl,
630 CURL_EASY_SETOPT (curl,
632 GNUNET_SERVER_MAX_MESSAGE_SIZE);
633 if (0 == strncmp (current_url, "http", 4))
634 CURL_EASY_SETOPT (curl, CURLOPT_USERAGENT, "GNUnet");
635 CURL_EASY_SETOPT (curl,
636 CURLOPT_CONNECTTIMEOUT,
638 CURL_EASY_SETOPT (curl,
642 /* this should no longer be needed; we're now single-threaded! */
643 CURL_EASY_SETOPT (curl,
647 multi = curl_multi_init ();
654 mret = curl_multi_add_handle (multi, curl);
655 if (mret != CURLM_OK)
657 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
658 _("%s failed at %s:%d: `%s'\n"),
659 "curl_multi_add_handle", __FILE__, __LINE__,
660 curl_multi_strerror (mret));
661 mret = curl_multi_cleanup (multi);
662 if (mret != CURLM_OK)
663 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
664 _("%s failed at %s:%d: `%s'\n"),
665 "curl_multi_cleanup", __FILE__, __LINE__,
666 curl_multi_strerror (mret));
671 end_time = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES);
677 * Task that checks if we should try to download a hostlist.
678 * If so, we initiate the download, otherwise we schedule
679 * this task again for a later time.
682 check_task (void *cls,
683 const struct GNUNET_SCHEDULER_TaskContext *tc)
685 current_task = GNUNET_SCHEDULER_NO_TASK;
686 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
688 if (connection_count < MIN_CONNECTIONS)
689 download_hostlist ();
691 schedule_hostlist_task ();
696 * Compute when we should check the next time about downloading
697 * a hostlist; then schedule the task accordingly.
700 schedule_hostlist_task ()
703 struct GNUNET_TIME_Relative delay;
707 curl_global_cleanup ();
708 return; /* in shutdown */
710 delay = hostlist_delay;
711 if (hostlist_delay.value == 0)
712 hostlist_delay = GNUNET_TIME_UNIT_SECONDS;
714 hostlist_delay = GNUNET_TIME_relative_multiply (hostlist_delay, 2);
715 if (hostlist_delay.value > GNUNET_TIME_UNIT_HOURS.value * (1 + connection_count))
716 hostlist_delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS,
717 (1 + connection_count));
718 GNUNET_STATISTICS_set (stats,
719 gettext_noop("# seconds between hostlist downloads"),
720 hostlist_delay.value,
724 delay = GNUNET_TIME_UNIT_ZERO;
727 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
728 _("Have %u/%u connections. Will consider downloading hostlist in %llums\n"),
731 (unsigned long long) delay.value);
732 current_task = GNUNET_SCHEDULER_add_delayed (sched,
740 * Method called whenever a given peer connects.
743 * @param peer peer identity this notification is about
744 * @param latency reported latency of the connection with 'other'
745 * @param distance reported distance (DV) to 'other'
748 connect_handler (void *cls,
750 GNUNET_PeerIdentity * peer,
751 struct GNUNET_TIME_Relative latency,
755 GNUNET_STATISTICS_update (stats,
756 gettext_noop ("# active connections"),
763 * Method called whenever a given peer disconnects.
766 * @param peer peer identity this notification is about
769 disconnect_handler (void *cls,
771 GNUNET_PeerIdentity * peer)
774 GNUNET_STATISTICS_update (stats,
775 gettext_noop ("# active connections"),
783 dll_contains (const char * uri)
785 struct Hostlist * pos;
790 if (0 == strcmp(pos->hostlist_uri, uri) )
799 static struct Hostlist *
800 dll_get_lowest_quality ( )
802 struct Hostlist * pos;
803 struct Hostlist * lowest;
808 pos = dll_head->next;
811 if (pos->quality < lowest->quality)
820 /* TO BE REMOVED later */
821 static void dll_insert ( struct Hostlist *hostlist)
823 GNUNET_CONTAINER_DLL_insert(dll_head, dll_tail, hostlist);
827 static void create_dummy_entries ()
831 struct Hostlist * hostlist1;
832 hostlist1 = GNUNET_malloc ( sizeof (struct Hostlist) );
833 char * str = "uri_1";
835 GNUNET_CRYPTO_hash_create_random ( GNUNET_CRYPTO_QUALITY_WEAK , &hostlist1->peer.hashPubKey);
836 hostlist1->hello_count = 0;
837 hostlist1->hostlist_uri = GNUNET_malloc ( strlen(str) +1 );
838 strcpy(hostlist1->hostlist_uri,str);
839 hostlist1->time_creation = GNUNET_TIME_absolute_get();
840 hostlist1->time_last_usage = GNUNET_TIME_absolute_get_zero();
841 hostlist1->quality = HOSTLIST_INITIAL - 100;
842 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
843 "Adding test peer '%s' with URI %s and quality %u to dll \n", GNUNET_h2s (&hostlist1->peer.hashPubKey) , hostlist1->hostlist_uri, hostlist1->quality);
844 dll_insert (hostlist1);
846 struct Hostlist * hostlist2;
847 hostlist2 = GNUNET_malloc ( sizeof (struct Hostlist) );
848 char * str2 = "uri_2";
850 GNUNET_CRYPTO_hash_create_random ( GNUNET_CRYPTO_QUALITY_WEAK , &hostlist2->peer.hashPubKey);
851 hostlist2->hello_count = 0;
852 hostlist2->hostlist_uri = GNUNET_malloc ( strlen(str2) +1 );
853 strcpy(hostlist2->hostlist_uri,str2);
854 hostlist2->time_creation = GNUNET_TIME_absolute_get();
855 hostlist2->time_last_usage = GNUNET_TIME_absolute_get_zero();
856 hostlist2->quality = HOSTLIST_INITIAL - 200;
857 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
858 "Adding test peer '%s' with URI %s and quality %u to dll \n", GNUNET_h2s (&hostlist2->peer.hashPubKey) , hostlist2->hostlist_uri, hostlist2->quality);
859 dll_insert (hostlist2);
861 struct Hostlist * hostlist3;
862 hostlist3 = GNUNET_malloc ( sizeof (struct Hostlist) );
863 char * str3 = "uri_3";
865 GNUNET_CRYPTO_hash_create_random ( GNUNET_CRYPTO_QUALITY_WEAK , &hostlist3->peer.hashPubKey);
866 hostlist3->hello_count = 0;
867 hostlist3->hostlist_uri = GNUNET_malloc ( strlen(str3) +1 );
868 strcpy(hostlist3->hostlist_uri,str3);
869 hostlist3->time_creation = GNUNET_TIME_absolute_get();
870 hostlist3->time_last_usage = GNUNET_TIME_absolute_get_zero();
871 hostlist3->quality = HOSTLIST_INITIAL - 300;
872 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
873 "Adding test peer '%s' with URI %s and quality %u to dll \n", GNUNET_h2s (&hostlist3->peer.hashPubKey) , hostlist3->hostlist_uri, hostlist3->quality);
874 dll_insert (hostlist3);
877 struct Hostlist * hostlist4;
878 hostlist4 = GNUNET_malloc ( sizeof (struct Hostlist) );
879 char * str4 = "uri_4";
881 GNUNET_CRYPTO_hash_create_random ( GNUNET_CRYPTO_QUALITY_WEAK , &hostlist4->peer.hashPubKey);
882 hostlist4->hello_count = 0;
883 hostlist4->hostlist_uri = GNUNET_malloc ( strlen(str4) +1 );
884 strcpy(hostlist4->hostlist_uri,str4);
885 hostlist4->time_creation = GNUNET_TIME_absolute_get();
886 hostlist4->time_last_usage = GNUNET_TIME_absolute_get_zero();
887 hostlist4->quality = HOSTLIST_INITIAL - 400;
888 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
889 "Adding test peer '%s' with URI %s and quality %u to dll \n", GNUNET_h2s (&hostlist4->peer.hashPubKey) , hostlist4->hostlist_uri, hostlist4->quality);
890 dll_insert (hostlist4);
895 * Method called whenever an advertisement message arrives.
897 * @param cls closure (always NULL)
898 * @param client identification of the client
899 * @param message the actual message
900 * @return GNUNET_OK to keep the connection open,
901 * GNUNET_SYSERR to close it (signal serious error)
904 advertisement_handler (void *cls,
905 const struct GNUNET_PeerIdentity * peer,
906 const struct GNUNET_MessageHeader * message,
907 struct GNUNET_TIME_Relative latency,
912 const struct GNUNET_MessageHeader * incoming;
914 struct Hostlist * hostlist;
916 GNUNET_assert (ntohs (message->type) == GNUNET_MESSAGE_TYPE_HOSTLIST_ADVERTISEMENT);
917 size = ntohs (message->size);
918 if (size <= sizeof(struct GNUNET_MessageHeader))
921 return GNUNET_SYSERR;
923 incoming = (const struct GNUNET_MessageHeader *) message;
924 uri = (const char*) &incoming[1];
925 uri_size = size - sizeof (struct GNUNET_MessageHeader);
926 if (uri [uri_size - 1] != '\0')
929 return GNUNET_SYSERR;
931 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
932 "Hostlist client recieved advertisement from `%s' containing URI `%s'\n",
935 if (GNUNET_YES != dll_contains (uri))
937 hostlist = GNUNET_malloc (sizeof (struct Hostlist) + uri_size);
938 hostlist->peer = *peer;
939 hostlist->hostlist_uri = (const char*) &hostlist[1];
940 memcpy (&hostlist[1], uri, uri_size);
941 hostlist->time_creation = GNUNET_TIME_absolute_get();
942 hostlist->time_last_usage = GNUNET_TIME_absolute_get_zero();
943 hostlist->quality = HOSTLIST_INITIAL;
945 create_dummy_entries(); /* FIXME: remove later... */
947 GNUNET_CONTAINER_DLL_insert(dll_head, dll_tail, hostlist);
950 if (MAX_NUMBER_HOSTLISTS >= dll_size)
953 /* No free entries available, replace existing entry */
954 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
955 "Removing lowest quality entry\n" );
956 struct Hostlist * lowest_quality = dll_get_lowest_quality();
957 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
958 "Hostlist with URI `%s' has the worst quality of all with value %llu\n",
959 lowest_quality->hostlist_uri,
960 (unsigned long long) lowest_quality->quality);
961 GNUNET_CONTAINER_DLL_remove (dll_head, dll_tail, lowest_quality);
963 GNUNET_free (lowest_quality);
969 * Continuation called by the statistics code once
970 * we go the stat. Initiates hostlist download scheduling.
973 * @param success GNUNET_OK if statistics were
974 * successfully obtained, GNUNET_SYSERR if not.
977 primary_task (void *cls, int success)
980 return; /* in shutdown */
981 #if DEBUG_HOSTLIST_CLIENT
982 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
983 "Statistics request done, scheduling hostlist download\n");
985 schedule_hostlist_task ();
990 process_stat (void *cls,
991 const char *subsystem,
996 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
997 _("Initial time between hostlist downloads is %llums\n"),
998 (unsigned long long) value);
999 hostlist_delay.value = value;
1004 * Method to load persistent hostlist file during hostlist client startup
1007 load_hostlist_file ()
1012 struct Hostlist * hostlist;
1015 GNUNET_CONFIGURATION_get_value_string (cfg,
1020 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1021 _("No `%s' specified in `%s' configuration, cannot load hostlists from file.\n"),
1022 "HOSTLISTFILE", "HOSTLIST");
1026 struct GNUNET_BIO_ReadHandle * rh = GNUNET_BIO_read_open (filename);
1029 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1030 _("Could not open file `%s' for reading to load hostlists: %s\n"),
1033 GNUNET_free (filename);
1037 /* add code to read hostlists to file using bio */
1039 uint32_t times_used;
1040 uint32_t hellos_returned;
1045 while ( (GNUNET_OK == GNUNET_BIO_read_string (rh, "url" , &uri, MAX_URL_LEN)) &&
1046 (GNUNET_OK == GNUNET_BIO_read_int32 (rh, ×_used)) &&
1047 (GNUNET_OK == GNUNET_BIO_read_int64 (rh, &quality)) &&
1048 (GNUNET_OK == GNUNET_BIO_read_int64 (rh, &last_used)) &&
1049 (GNUNET_OK == GNUNET_BIO_read_int64 (rh, &created)) &&
1050 (GNUNET_OK == GNUNET_BIO_read_int32 (rh, &hellos_returned)) )
1052 hostlist = GNUNET_malloc ( sizeof (struct Hostlist));
1053 hostlist->hello_count = hellos_returned;
1054 strcpy(hostlist->hostlist_uri, uri);
1055 hostlist->quality = quality;
1056 hostlist->time_creation.value = created;
1057 hostlist->time_last_usage.value = last_used;
1058 GNUNET_CONTAINER_DLL_insert(dll_head, dll_tail, hostlist);
1060 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1061 "Added hostlist entry eith URI `%s' \n", hostlist->hostlist_uri);
1064 GNUNET_free_non_null (uri);
1066 GNUNET_BIO_read_close (rh, &emsg);
1069 GNUNET_free (filename);
1074 * Method to load persistent hostlist file during hostlist client shutdown
1076 static void save_hostlist_file ()
1079 struct Hostlist *pos;
1080 struct GNUNET_BIO_WriteHandle * wh;
1084 GNUNET_CONFIGURATION_get_value_string (cfg,
1089 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1090 _("No `%s' specified in `%s' configuration, cannot save hostlists to file.\n"),
1091 "HOSTLISTFILE", "HOSTLIST");
1094 wh = GNUNET_BIO_write_open (filename);
1097 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1098 _("Could not open file `%s' for writing to save hostlists: %s\n"),
1103 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1104 _("Writing hostlist URIs to `%s'\n"),
1107 /* add code to write hostlists to file using bio */
1109 while (NULL != (pos = dll_head))
1111 GNUNET_CONTAINER_DLL_remove (dll_head, dll_tail, pos);
1113 if (GNUNET_YES == ok)
1116 GNUNET_BIO_write_string (wh, pos->hostlist_uri)) ||
1118 GNUNET_BIO_write_int32 (wh, pos->times_used)) ||
1120 GNUNET_BIO_write_int64 (wh, pos->quality)) ||
1122 GNUNET_BIO_write_int64 (wh, pos->time_last_usage.value)) ||
1124 GNUNET_BIO_write_int64 (wh, pos->time_creation.value)) ||
1126 GNUNET_BIO_write_int32 (wh, pos->hello_count)))
1128 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1129 _("Error writing hostlist URIs to file `%s'\n"),
1136 if ( GNUNET_OK != GNUNET_BIO_write_close ( wh ) )
1137 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1138 _("Error writing hostlist URIs to file `%s'\n"),
1140 GNUNET_free (filename);
1144 * Start downloading hostlists from hostlist servers as necessary.
1147 GNUNET_HOSTLIST_client_start (const struct GNUNET_CONFIGURATION_Handle *c,
1148 struct GNUNET_SCHEDULER_Handle *s,
1149 struct GNUNET_STATISTICS_Handle *st,
1150 GNUNET_CORE_ConnectEventHandler *ch,
1151 GNUNET_CORE_DisconnectEventHandler *dh,
1152 GNUNET_CORE_MessageCallback *msgh,
1155 if (0 != curl_global_init (CURL_GLOBAL_WIN32))
1158 return GNUNET_SYSERR;
1160 transport = GNUNET_TRANSPORT_connect (s, c, NULL, NULL, NULL, NULL);
1161 if (NULL == transport)
1163 curl_global_cleanup ();
1164 return GNUNET_SYSERR;
1170 GNUNET_CONFIGURATION_get_value_string (cfg,
1175 *ch = &connect_handler;
1176 *dh = &disconnect_handler;
1178 *msgh = &advertisement_handler;
1183 load_hostlist_file ();
1185 GNUNET_STATISTICS_get (stats,
1187 gettext_noop("# seconds between hostlist downloads"),
1188 GNUNET_TIME_UNIT_MINUTES,
1197 * Stop downloading hostlists from hostlist servers as necessary.
1200 GNUNET_HOSTLIST_client_stop ()
1202 #if DEBUG_HOSTLIST_CLIENT
1203 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1204 "Hostlist client shutdown\n");
1206 save_hostlist_file ();
1208 if (current_task != GNUNET_SCHEDULER_NO_TASK)
1210 GNUNET_SCHEDULER_cancel (sched,
1212 curl_global_cleanup ();
1214 if (transport != NULL)
1216 GNUNET_TRANSPORT_disconnect (transport);
1219 GNUNET_assert (NULL == transport);
1220 GNUNET_free_non_null (proxy);
1226 /* end of hostlist-client.c */