From af4dff0ff8a129c05c75180446b691a0b2cd74c7 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Tue, 3 Jun 2014 08:41:00 +0000 Subject: -doxygen, code cleanup --- src/hostlist/Makefile.am | 5 +- src/hostlist/gnunet-daemon-hostlist.c | 48 +- src/hostlist/gnunet-daemon-hostlist.h | 14 +- src/hostlist/gnunet-daemon-hostlist_client.c | 1710 ++++++++++++++++++++ src/hostlist/gnunet-daemon-hostlist_client.h | 61 + src/hostlist/gnunet-daemon-hostlist_server.c | 888 ++++++++++ src/hostlist/gnunet-daemon-hostlist_server.h | 63 + src/hostlist/hostlist-client.c | 1654 ------------------- src/hostlist/hostlist-client.h | 108 -- src/hostlist/hostlist-server.c | 802 --------- src/hostlist/hostlist-server.h | 58 - .../test_gnunet_daemon_hostlist_learning.c | 6 +- 12 files changed, 2765 insertions(+), 2652 deletions(-) create mode 100644 src/hostlist/gnunet-daemon-hostlist_client.c create mode 100644 src/hostlist/gnunet-daemon-hostlist_client.h create mode 100644 src/hostlist/gnunet-daemon-hostlist_server.c create mode 100644 src/hostlist/gnunet-daemon-hostlist_server.h delete mode 100644 src/hostlist/hostlist-client.c delete mode 100644 src/hostlist/hostlist-client.h delete mode 100644 src/hostlist/hostlist-server.c delete mode 100644 src/hostlist/hostlist-server.h (limited to 'src') diff --git a/src/hostlist/Makefile.am b/src/hostlist/Makefile.am index e647169c0..d777cd658 100644 --- a/src/hostlist/Makefile.am +++ b/src/hostlist/Makefile.am @@ -12,7 +12,8 @@ if USE_COVERAGE endif if HAVE_MHD - HOSTLIST_SERVER_SOURCES = hostlist-server.c hostlist-server.h + HOSTLIST_SERVER_SOURCES = \ + gnunet-daemon-hostlist_server.c gnunet-daemon-hostlist_server.h GN_LIBMHD = -lmicrohttpd endif @@ -23,7 +24,7 @@ endif gnunet_daemon_hostlist_SOURCES = \ gnunet-daemon-hostlist.c gnunet-daemon-hostlist.h \ - hostlist-client.c hostlist-client.h \ + gnunet-daemon-hostlist_client.c gnunet-daemon-hostlist_client.h \ $(HOSTLIST_SERVER_SOURCES) gnunet_daemon_hostlist_LDADD = \ diff --git a/src/hostlist/gnunet-daemon-hostlist.c b/src/hostlist/gnunet-daemon-hostlist.c index a93d7e37d..62ecc5dfd 100644 --- a/src/hostlist/gnunet-daemon-hostlist.c +++ b/src/hostlist/gnunet-daemon-hostlist.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - (C) 2007, 2008, 2009 Christian Grothoff (and other contributing authors) + (C) 2007, 2008, 2009, 2014 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published @@ -23,10 +23,8 @@ * @brief code for bootstrapping via hostlist servers * @author Christian Grothoff */ - -#include #include "platform.h" -#include "hostlist-client.h" +#include "gnunet-daemon-hostlist_client.h" #include "gnunet_core_service.h" #include "gnunet_util_lib.h" #include "gnunet_protocols.h" @@ -34,7 +32,7 @@ #if HAVE_MHD -#include "hostlist-server.h" +#include "gnunet-daemon-hostlist_server.h" /** * Set if we are allowed to advertise our hostlist to others. @@ -123,9 +121,19 @@ struct GNUNET_HOSTLIST_ADV_Message }; GNUNET_NETWORK_STRUCT_END + +/** + * Our own peer identity. + */ static struct GNUNET_PeerIdentity me; +/** + * Callback invoked once our connection to CORE service is up. + * + * @param cls NULL + * @param my_identity our peer's identity + */ static void core_init (void *cls, const struct GNUNET_PeerIdentity *my_identity) @@ -143,7 +151,8 @@ core_init (void *cls, * @return #GNUNET_OK on success */ static int -advertisement_handler (void *cls, const struct GNUNET_PeerIdentity *peer, +advertisement_handler (void *cls, + const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message) { GNUNET_assert (NULL != client_adv_handler); @@ -182,7 +191,8 @@ connect_handler (void *cls, const struct GNUNET_PeerIdentity *peer) * @param peer peer identity this notification is about */ static void -disconnect_handler (void *cls, const struct GNUNET_PeerIdentity *peer) +disconnect_handler (void *cls, + const struct GNUNET_PeerIdentity *peer) { if (0 == memcmp (&me, peer, sizeof (struct GNUNET_PeerIdentity))) return; @@ -200,13 +210,17 @@ disconnect_handler (void *cls, const struct GNUNET_PeerIdentity *peer) /** * Last task run during shutdown. Disconnects us from * the other services. + * + * @param cls NULL + * @param tc scheduler context */ static void -cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +cleaning_task (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hostlist daemon is shutting down\n"); - if (core != NULL) + if (NULL != core) { GNUNET_CORE_disconnect (core); core = NULL; @@ -221,7 +235,7 @@ cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) GNUNET_HOSTLIST_server_stop (); } #endif - if (stats != NULL) + if (NULL != stats) { GNUNET_STATISTICS_destroy (stats, GNUNET_NO); stats = NULL; @@ -238,7 +252,9 @@ cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) * @param cfg configuration */ static void -run (void *cls, char *const *args, const char *cfgfile, +run (void *cls, + char *const *args, + const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { static const struct GNUNET_CORE_MessageHandler learn_handlers[] = { @@ -248,15 +264,14 @@ run (void *cls, char *const *args, const char *cfgfile, static const struct GNUNET_CORE_MessageHandler no_learn_handlers[] = { {NULL, 0, 0} }; - if ((!bootstrapping) && (!learning) + if ((! bootstrapping) && (! learning) #if HAVE_MHD - && (!provide_hostlist) + && (! provide_hostlist) #endif ) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _ - ("None of the functions for the hostlist daemon were enabled. I have no reason to run!\n")); + _("None of the functions for the hostlist daemon were enabled. I have no reason to run!\n")); return; } stats = GNUNET_STATISTICS_create ("hostlist", cfg); @@ -332,7 +347,8 @@ main (int argc, char *const *argv) ret = (GNUNET_OK == GNUNET_PROGRAM_run (argc, argv, "hostlist", - _("GNUnet hostlist server and client"), options, + _("GNUnet hostlist server and client"), + options, &run, NULL)) ? 0 : 1; GNUNET_free ((void*) argv); return ret; diff --git a/src/hostlist/gnunet-daemon-hostlist.h b/src/hostlist/gnunet-daemon-hostlist.h index 8c9824e0c..ca9895dad 100644 --- a/src/hostlist/gnunet-daemon-hostlist.h +++ b/src/hostlist/gnunet-daemon-hostlist.h @@ -25,23 +25,19 @@ */ #include #include "platform.h" -#include "hostlist-client.h" -#include "hostlist-server.h" #include "gnunet_core_service.h" -#include "gnunet_getopt_lib.h" #include "gnunet_protocols.h" -#include "gnunet_program_lib.h" #include "gnunet_statistics_service.h" -#include "gnunet_strings_lib.h" -#include "gnunet_time_lib.h" #include "gnunet_util_lib.h" /** - * General hostlist daemon debugging. + * How long can hostlist URLs be? */ -#define DEBUG_HOSTLIST GNUNET_EXTRA_LOGGING - #define MAX_URL_LEN 1000 + +/** + * How many bytes do we download at most from a hostlist server? + */ #define MAX_BYTES_PER_HOSTLISTS 500000 /* end of gnunet-daemon-hostlist.h */ diff --git a/src/hostlist/gnunet-daemon-hostlist_client.c b/src/hostlist/gnunet-daemon-hostlist_client.c new file mode 100644 index 000000000..20bd8bedd --- /dev/null +++ b/src/hostlist/gnunet-daemon-hostlist_client.c @@ -0,0 +1,1710 @@ +/* + This file is part of GNUnet. + (C) 2001-2010, 2014 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file hostlist/gnunet-daemon-hostlist_client.c + * @brief hostlist support. Downloads HELLOs via HTTP. + * @author Christian Grothoff + * @author Matthias Wachs + */ +#include "platform.h" +#include "gnunet-daemon-hostlist_client.h" +#include "gnunet_hello_lib.h" +#include "gnunet_statistics_service.h" +#include "gnunet_transport_service.h" +#include "gnunet-daemon-hostlist.h" +#include + + +/** + * Number of connections that we must have to NOT download + * hostlists anymore. + */ +#define MIN_CONNECTIONS 4 + +/** + * Maximum number of hostlist that are saved + */ +#define MAX_NUMBER_HOSTLISTS 30 + +/** + * Time interval hostlists are saved to disk + */ +#define SAVING_INTERVAL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30) + +/** + * Time interval between two hostlist tests + */ +#define TESTING_INTERVAL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3) + +/** + * Time interval for download dispatcher before a download is re-scheduled + */ +#define WAITING_INTERVAL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1) + +/** + * Defines concerning the hostlist quality metric + */ + +/** + * Initial quality of a new created hostlist + */ +#define HOSTLIST_INITIAL 10000 + +/** + * Value subtracted each time a hostlist download fails + */ +#define HOSTLIST_FAILED_DOWNLOAD 100 + +/** + * Value added each time a hostlist download is successful + */ +#define HOSTLIST_SUCCESSFUL_DOWNLOAD 100 + +/** + * Value added for each valid HELLO recived during a hostlist download + */ +#define HOSTLIST_SUCCESSFUL_HELLO 1 + + + +/** + * A single hostlist obtained by hostlist advertisements + */ +struct Hostlist +{ + /** + * previous entry, used to manage entries in a double linked list + */ + struct Hostlist *prev; + + /** + * next entry, used to manage entries in a double linked list + */ + struct Hostlist *next; + + /** + * URI where hostlist can be obtained + */ + const char *hostlist_uri; + + /** + * Value describing the quality of the hostlist, the bigger the better but (should) never < 0 + * used for deciding which hostlist is replaced if MAX_NUMBER_HOSTLISTS in data structure is reached + * intial value = HOSTLIST_INITIAL + * increased every successful download by HOSTLIST_SUCCESSFULL_DOWNLOAD + * increased every successful download by number of obtained HELLO messages + * decreased every failed download by HOSTLIST_SUCCESSFULL_DOWNLOAD + */ + uint64_t quality; + + /** + * Time the hostlist advertisement was recieved and the entry was created + */ + struct GNUNET_TIME_Absolute time_creation; + + /** + * Last time the hostlist was obtained + */ + struct GNUNET_TIME_Absolute time_last_usage; + + /** + * Number of HELLO messages obtained during last download + */ + uint32_t hello_count; + + /** + * Number of times the hostlist was successfully obtained + */ + uint32_t times_used; + +}; + + +/** + * Our configuration. + */ +static const struct GNUNET_CONFIGURATION_Handle *cfg; + +/** + * Statistics handle. + */ +static struct GNUNET_STATISTICS_Handle *stats; + +/** + * Transport handle. + */ +static struct GNUNET_TRANSPORT_Handle *transport; + +/** + * Proxy hostname or ip we are using (can be NULL). + */ +static char *proxy; + +/** + * Proxy username we are using (can be NULL). + */ +static char *proxy_username; + +/** + * Proxy password we are using (can be NULL). + */ +static char *proxy_password; + +/** + * Proxy type we are using (can be NULL). + */ +static curl_proxytype proxy_type; + +/** + * Number of bytes valid in 'download_buffer'. + */ +static size_t download_pos; + +/** + * Current URL that we are using. + */ +static char *current_url; + +/** + * Current CURL handle. + */ +static CURL *curl; + +/** + * Current multi-CURL handle. + */ +static CURLM *multi; + +/** + * How many bytes did we download from the current hostlist URL? + */ +static uint32_t stat_bytes_downloaded; + +/** + * Amount of time we wait between hostlist downloads. + */ +static struct GNUNET_TIME_Relative hostlist_delay; + +/** + * ID of the task, checking if hostlist download should take plate + */ +static GNUNET_SCHEDULER_TaskIdentifier ti_check_download; + +/** + * ID of the task downloading the hostlist + */ +static GNUNET_SCHEDULER_TaskIdentifier ti_download; + +/** + * ID of the task saving the hostlsit in a regular intervall + */ +static GNUNET_SCHEDULER_TaskIdentifier ti_saving_task; + +/** + * ID of the task called to initiate a download + */ +static GNUNET_SCHEDULER_TaskIdentifier ti_download_dispatcher_task; + +/** + * ID of the task controlling the locking between two hostlist tests + */ +static GNUNET_SCHEDULER_TaskIdentifier ti_testing_intervall_task; + +/** + * At what time MUST the current hostlist request be done? + */ +static struct GNUNET_TIME_Absolute end_time; + +/** + * Head of the linked list used to store hostlists + */ +static struct Hostlist *linked_list_head; + +/** + * Tail of the linked list used to store hostlists + */ +static struct Hostlist *linked_list_tail; + +/** + * Current hostlist used for downloading + */ +static struct Hostlist *current_hostlist; + +/** + * Size of the linke list used to store hostlists + */ +static unsigned int linked_list_size; + +/** + * Head of the linked list used to store hostlists + */ +static struct Hostlist *hostlist_to_test; + +/** + * Handle for our statistics GET operation. + */ +static struct GNUNET_STATISTICS_GetHandle *sget; + +/** + * Set to GNUNET_YES if the current URL had some problems. + */ +static int stat_bogus_url; + +/** + * Value controlling if a hostlist is tested at the moment + */ +static int stat_testing_hostlist; + +/** + * Value controlling if a hostlist testing is allowed at the moment + */ +static int stat_testing_allowed; + +/** + * Value controlling if a hostlist download is running at the moment + */ +static int stat_download_in_progress; + +/** + * Value saying if a preconfigured bootstrap server is used + */ +static unsigned int stat_use_bootstrap; + +/** + * Set if we are allowed to learn new hostlists and use them + */ +static int stat_learning; + +/** + * Value saying if hostlist download was successful + */ +static unsigned int stat_download_successful; + +/** + * Value saying how many valid HELLO messages were obtained during download + */ +static unsigned int stat_hellos_obtained; + +/** + * Number of active connections (according to core service). + */ +static unsigned int stat_connection_count; + + +/** + * Process downloaded bits by calling callback on each HELLO. + * + * @param ptr buffer with downloaded data + * @param size size of a record + * @param nmemb number of records downloaded + * @param ctx unused + * @return number of bytes that were processed (always size*nmemb) + */ +static size_t +callback_download (void *ptr, + size_t size, + size_t nmemb, + void *ctx) +{ + static char download_buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1]; + const char *cbuf = ptr; + const struct GNUNET_MessageHeader *msg; + size_t total; + size_t cpy; + size_t left; + uint16_t msize; + + total = size * nmemb; + stat_bytes_downloaded += total; + if ((total == 0) || (stat_bogus_url)) + { + return total; /* ok, no data or bogus data */ + } + + GNUNET_STATISTICS_update (stats, + gettext_noop + ("# bytes downloaded from hostlist servers"), + (int64_t) total, GNUNET_NO); + left = total; + while ((left > 0) || (download_pos > 0)) + { + cpy = GNUNET_MIN (left, GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - download_pos); + memcpy (&download_buffer[download_pos], cbuf, cpy); + cbuf += cpy; + download_pos += cpy; + left -= cpy; + if (download_pos < sizeof (struct GNUNET_MessageHeader)) + { + GNUNET_assert (0 == left); + break; + } + msg = (const struct GNUNET_MessageHeader *) download_buffer; + msize = ntohs (msg->size); + if (msize < sizeof (struct GNUNET_MessageHeader)) + { + GNUNET_STATISTICS_update (stats, + gettext_noop + ("# invalid HELLOs downloaded from hostlist servers"), + 1, GNUNET_NO); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Invalid `%s' message received from hostlist at `%s'\n"), + "HELLO", current_url); + stat_hellos_obtained++; + stat_bogus_url = 1; + return total; + } + if (download_pos < msize) + { + GNUNET_assert (left == 0); + break; + } + if (GNUNET_HELLO_size ((const struct GNUNET_HELLO_Message *) msg) == msize) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received valid `%s' message from hostlist server.\n", + "HELLO"); + GNUNET_STATISTICS_update (stats, + gettext_noop + ("# valid HELLOs downloaded from hostlist servers"), + 1, GNUNET_NO); + stat_hellos_obtained++; + GNUNET_TRANSPORT_offer_hello (transport, msg, NULL, NULL); + } + else + { + GNUNET_STATISTICS_update (stats, + gettext_noop + ("# invalid HELLOs downloaded from hostlist servers"), + 1, GNUNET_NO); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Invalid `%s' message received from hostlist at `%s'\n"), + "HELLO", current_url); + stat_bogus_url = GNUNET_YES; + stat_hellos_obtained++; + return total; + } + memmove (download_buffer, &download_buffer[msize], download_pos - msize); + download_pos -= msize; + } + return total; +} + + +/** + * Obtain a hostlist URL that we should use. + * + * @return NULL if there is no URL available + */ +static char * +get_bootstrap_server () +{ + char *servers; + char *ret; + size_t urls; + size_t pos; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, "HOSTLIST", "SERVERS", + &servers)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, + "hostlist", "SERVERS"); + return NULL; + } + + urls = 0; + if (strlen (servers) > 0) + { + urls++; + pos = strlen (servers) - 1; + while (pos > 0) + { + if (servers[pos] == ' ') + urls++; + pos--; + } + } + if (urls == 0) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, + "hostlist", "SERVERS"); + GNUNET_free (servers); + return NULL; + } + + urls = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, urls) + 1; + pos = strlen (servers) - 1; + while (pos > 0) + { + if (servers[pos] == ' ') + { + urls--; + servers[pos] = '\0'; + } + if (urls == 0) + { + pos++; + break; + } + pos--; + } + ret = GNUNET_strdup (&servers[pos]); + GNUNET_free (servers); + return ret; +} + + +/** + * Method deciding if a preconfigured or advertisied hostlist is used on a 50:50 ratio + * @return uri to use, NULL if there is no URL available + */ +static char * +download_get_url () +{ + uint32_t index; + unsigned int counter; + struct Hostlist *pos; + + if (GNUNET_NO == stat_learning) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Using preconfigured bootstrap server\n"); + current_hostlist = NULL; + return get_bootstrap_server (); + } + + if ((GNUNET_YES == stat_testing_hostlist) && (NULL != hostlist_to_test)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Testing new advertised hostlist if it is obtainable\n"); + current_hostlist = hostlist_to_test; + return GNUNET_strdup (hostlist_to_test->hostlist_uri); + } + + if ((GNUNET_YES == stat_use_bootstrap) || (linked_list_size == 0)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Using preconfigured bootstrap server\n"); + current_hostlist = NULL; + return get_bootstrap_server (); + } + index = + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, linked_list_size); + counter = 0; + pos = linked_list_head; + while (counter < index) + { + pos = pos->next; + counter++; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Using learned hostlist `%s'\n", + pos->hostlist_uri); + current_hostlist = pos; + return GNUNET_strdup (pos->hostlist_uri); +} + + +#define CURL_EASY_SETOPT(c, a, b) do { ret = curl_easy_setopt (c, a, b); if (CURLE_OK != ret) GNUNET_log(GNUNET_ERROR_TYPE_WARNING, _("%s failed at %s:%d: `%s'\n"), "curl_easy_setopt", __FILE__, __LINE__, curl_easy_strerror (ret)); } while (0) + + +/** + * Method to save hostlist to a file during hostlist client shutdown + * + * @param shutdown set if called because of shutdown, entries in linked list will be destroyed + */ +static void +save_hostlist_file (int shutdown); + + +/** + * Add val2 to val1 with overflow check + * + * @param val1 value 1 + * @param val2 value 2 + * @return result + */ +static uint64_t +checked_add (uint64_t val1, + uint64_t val2) +{ + static uint64_t temp; + static uint64_t maxv; + + maxv = 0; + maxv--; + + temp = val1 + val2; + if (temp < val1) + return maxv; + return temp; +} + + +/** + * Subtract val2 from val1 with underflow check + * + * @param val1 value 1 + * @param val2 value 2 + * @return result + */ +static uint64_t +checked_sub (uint64_t val1, + uint64_t val2) +{ + if (val1 <= val2) + return 0; + return (val1 - val2); +} + + +/** + * Method to check if a URI is in hostlist linked list + * + * @param uri uri to check + * @return #GNUNET_YES if existing in linked list, #GNUNET_NO if not + */ +static int +linked_list_contains (const char *uri) +{ + struct Hostlist *pos; + + pos = linked_list_head; + while (pos != NULL) + { + if (0 == strcmp (pos->hostlist_uri, uri)) + return GNUNET_YES; + pos = pos->next; + } + return GNUNET_NO; +} + + +/** + * Method returning the hostlist element with the lowest quality in the datastore + * @return hostlist with lowest quality + */ +static struct Hostlist * +linked_list_get_lowest_quality () +{ + struct Hostlist *pos; + struct Hostlist *lowest; + + if (linked_list_size == 0) + return NULL; + lowest = linked_list_head; + pos = linked_list_head->next; + while (pos != NULL) + { + if (pos->quality < lowest->quality) + lowest = pos; + pos = pos->next; + } + return lowest; +} + + +/** + * Method to insert a hostlist into the datastore. If datastore + * contains maximum number of elements, the elements with lowest + * quality is dismissed + */ +static void +insert_hostlist () +{ + struct Hostlist *lowest_quality; + + if (MAX_NUMBER_HOSTLISTS <= linked_list_size) + { + /* No free entries available, replace existing entry */ + lowest_quality = linked_list_get_lowest_quality (); + GNUNET_assert (lowest_quality != NULL); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Removing hostlist with URI `%s' which has the worst quality of all (%llu)\n", + lowest_quality->hostlist_uri, + (unsigned long long) lowest_quality->quality); + GNUNET_CONTAINER_DLL_remove (linked_list_head, linked_list_tail, + lowest_quality); + linked_list_size--; + GNUNET_free (lowest_quality); + } + GNUNET_CONTAINER_DLL_insert (linked_list_head, linked_list_tail, + hostlist_to_test); + linked_list_size++; + GNUNET_STATISTICS_set (stats, gettext_noop ("# advertised hostlist URIs"), + linked_list_size, GNUNET_NO); + stat_testing_hostlist = GNUNET_NO; +} + + +/** + * Method updating hostlist statistics + */ +static void +update_hostlist () +{ + char *stat; + + if (((stat_use_bootstrap == GNUNET_NO) && (NULL != current_hostlist)) || + ((stat_testing_hostlist == GNUNET_YES) && (NULL != current_hostlist))) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Updating hostlist statics for URI `%s'\n", + current_hostlist->hostlist_uri); + current_hostlist->hello_count = stat_hellos_obtained; + current_hostlist->time_last_usage = GNUNET_TIME_absolute_get (); + current_hostlist->quality = + checked_add (current_hostlist->quality, + (stat_hellos_obtained * HOSTLIST_SUCCESSFUL_HELLO)); + if (GNUNET_YES == stat_download_successful) + { + current_hostlist->times_used++; + current_hostlist->quality = + checked_add (current_hostlist->quality, HOSTLIST_SUCCESSFUL_DOWNLOAD); + GNUNET_asprintf (&stat, gettext_noop ("# advertised URI `%s' downloaded"), + current_hostlist->hostlist_uri); + + GNUNET_STATISTICS_update (stats, stat, 1, GNUNET_YES); + GNUNET_free (stat); + } + else + current_hostlist->quality = + checked_sub (current_hostlist->quality, HOSTLIST_FAILED_DOWNLOAD); + } + current_hostlist = NULL; + /* Alternating the usage of preconfigured and learned hostlists */ + + if (stat_testing_hostlist == GNUNET_YES) + return; + + if (GNUNET_YES == stat_learning) + { + if (stat_use_bootstrap == GNUNET_YES) + stat_use_bootstrap = GNUNET_NO; + else + stat_use_bootstrap = GNUNET_YES; + } + else + stat_use_bootstrap = GNUNET_YES; +} + + +/** + * Clean up the state from the task that downloaded the + * hostlist and schedule the next task. + */ +static void +clean_up () +{ + CURLMcode mret; + + if ((stat_testing_hostlist == GNUNET_YES) && + (GNUNET_NO == stat_download_successful) && (NULL != hostlist_to_test)) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _ + ("Advertised hostlist with URI `%s' could not be downloaded. Advertised URI gets dismissed.\n"), + hostlist_to_test->hostlist_uri); + } + + if (stat_testing_hostlist == GNUNET_YES) + { + stat_testing_hostlist = GNUNET_NO; + } + if (NULL != hostlist_to_test) + { + GNUNET_free (hostlist_to_test); + hostlist_to_test = NULL; + } + + if (multi != NULL) + { + mret = curl_multi_remove_handle (multi, curl); + if (mret != CURLM_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"), + "curl_multi_remove_handle", __FILE__, __LINE__, + curl_multi_strerror (mret)); + } + mret = curl_multi_cleanup (multi); + if (mret != CURLM_OK) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"), + "curl_multi_cleanup", __FILE__, __LINE__, + curl_multi_strerror (mret)); + multi = NULL; + } + if (curl != NULL) + { + curl_easy_cleanup (curl); + curl = NULL; + } + GNUNET_free_non_null (current_url); + current_url = NULL; + stat_bytes_downloaded = 0; + stat_download_in_progress = GNUNET_NO; +} + + +/** + * Task that is run when we are ready to receive more data from the hostlist + * server. + * + * @param cls closure, unused + * @param tc task context, unused + */ +static void +task_download (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * Ask CURL for the select set and then schedule the + * receiving task with the scheduler. + */ +static void +download_prepare () +{ + CURLMcode mret; + fd_set rs; + fd_set ws; + fd_set es; + int max; + struct GNUNET_NETWORK_FDSet *grs; + struct GNUNET_NETWORK_FDSet *gws; + long timeout; + struct GNUNET_TIME_Relative rtime; + + max = -1; + FD_ZERO (&rs); + FD_ZERO (&ws); + FD_ZERO (&es); + mret = curl_multi_fdset (multi, &rs, &ws, &es, &max); + if (mret != CURLM_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"), + "curl_multi_fdset", __FILE__, __LINE__, + curl_multi_strerror (mret)); + clean_up (); + return; + } + mret = curl_multi_timeout (multi, &timeout); + if (mret != CURLM_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"), + "curl_multi_timeout", __FILE__, __LINE__, + curl_multi_strerror (mret)); + clean_up (); + return; + } + rtime = + GNUNET_TIME_relative_min (GNUNET_TIME_absolute_get_remaining (end_time), + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MILLISECONDS, timeout)); + grs = GNUNET_NETWORK_fdset_create (); + gws = GNUNET_NETWORK_fdset_create (); + GNUNET_NETWORK_fdset_copy_native (grs, &rs, max + 1); + GNUNET_NETWORK_fdset_copy_native (gws, &ws, max + 1); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Scheduling task for hostlist download using cURL\n"); + ti_download = + GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, + rtime, grs, gws, + &task_download, multi); + GNUNET_NETWORK_fdset_destroy (gws); + GNUNET_NETWORK_fdset_destroy (grs); +} + + +/** + * Task that is run when we are ready to receive more data from the hostlist + * server. + * + * @param cls closure, unused + * @param tc task context, unused + */ +static void +task_download (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + int running; + struct CURLMsg *msg; + CURLMcode mret; + + ti_download = GNUNET_SCHEDULER_NO_TASK; + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Shutdown requested while trying to download hostlist from `%s'\n", + current_url); + update_hostlist (); + clean_up (); + return; + } + if (0 == GNUNET_TIME_absolute_get_remaining (end_time).rel_value_us) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Timeout trying to download hostlist from `%s'\n"), + current_url); + update_hostlist (); + clean_up (); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Ready for processing hostlist client request\n"); + do + { + running = 0; + if (stat_bytes_downloaded > MAX_BYTES_PER_HOSTLISTS) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Download limit of %u bytes exceeded, stopping download\n"), + MAX_BYTES_PER_HOSTLISTS); + clean_up (); + return; + } + mret = curl_multi_perform (multi, &running); + if (running == 0) + { + do + { + msg = curl_multi_info_read (multi, &running); + GNUNET_break (msg != NULL); + if (msg == NULL) + break; + switch (msg->msg) + { + case CURLMSG_DONE: + if ((msg->data.result != CURLE_OK) && + (msg->data.result != CURLE_GOT_NOTHING)) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Download of hostlist from `%s' failed: `%s'\n"), + current_url, + curl_easy_strerror (msg->data.result)); + else + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Download of hostlist `%s' completed.\n"), + current_url); + stat_download_successful = GNUNET_YES; + update_hostlist (); + if (GNUNET_YES == stat_testing_hostlist) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _ + ("Adding successfully tested hostlist `%s' datastore.\n"), + current_url); + insert_hostlist (); + hostlist_to_test = NULL; + stat_testing_hostlist = GNUNET_NO; + } + } + clean_up (); + return; + default: + break; + } + + } + while ((running > 0)); + } + } + while (mret == CURLM_CALL_MULTI_PERFORM); + + if (mret != CURLM_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("%s failed at %s:%d: `%s'\n"), + "curl_multi_perform", __FILE__, __LINE__, + curl_multi_strerror (mret)); + clean_up (); + } + download_prepare (); +} + + +/** + * Main function that will download a hostlist and process its + * data. + */ +static void +download_hostlist () +{ + CURLcode ret; + CURLMcode mret; + + + current_url = download_get_url (); + if (current_url == NULL) + return; + curl = curl_easy_init (); + multi = NULL; + if (curl == NULL) + { + GNUNET_break (0); + clean_up (); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK, + _("Bootstrapping using hostlist at `%s'.\n"), current_url); + + stat_download_in_progress = GNUNET_YES; + stat_download_successful = GNUNET_NO; + stat_hellos_obtained = 0; + stat_bytes_downloaded = 0; + + GNUNET_STATISTICS_update (stats, + gettext_noop ("# hostlist downloads initiated"), 1, + GNUNET_NO); + if (proxy != NULL) + { + CURL_EASY_SETOPT (curl, CURLOPT_PROXY, proxy); + CURL_EASY_SETOPT (curl, CURLOPT_PROXYTYPE, proxy_type); + if (NULL != proxy_username) + CURL_EASY_SETOPT (curl, CURLOPT_PROXYUSERNAME, proxy_username); + if (NULL != proxy_password) + CURL_EASY_SETOPT (curl, CURLOPT_PROXYPASSWORD, proxy_password); + } + download_pos = 0; + stat_bogus_url = 0; + CURL_EASY_SETOPT (curl, CURLOPT_WRITEFUNCTION, &callback_download); + if (ret != CURLE_OK) + { + clean_up (); + return; + } + CURL_EASY_SETOPT (curl, CURLOPT_WRITEDATA, NULL); + if (ret != CURLE_OK) + { + clean_up (); + return; + } + CURL_EASY_SETOPT (curl, CURLOPT_FOLLOWLOCATION, 1); + CURL_EASY_SETOPT (curl, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS); + CURL_EASY_SETOPT (curl, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS); + CURL_EASY_SETOPT (curl, CURLOPT_MAXREDIRS, 4); + /* no need to abort if the above failed */ + CURL_EASY_SETOPT (curl, CURLOPT_URL, current_url); + if (ret != CURLE_OK) + { + clean_up (); + return; + } + CURL_EASY_SETOPT (curl, CURLOPT_FAILONERROR, 1); +#if 0 + CURL_EASY_SETOPT (curl, CURLOPT_VERBOSE, 1); +#endif + CURL_EASY_SETOPT (curl, CURLOPT_BUFFERSIZE, GNUNET_SERVER_MAX_MESSAGE_SIZE); + if (0 == strncmp (current_url, "http", 4)) + CURL_EASY_SETOPT (curl, CURLOPT_USERAGENT, "GNUnet"); + CURL_EASY_SETOPT (curl, CURLOPT_CONNECTTIMEOUT, 60L); + CURL_EASY_SETOPT (curl, CURLOPT_TIMEOUT, 60L); + multi = curl_multi_init (); + if (multi == NULL) + { + GNUNET_break (0); + /* clean_up (); */ + return; + } + mret = curl_multi_add_handle (multi, curl); + if (mret != CURLM_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"), + "curl_multi_add_handle", __FILE__, __LINE__, + curl_multi_strerror (mret)); + mret = curl_multi_cleanup (multi); + if (mret != CURLM_OK) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"), + "curl_multi_cleanup", __FILE__, __LINE__, + curl_multi_strerror (mret)); + multi = NULL; + clean_up (); + return; + } + end_time = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES); + download_prepare (); +} + + +static void +task_download_dispatcher (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + ti_download_dispatcher_task = GNUNET_SCHEDULER_NO_TASK; + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + return; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download is initiated...\n"); + if (GNUNET_NO == stat_download_in_progress) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download can start immediately...\n"); + download_hostlist (); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Download in progess, have to wait...\n"); + ti_download_dispatcher_task = + GNUNET_SCHEDULER_add_delayed (WAITING_INTERVAL, + &task_download_dispatcher, NULL); + } +} + + +/** + * Task that checks if we should try to download a hostlist. + * If so, we initiate the download, otherwise we schedule + * this task again for a later time. + */ +static void +task_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + static int once; + struct GNUNET_TIME_Relative delay; + + ti_check_download = GNUNET_SCHEDULER_NO_TASK; + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + return; + if (stats == NULL) + { + curl_global_cleanup (); + return; /* in shutdown */ + } + if ( (stat_connection_count < MIN_CONNECTIONS) && + (GNUNET_SCHEDULER_NO_TASK == ti_download_dispatcher_task) ) + ti_download_dispatcher_task = + GNUNET_SCHEDULER_add_now (&task_download_dispatcher, NULL); + + delay = hostlist_delay; + if (0 == hostlist_delay.rel_value_us) + hostlist_delay = GNUNET_TIME_UNIT_SECONDS; + else + hostlist_delay = GNUNET_TIME_relative_multiply (hostlist_delay, 2); + if (hostlist_delay.rel_value_us > + GNUNET_TIME_UNIT_HOURS.rel_value_us * (1 + stat_connection_count)) + hostlist_delay = + GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, + (1 + stat_connection_count)); + GNUNET_STATISTICS_set (stats, + gettext_noop + ("# milliseconds between hostlist downloads"), + hostlist_delay.rel_value_us / 1000LL, + GNUNET_YES); + if (0 == once) + { + delay = GNUNET_TIME_UNIT_ZERO; + once = 1; + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Have %u/%u connections. Will consider downloading hostlist in %s\n"), + stat_connection_count, MIN_CONNECTIONS, + GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES)); + ti_check_download = GNUNET_SCHEDULER_add_delayed (delay, &task_check, NULL); +} + + +/** + * This tasks sets hostlist testing to allowed after intervall between to testings is reached + * + * @param cls closure + * @param tc TaskContext + */ +static void +task_testing_intervall_reset (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + ti_testing_intervall_task = GNUNET_SCHEDULER_NO_TASK; + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + return; + stat_testing_allowed = GNUNET_OK; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Testing new hostlist advertisements is allowed again\n"); +} + + +/** + * Task that writes hostlist entries to a file on a regular base + * + * @param cls closure + * @param tc TaskContext + */ +static void +task_hostlist_saving (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + ti_saving_task = GNUNET_SCHEDULER_NO_TASK; + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + return; + save_hostlist_file (GNUNET_NO); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Hostlists will be saved to file again in %s\n", + GNUNET_STRINGS_relative_time_to_string(SAVING_INTERVAL, GNUNET_YES)); + ti_saving_task = + GNUNET_SCHEDULER_add_delayed (SAVING_INTERVAL, &task_hostlist_saving, + NULL); +} + + +/** + * Method called whenever a given peer connects. + * + * @param cls closure + * @param peer peer identity this notification is about + */ +static void +handler_connect (void *cls, const struct GNUNET_PeerIdentity *peer) +{ + GNUNET_assert (stat_connection_count < UINT_MAX); + stat_connection_count++; + GNUNET_STATISTICS_update (stats, gettext_noop ("# active connections"), 1, + GNUNET_NO); +} + + +/** + * Method called whenever a given peer disconnects. + * + * @param cls closure + * @param peer peer identity this notification is about + */ +static void +handler_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) +{ + GNUNET_assert (stat_connection_count > 0); + stat_connection_count--; + GNUNET_STATISTICS_update (stats, gettext_noop ("# active connections"), -1, + GNUNET_NO); +} + + +/** + * Method called whenever an advertisement message arrives. + * + * @param cls closure (always NULL) + * @param peer the peer sending the message + * @param message the actual message + * @return #GNUNET_OK to keep the connection open, + * #GNUNET_SYSERR to close it (signal serious error) + */ +static int +handler_advertisement (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message) +{ + size_t size; + size_t uri_size; + const struct GNUNET_MessageHeader *incoming; + const char *uri; + struct Hostlist *hostlist; + + GNUNET_assert (ntohs (message->type) == + GNUNET_MESSAGE_TYPE_HOSTLIST_ADVERTISEMENT); + size = ntohs (message->size); + if (size <= sizeof (struct GNUNET_MessageHeader)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + incoming = (const struct GNUNET_MessageHeader *) message; + uri = (const char *) &incoming[1]; + uri_size = size - sizeof (struct GNUNET_MessageHeader); + if (uri[uri_size - 1] != '\0') + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Hostlist client recieved advertisement from `%s' containing URI `%s'\n", + GNUNET_i2s (peer), uri); + if (GNUNET_NO != linked_list_contains (uri)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "URI `%s' is already known\n", uri); + return GNUNET_OK; + } + + if (GNUNET_NO == stat_testing_allowed) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Currently not accepting new advertisements: interval between to advertisements is not reached\n"); + return GNUNET_SYSERR; + } + if (GNUNET_YES == stat_testing_hostlist) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Currently not accepting new advertisements: we are already testing a hostlist\n"); + return GNUNET_SYSERR; + } + + hostlist = GNUNET_malloc (sizeof (struct Hostlist) + uri_size); + hostlist->hostlist_uri = (const char *) &hostlist[1]; + memcpy (&hostlist[1], uri, uri_size); + hostlist->time_creation = GNUNET_TIME_absolute_get (); + hostlist->quality = HOSTLIST_INITIAL; + hostlist_to_test = hostlist; + + stat_testing_hostlist = GNUNET_YES; + stat_testing_allowed = GNUNET_NO; + ti_testing_intervall_task = + GNUNET_SCHEDULER_add_delayed (TESTING_INTERVAL, + &task_testing_intervall_reset, NULL); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Testing new hostlist advertisements is locked for the next %s\n", + GNUNET_STRINGS_relative_time_to_string (TESTING_INTERVAL, + GNUNET_YES)); + + ti_download_dispatcher_task = + GNUNET_SCHEDULER_add_now (&task_download_dispatcher, NULL); + + return GNUNET_OK; +} + + +/** + * Continuation called by the statistics code once + * we go the stat. Initiates hostlist download scheduling. + * + * @param cls closure + * @param success #GNUNET_OK if statistics were + * successfully obtained, #GNUNET_SYSERR if not. + */ +static void +primary_task (void *cls, int success) +{ + sget = NULL; + GNUNET_assert (stats != NULL); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Statistics request done, scheduling hostlist download\n"); + ti_check_download = GNUNET_SCHEDULER_add_now (&task_check, NULL); +} + + +/** + * We've received the previous delay value from statistics. Remember it. + * + * @param cls NULL, unused + * @param subsystem should be "hostlist", unused + * @param name will be "milliseconds between hostlist downloads", unused + * @param value previous delay value, in milliseconds (!) + * @param is_persistent unused, will be #GNUNET_YES + */ +static int +process_stat (void *cls, + const char *subsystem, + const char *name, + uint64_t value, + int is_persistent) +{ + hostlist_delay.rel_value_us = value * 1000LL; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Initial time between hostlist downloads is %s\n", + GNUNET_STRINGS_relative_time_to_string (hostlist_delay, GNUNET_YES)); + return GNUNET_OK; +} + + +/** + * Method to load persistent hostlist file during hostlist client startup + */ +static void +load_hostlist_file () +{ + char *filename; + char *uri; + char *emsg; + struct Hostlist *hostlist; + uint32_t times_used; + uint32_t hellos_returned; + uint64_t quality; + uint64_t last_used; + uint64_t created; + uint32_t counter; + struct GNUNET_BIO_ReadHandle *rh; + + uri = NULL; + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, "HOSTLIST", "HOSTLISTFILE", + &filename)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, + "hostlist", "HOSTLISTFILE"); + return; + } + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Loading saved hostlist entries from file `%s' \n"), + filename); + if (GNUNET_NO == GNUNET_DISK_file_test (filename)) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Hostlist file `%s' does not exist\n"), filename); + GNUNET_free (filename); + return; + } + + rh = GNUNET_BIO_read_open (filename); + if (NULL == rh) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Could not open file `%s' for reading to load hostlists: %s\n"), + filename, STRERROR (errno)); + GNUNET_free (filename); + return; + } + + counter = 0; + while ((GNUNET_OK == GNUNET_BIO_read_string (rh, "url", &uri, MAX_URL_LEN)) && + (NULL != uri) && (GNUNET_OK == GNUNET_BIO_read_int32 (rh, ×_used)) + && (GNUNET_OK == GNUNET_BIO_read_int64 (rh, &quality)) && + (GNUNET_OK == GNUNET_BIO_read_int64 (rh, &last_used)) && + (GNUNET_OK == GNUNET_BIO_read_int64 (rh, &created)) && + (GNUNET_OK == GNUNET_BIO_read_int32 (rh, &hellos_returned))) + { + hostlist = GNUNET_malloc (sizeof (struct Hostlist) + strlen (uri) + 1); + hostlist->hello_count = hellos_returned; + hostlist->hostlist_uri = (const char *) &hostlist[1]; + memcpy (&hostlist[1], uri, strlen (uri) + 1); + hostlist->quality = quality; + hostlist->time_creation.abs_value_us = created; + hostlist->time_last_usage.abs_value_us = last_used; + GNUNET_CONTAINER_DLL_insert (linked_list_head, linked_list_tail, hostlist); + linked_list_size++; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Added hostlist entry eith URI `%s' \n", + hostlist->hostlist_uri); + GNUNET_free (uri); + uri = NULL; + counter++; + if (counter >= MAX_NUMBER_HOSTLISTS) + break; + } + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("%u hostlist URIs loaded from file\n"), + counter); + GNUNET_STATISTICS_set (stats, + gettext_noop ("# hostlist URIs read from file"), + counter, GNUNET_YES); + GNUNET_STATISTICS_set (stats, + gettext_noop ("# advertised hostlist URIs"), + linked_list_size, GNUNET_NO); + + GNUNET_free_non_null (uri); + emsg = NULL; + (void) GNUNET_BIO_read_close (rh, &emsg); + if (emsg != NULL) + GNUNET_free (emsg); + GNUNET_free (filename); +} + + +/** + * Method to save persistent hostlist file during hostlist client shutdown + * + * @param shutdown set if called because of shutdown, entries in linked list will be destroyed + */ +static void +save_hostlist_file (int shutdown) +{ + char *filename; + struct Hostlist *pos; + struct GNUNET_BIO_WriteHandle *wh; + int ok; + uint32_t counter; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, "HOSTLIST", "HOSTLISTFILE", + &filename)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, + "hostlist", "HOSTLISTFILE"); + return; + } + if (GNUNET_SYSERR == GNUNET_DISK_directory_create_for_file (filename)) + { + GNUNET_free (filename); + return; + } + wh = GNUNET_BIO_write_open (filename); + if (NULL == wh) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Could not open file `%s' for writing to save hostlists: %s\n"), + filename, STRERROR (errno)); + GNUNET_free (filename); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Writing %u hostlist URIs to `%s'\n"), + linked_list_size, filename); + /* add code to write hostlists to file using bio */ + ok = GNUNET_YES; + counter = 0; + while (NULL != (pos = linked_list_head)) + { + if (GNUNET_YES == shutdown) + { + GNUNET_CONTAINER_DLL_remove (linked_list_head, linked_list_tail, pos); + linked_list_size--; + } + if (GNUNET_YES == ok) + { + if ((GNUNET_OK != GNUNET_BIO_write_string (wh, pos->hostlist_uri)) || + (GNUNET_OK != GNUNET_BIO_write_int32 (wh, pos->times_used)) || + (GNUNET_OK != GNUNET_BIO_write_int64 (wh, pos->quality)) || + (GNUNET_OK != + GNUNET_BIO_write_int64 (wh, pos->time_last_usage.abs_value_us)) || + (GNUNET_OK != + GNUNET_BIO_write_int64 (wh, pos->time_creation.abs_value_us)) || + (GNUNET_OK != GNUNET_BIO_write_int32 (wh, pos->hello_count))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Error writing hostlist URIs to file `%s'\n"), filename); + ok = GNUNET_NO; + } + } + + if (GNUNET_YES == shutdown) + GNUNET_free (pos); + counter++; + if (counter >= MAX_NUMBER_HOSTLISTS) + break; + } + GNUNET_STATISTICS_set (stats, + gettext_noop ("# hostlist URIs written to file"), + counter, GNUNET_YES); + + if (GNUNET_OK != GNUNET_BIO_write_close (wh)) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Error writing hostlist URIs to file `%s'\n"), filename); + GNUNET_free (filename); +} + + +/** + * Start downloading hostlists from hostlist servers as necessary. + * + * @param c configuration to use + * @param st statistics handle to use + * @param ch[OUT] set to handler for CORE connect events + * @param dh[OUT] set to handler for CORE disconnect events + * @param msgh[OUT] set to handler for CORE advertisement messages + * @param learn should we learn hostlist URLs from CORE + * @return #GNUNET_OK on success + */ +int +GNUNET_HOSTLIST_client_start (const struct GNUNET_CONFIGURATION_Handle *c, + struct GNUNET_STATISTICS_Handle *st, + GNUNET_CORE_ConnectEventHandler *ch, + GNUNET_CORE_DisconnectEventHandler *dh, + GNUNET_CORE_MessageCallback *msgh, + int learn) +{ + char *filename; + char *proxytype_str; + int result; + + GNUNET_assert (NULL != st); + if (0 != curl_global_init (CURL_GLOBAL_WIN32)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + transport = GNUNET_TRANSPORT_connect (c, NULL, NULL, NULL, NULL, NULL); + if (NULL == transport) + { + curl_global_cleanup (); + return GNUNET_SYSERR; + } + cfg = c; + stats = st; + + /* Read proxy configuration */ + if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, + "HOSTLIST", "PROXY", &proxy)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Found proxy host: `%s'\n", + proxy); + /* proxy username */ + if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, + "HOSTLIST", "PROXY_USERNAME", &proxy_username)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Found proxy username name: `%s'\n", + proxy_username); + } + + /* proxy password */ + if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, + "HOSTLIST", "PROXY_PASSWORD", &proxy_password)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Found proxy password name: `%s'\n", + proxy_password); + } + + /* proxy type */ + if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, + "HOSTLIST", "PROXY_TYPE", &proxytype_str)) + { + GNUNET_STRINGS_utf8_toupper (proxytype_str, proxytype_str); + + proxy_type = CURLPROXY_HTTP; + if (0 == strcmp(proxytype_str, "HTTP")) + proxy_type = CURLPROXY_HTTP; + else if (0 == strcmp(proxytype_str, "HTTP_1_0")) + proxy_type = CURLPROXY_HTTP_1_0; + else if (0 == strcmp(proxytype_str, "SOCKS4")) + proxy_type = CURLPROXY_SOCKS4; + else if (0 == strcmp(proxytype_str, "SOCKS5")) + proxy_type = CURLPROXY_SOCKS5; + else if (0 == strcmp(proxytype_str, "SOCKS4A")) + proxy_type = CURLPROXY_SOCKS4A; + else if (0 == strcmp(proxytype_str, "SOCKS5_HOSTNAME")) + proxy_type = CURLPROXY_SOCKS5_HOSTNAME ; + else + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Invalid proxy type: `%s', disabling proxy! Check configuration!\n"), + proxytype_str); + GNUNET_free (proxytype_str); + + GNUNET_free (proxy); + proxy = NULL; + GNUNET_free_non_null (proxy_username); + proxy_username = NULL; + GNUNET_free_non_null (proxy_password); + proxy_password = NULL; + + return GNUNET_SYSERR; + } + } + GNUNET_free_non_null (proxytype_str); + } + + stat_learning = learn; + *ch = &handler_connect; + *dh = &handler_disconnect; + linked_list_head = NULL; + linked_list_tail = NULL; + stat_use_bootstrap = GNUNET_YES; + stat_testing_hostlist = GNUNET_NO; + stat_testing_allowed = GNUNET_YES; + + if (GNUNET_YES == stat_learning) + { + *msgh = &handler_advertisement; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Learning is enabled on this peer\n")); + load_hostlist_file (); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Hostlists will be saved to file again in %s\n", + GNUNET_STRINGS_relative_time_to_string (SAVING_INTERVAL, GNUNET_YES)); + ti_saving_task = + GNUNET_SCHEDULER_add_delayed (SAVING_INTERVAL, &task_hostlist_saving, + NULL); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Learning is not enabled on this peer\n")); + *msgh = NULL; + if (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_filename (cfg, "HOSTLIST", + "HOSTLISTFILE", &filename)) + { + if (GNUNET_YES == GNUNET_DISK_file_test (filename)) + { + result = remove (filename); + if (result == 0) + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _ + ("Since learning is not enabled on this peer, hostlist file `%s' was removed\n"), + filename); + else + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Hostlist file `%s' could not be removed\n"), filename); + } + } + GNUNET_free (filename); + } + sget = GNUNET_STATISTICS_get (stats, "hostlist", + gettext_noop + ("# milliseconds between hostlist downloads"), + GNUNET_TIME_UNIT_MINUTES, &primary_task, &process_stat, + NULL); + return GNUNET_OK; +} + + +/** + * Stop downloading hostlists from hostlist servers as necessary. + */ +void +GNUNET_HOSTLIST_client_stop () +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hostlist client shutdown\n"); + if (NULL != sget) + { + GNUNET_STATISTICS_get_cancel (sget); + sget = NULL; + } + stats = NULL; + if (GNUNET_YES == stat_learning) + save_hostlist_file (GNUNET_YES); + if (ti_saving_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (ti_saving_task); + ti_saving_task = GNUNET_SCHEDULER_NO_TASK; + } + + if (ti_download_dispatcher_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (ti_download_dispatcher_task); + ti_download_dispatcher_task = GNUNET_SCHEDULER_NO_TASK; + } + if (ti_testing_intervall_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (ti_testing_intervall_task); + ti_testing_intervall_task = GNUNET_SCHEDULER_NO_TASK; + } + if (ti_download != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (ti_download); + ti_download = GNUNET_SCHEDULER_NO_TASK; + } + if (ti_check_download != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (ti_check_download); + ti_check_download = GNUNET_SCHEDULER_NO_TASK; + curl_global_cleanup (); + } + if (NULL != transport) + { + GNUNET_TRANSPORT_disconnect (transport); + transport = NULL; + } + GNUNET_free_non_null (proxy); + proxy = NULL; + GNUNET_free_non_null (proxy_username); + proxy_username = NULL; + GNUNET_free_non_null (proxy_password); + proxy_password = NULL; + + cfg = NULL; +} + +/* end of gnunet-daemon-hostlist_client.c */ diff --git a/src/hostlist/gnunet-daemon-hostlist_client.h b/src/hostlist/gnunet-daemon-hostlist_client.h new file mode 100644 index 000000000..55f355649 --- /dev/null +++ b/src/hostlist/gnunet-daemon-hostlist_client.h @@ -0,0 +1,61 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file hostlist/gnunet-daemon-hostlist_client.h + * @brief hostlist support. Downloads HELLOs via HTTP. + * @author Christian Grothoff + */ +#ifndef GNUNET_DAEMON_HOSTLIST_CLIENT_H +#define GNUNET_DAEMON_HOSTLIST_CLIENT_H + +#include "gnunet_core_service.h" +#include "gnunet_statistics_service.h" +#include "gnunet_util_lib.h" + + +/** + * Start downloading hostlists from hostlist servers as necessary. + * + * @param c the configuration to use + * @param st hande for publishing statistics + * @param ch[OUT] set to handler for connect notifications + * @param dh[OUT] set to handler for disconnect notifications + * @param msgh[OUT] set to handler for message handler notifications + * @param learn set if client is learning new hostlists + * @return #GNUNET_OK on success + */ +int +GNUNET_HOSTLIST_client_start (const struct GNUNET_CONFIGURATION_Handle *c, + struct GNUNET_STATISTICS_Handle *st, + GNUNET_CORE_ConnectEventHandler *ch, + GNUNET_CORE_DisconnectEventHandler *dh, + GNUNET_CORE_MessageCallback *msgh, + int learn); + + +/** + * Stop downloading hostlists from hostlist servers as necessary. + */ +void +GNUNET_HOSTLIST_client_stop (void); + + +#endif +/* end of gnunet-daemon-hostlist_client.h */ diff --git a/src/hostlist/gnunet-daemon-hostlist_server.c b/src/hostlist/gnunet-daemon-hostlist_server.c new file mode 100644 index 000000000..8a7e747c6 --- /dev/null +++ b/src/hostlist/gnunet-daemon-hostlist_server.c @@ -0,0 +1,888 @@ +/* + This file is part of GNUnet. + (C) 2008, 2009, 2010, 2014 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file hostlist/gnunet-daemon-hostlist_server.c + * @author Christian Grothoff + * @author Matthias Wachs + * @author David Barksdale + * @brief application to provide an integrated hostlist HTTP server + */ +#include "platform.h" +#include +#include "gnunet-daemon-hostlist_server.h" +#include "gnunet_hello_lib.h" +#include "gnunet_peerinfo_service.h" +#include "gnunet-daemon-hostlist.h" +#include "gnunet_resolver_service.h" + + +/** + * How long until our hostlist advertisment transmission via CORE should + * time out? + */ +#define GNUNET_ADV_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5) + + +/** + * Handle to the HTTP server as provided by libmicrohttpd for IPv6. + */ +static struct MHD_Daemon *daemon_handle_v6; + +/** + * Handle to the HTTP server as provided by libmicrohttpd for IPv4. + */ +static struct MHD_Daemon *daemon_handle_v4; + +/** + * Our configuration. + */ +static const struct GNUNET_CONFIGURATION_Handle *cfg; + +/** + * For keeping statistics. + */ +static struct GNUNET_STATISTICS_Handle *stats; + +/** + * Handle to the core service (NULL until we've connected to it). + */ +static struct GNUNET_CORE_Handle *core; + +/** + * Handle to the peerinfo notify service (NULL until we've connected to it). + */ +static struct GNUNET_PEERINFO_NotifyContext *notify; + +/** + * Our primary task for IPv4. + */ +static GNUNET_SCHEDULER_TaskIdentifier hostlist_task_v4; + +/** + * Our primary task for IPv6. + */ +static GNUNET_SCHEDULER_TaskIdentifier hostlist_task_v6; + +/** + * Our canonical response. + */ +static struct MHD_Response *response; + +/** + * Handle for accessing peerinfo service. + */ +static struct GNUNET_PEERINFO_Handle *peerinfo; + +/** + * Set if we are allowed to advertise our hostlist to others. + */ +static int advertising; + +/** + * Buffer for the hostlist address + */ +static char *hostlist_uri; + + +/** + * Context for host processor. + */ +struct HostSet +{ + unsigned int size; + + char *data; + + struct GNUNET_PEERINFO_IteratorContext *pitr; +}; + + +/** + * NULL if we are not currenlty iterating over peer information. + */ +static struct HostSet *builder; + + +/** + * Function that assembles our response. + */ +static void +finish_response () +{ + if (NULL != response) + MHD_destroy_response (response); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Creating hostlist response with %u bytes\n", + (unsigned int) builder->size); + response = + MHD_create_response_from_data (builder->size, builder->data, MHD_YES, + MHD_NO); + if ((NULL == daemon_handle_v4) && (NULL == daemon_handle_v6)) + { + MHD_destroy_response (response); + response = NULL; + } + GNUNET_STATISTICS_set (stats, gettext_noop ("bytes in hostlist"), + builder->size, GNUNET_YES); + GNUNET_free (builder); + builder = NULL; +} + + +/** + * Set @a cls to #GNUNET_YES (we have an address!). + * + * @param cls closure, an `int *` + * @param address the address (ignored) + * @param expiration expiration time (call is ignored if this is in the past) + * @return #GNUNET_SYSERR to stop iterating (unless expiration has occured) + */ +static int +check_has_addr (void *cls, + const struct GNUNET_HELLO_Address *address, + struct GNUNET_TIME_Absolute expiration) +{ + int *arg = cls; + + if (0 == GNUNET_TIME_absolute_get_remaining (expiration).rel_value_us) + { + GNUNET_STATISTICS_update (stats, + gettext_noop ("expired addresses encountered"), 1, + GNUNET_YES); + return GNUNET_YES; /* ignore this address */ + } + *arg = GNUNET_YES; + return GNUNET_SYSERR; +} + + +/** + * Callback that processes each of the known HELLOs for the + * hostlist response construction. + * + * @param cls closure, NULL + * @param peer id of the peer, NULL for last call + * @param hello hello message for the peer (can be NULL) + * @param error message + */ +static void +host_processor (void *cls, + const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_HELLO_Message *hello, + const char *err_msg) +{ + size_t old; + size_t s; + int has_addr; + + if (NULL != err_msg) + { + GNUNET_assert (NULL == peer); + builder->pitr = NULL; + GNUNET_free_non_null (builder->data); + GNUNET_free (builder); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Error in communication with PEERINFO service: %s\n"), + err_msg); + return; + } + if (NULL == peer) + { + builder->pitr = NULL; + finish_response (); + return; + } + if (NULL == hello) + return; + has_addr = GNUNET_NO; + GNUNET_HELLO_iterate_addresses (hello, + GNUNET_NO, + &check_has_addr, + &has_addr); + if (GNUNET_NO == has_addr) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "HELLO for peer `%4s' has no address, not suitable for hostlist!\n", + GNUNET_i2s (peer)); + GNUNET_STATISTICS_update (stats, + gettext_noop + ("HELLOs without addresses encountered (ignored)"), + 1, GNUNET_NO); + return; + } + old = builder->size; + s = GNUNET_HELLO_size (hello); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received %u bytes of `%s' from peer `%s' for hostlist.\n", + (unsigned int) s, + "HELLO", + GNUNET_i2s (peer)); + if ((old + s >= GNUNET_MAX_MALLOC_CHECKED) || + (old + s >= MAX_BYTES_PER_HOSTLISTS)) + { + GNUNET_STATISTICS_update (stats, + gettext_noop + ("bytes not included in hostlist (size limit)"), + s, GNUNET_NO); + return; /* too large, skip! */ + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Adding peer `%s' to hostlist (%u bytes)\n", + GNUNET_i2s (peer), + (unsigned int) s); + GNUNET_array_grow (builder->data, builder->size, old + s); + memcpy (&builder->data[old], hello, s); +} + + +/** + * Hostlist access policy (very permissive, allows everything). + * Returns #MHD_NO only if we are not yet ready to serve. + * + * @param cls closure + * @param addr address information from the client + * @param addrlen length of @a addr + * @return #MHD_YES if connection is allowed, #MHD_NO if not (we are not ready) + */ +static int +accept_policy_callback (void *cls, + const struct sockaddr *addr, + socklen_t addrlen) +{ + if (NULL == response) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received request for hostlist, but I am not yet ready; rejecting!\n"); + return MHD_NO; + } + return MHD_YES; /* accept all */ +} + + +/** + * Add headers to a request indicating that we allow Cross-Origin Resource + * Sharing. + * + * @param response response to add headers to + */ +static void +add_cors_headers (struct MHD_Response *response) +{ + MHD_add_response_header (response, + "Access-Control-Allow-Origin", + "*"); + MHD_add_response_header (response, + "Access-Control-Allow-Methods", + "GET, OPTIONS"); + MHD_add_response_header (response, + "Access-Control-Max-Age", + "86400"); +} + + +/** + * Main request handler. + * + * @param cls argument given together with the function + * pointer when the handler was registered with MHD + * @param url the requested url + * @param method the HTTP method used (#MHD_HTTP_METHOD_GET, + * #MHD_HTTP_METHOD_PUT, etc.) + * @param version the HTTP version string (i.e. + * #MHD_HTTP_VERSION_1_1) + * @param upload_data the data being uploaded (excluding HEADERS, + * for a POST that fits into memory and that is encoded + * with a supported encoding, the POST data will NOT be + * given in upload_data and is instead available as + * part of #MHD_get_connection_values; very large POST + * data *will* be made available incrementally in + * @a upload_data) + * @param upload_data_size set initially to the size of the + * @a upload_data provided; the method must update this + * value to the number of bytes NOT processed; + * @param con_cls pointer that the callback can set to some + * address and that will be preserved by MHD for future + * calls for this request; since the access handler may + * be called many times (i.e., for a PUT/POST operation + * with plenty of upload data) this allows the application + * to easily associate some request-specific state. + * If necessary, this state can be cleaned up in the + * global #MHD_RequestCompletedCallback (which + * can be set with the #MHD_OPTION_NOTIFY_COMPLETED). + * Initially, `*con_cls` will be NULL. + * @return #MHD_YES if the connection was handled successfully, + * #MHD_NO if the socket must be closed due to a serios + * error while handling the request + */ +static int +access_handler_callback (void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, + size_t *upload_data_size, + void **con_cls) +{ + static int dummy; + + /* CORS pre-flight request */ + if (0 == strcmp (MHD_HTTP_METHOD_OPTIONS, method)) + { + struct MHD_Response *options_response; + int rc; + + options_response = MHD_create_response_from_buffer (0, NULL, + MHD_RESPMEM_PERSISTENT); + add_cors_headers(options_response); + rc = MHD_queue_response (connection, MHD_HTTP_OK, options_response); + MHD_destroy_response (options_response); + return rc; + } + if (0 != strcmp (method, MHD_HTTP_METHOD_GET)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Refusing `%s' request to hostlist server\n"), method); + GNUNET_STATISTICS_update (stats, + gettext_noop + ("hostlist requests refused (not HTTP GET)"), 1, + GNUNET_YES); + return MHD_NO; + } + if (NULL == *con_cls) + { + (*con_cls) = &dummy; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending 100 CONTINUE reply\n"); + return MHD_YES; /* send 100 continue */ + } + if (0 != *upload_data_size) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Refusing `%s' request with %llu bytes of upload data\n"), + method, (unsigned long long) *upload_data_size); + GNUNET_STATISTICS_update (stats, + gettext_noop + ("hostlist requests refused (upload data)"), 1, + GNUNET_YES); + return MHD_NO; /* do not support upload data */ + } + if (NULL == response) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Could not handle hostlist request since I do not have a response yet\n")); + GNUNET_STATISTICS_update (stats, + gettext_noop + ("hostlist requests refused (not ready)"), 1, + GNUNET_YES); + return MHD_NO; /* internal error, no response yet */ + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Received request for our hostlist\n")); + GNUNET_STATISTICS_update (stats, + gettext_noop ("hostlist requests processed"), + 1, GNUNET_YES); + add_cors_headers (response); + return MHD_queue_response (connection, MHD_HTTP_OK, response); +} + + +/** + * Handler called by CORE when CORE is ready to transmit message + * + * @param cls closure + * @param size size of buffer to copy message to + * @param buf buffer to copy message to + * @return number of bytes copied to @a buf + */ +static size_t +adv_transmit_ready (void *cls, + size_t size, + void *buf) +{ + static uint64_t hostlist_adv_count; + size_t transmission_size; + size_t uri_size; /* Including \0 termination! */ + struct GNUNET_MessageHeader header; + char *cbuf; + + if (NULL == buf) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Transmission failed, buffer invalid!\n"); + return 0; + } + uri_size = strlen (hostlist_uri) + 1; + transmission_size = sizeof (struct GNUNET_MessageHeader) + uri_size; + header.type = htons (GNUNET_MESSAGE_TYPE_HOSTLIST_ADVERTISEMENT); + header.size = htons (transmission_size); + GNUNET_assert (size >= transmission_size); + memcpy (buf, &header, sizeof (struct GNUNET_MessageHeader)); + cbuf = buf; + memcpy (&cbuf[sizeof (struct GNUNET_MessageHeader)], hostlist_uri, uri_size); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sent advertisement message: Copied %u bytes into buffer!\n", + (unsigned int) transmission_size); + hostlist_adv_count++; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " # Sent advertisement message: %u\n", + hostlist_adv_count); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# hostlist advertisements send"), 1, + GNUNET_NO); + return transmission_size; +} + + +/** + * Method called whenever a given peer connects. + * + * @param cls closure + * @param peer peer identity this notification is about + */ +static void +connect_handler (void *cls, + const struct GNUNET_PeerIdentity *peer) +{ + size_t size; + + if (!advertising) + return; + if (NULL == hostlist_uri) + return; + size = strlen (hostlist_uri) + 1; + if (size + sizeof (struct GNUNET_MessageHeader) >= + GNUNET_SERVER_MAX_MESSAGE_SIZE) + { + GNUNET_break (0); + return; + } + size += sizeof (struct GNUNET_MessageHeader); + if (NULL == core) + { + GNUNET_break (0); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Asked CORE to transmit advertisement message with a size of %u bytes to peer `%s'\n", + size, + GNUNET_i2s (peer)); + if (NULL == + GNUNET_CORE_notify_transmit_ready (core, GNUNET_YES, + GNUNET_CORE_PRIO_BEST_EFFORT, + GNUNET_ADV_TIMEOUT, + peer, + size, + &adv_transmit_ready, NULL)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Advertisement message could not be queued by core\n")); + } +} + + +/** + * Method called whenever a given peer disconnects. + * + * @param cls closure + * @param peer peer identity this notification is about + */ +static void +disconnect_handler (void *cls, + const struct GNUNET_PeerIdentity *peer) +{ + /* nothing to do */ +} + + +/** + * PEERINFO calls this function to let us know about a possible peer + * that we might want to connect to. + * + * @param cls closure (not used) + * @param peer potential peer to connect to + * @param hello HELLO for this peer (or NULL) + * @param err_msg NULL if successful, otherwise contains error message + */ +static void +process_notify (void *cls, + const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_HELLO_Message *hello, + const char *err_msg) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peerinfo is notifying us to rebuild our hostlist\n"); + if (NULL != err_msg) + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Error in communication with PEERINFO service: %s\n"), + err_msg); + if (NULL != builder) + { + /* restart re-build already in progress ... */ + GNUNET_PEERINFO_iterate_cancel (builder->pitr); + GNUNET_free_non_null (builder->data); + builder->size = 0; + builder->data = NULL; + } + else + { + builder = GNUNET_new (struct HostSet); + } + GNUNET_assert (NULL != peerinfo); + builder->pitr = + GNUNET_PEERINFO_iterate (peerinfo, GNUNET_NO, NULL, GNUNET_TIME_UNIT_MINUTES, + &host_processor, NULL); +} + + +/** + * Function that queries MHD's select sets and + * starts the task waiting for them. + */ +static GNUNET_SCHEDULER_TaskIdentifier +prepare_daemon (struct MHD_Daemon *daemon_handle); + + +/** + * Call MHD to process pending requests and then go back + * and schedule the next run. + * + * @param cls the `struct MHD_Daemon` of the HTTP server to run + * @param tc scheduler context + */ +static void +run_daemon (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct MHD_Daemon *daemon_handle = cls; + + if (daemon_handle == daemon_handle_v4) + hostlist_task_v4 = GNUNET_SCHEDULER_NO_TASK; + else + hostlist_task_v6 = GNUNET_SCHEDULER_NO_TASK; + + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + return; + GNUNET_assert (MHD_YES == MHD_run (daemon_handle)); + if (daemon_handle == daemon_handle_v4) + hostlist_task_v4 = prepare_daemon (daemon_handle); + else + hostlist_task_v6 = prepare_daemon (daemon_handle); +} + + +/** + * Function that queries MHD's select sets and + * starts the task waiting for them. + * + * @param daemon_handle HTTP server to prepare to run + */ +static GNUNET_SCHEDULER_TaskIdentifier +prepare_daemon (struct MHD_Daemon *daemon_handle) +{ + GNUNET_SCHEDULER_TaskIdentifier ret; + fd_set rs; + fd_set ws; + fd_set es; + struct GNUNET_NETWORK_FDSet *wrs; + struct GNUNET_NETWORK_FDSet *wws; + int max; + MHD_UNSIGNED_LONG_LONG timeout; + int haveto; + struct GNUNET_TIME_Relative tv; + + FD_ZERO (&rs); + FD_ZERO (&ws); + FD_ZERO (&es); + wrs = GNUNET_NETWORK_fdset_create (); + wws = GNUNET_NETWORK_fdset_create (); + max = -1; + GNUNET_assert (MHD_YES == MHD_get_fdset (daemon_handle, &rs, &ws, &es, &max)); + haveto = MHD_get_timeout (daemon_handle, &timeout); + if (haveto == MHD_YES) + tv.rel_value_us = (uint64_t) timeout * 1000LL; + else + tv = GNUNET_TIME_UNIT_FOREVER_REL; + GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1); + GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1); + ret = + GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH, + tv, wrs, wws, + &run_daemon, daemon_handle); + GNUNET_NETWORK_fdset_destroy (wrs); + GNUNET_NETWORK_fdset_destroy (wws); + return ret; +} + + +/** + * Start server offering our hostlist. + * + * @param c configuration to use + * @param st statistics handle to use + * @param co core handle to use + * @param server_ch[OUT] set to handler for CORE connect events + * @param server_dh[OUT] set to handler for CORE disconnect events + * @param advertise #GNUNET_YES if we should advertise our hostlist + * @return #GNUNET_OK on success + */ +int +GNUNET_HOSTLIST_server_start (const struct GNUNET_CONFIGURATION_Handle *c, + struct GNUNET_STATISTICS_Handle *st, + struct GNUNET_CORE_Handle *co, + GNUNET_CORE_ConnectEventHandler *server_ch, + GNUNET_CORE_DisconnectEventHandler *server_dh, + int advertise) +{ + unsigned long long port; + char *hostname; + char *ipv4; + char *ipv6; + size_t size; + struct in_addr i4; + struct in6_addr i6; + struct sockaddr_in v4; + struct sockaddr_in6 v6; + const struct sockaddr *sa4; + const struct sockaddr *sa6; + + advertising = advertise; + if (! advertising) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Advertising not enabled on this hostlist server\n"); + else + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Advertising enabled on this hostlist server\n"); + cfg = c; + stats = st; + peerinfo = GNUNET_PEERINFO_connect (cfg); + if (NULL == peerinfo) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Could not access PEERINFO service. Exiting.\n")); + return GNUNET_SYSERR; + } + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, + "HOSTLIST", + "HTTPPORT", + &port)) + return GNUNET_SYSERR; + if ((0 == port) || (port > UINT16_MAX)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Invalid port number %llu. Exiting.\n"), + port); + return GNUNET_SYSERR; + } + + if (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_string (cfg, + "HOSTLIST", + "EXTERNAL_DNS_NAME", + &hostname)) + hostname = GNUNET_RESOLVER_local_fqdn_get (); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Hostlist service starts on %s:%llu\n"), + hostname, port); + if (NULL != hostname) + { + size = strlen (hostname); + if (size + 15 > MAX_URL_LEN) + { + GNUNET_break (0); + } + else + { + GNUNET_asprintf (&hostlist_uri, + "http://%s:%u/", hostname, + (unsigned int) port); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Address to obtain hostlist: `%s'\n"), + hostlist_uri); + } + GNUNET_free (hostname); + } + + if (GNUNET_CONFIGURATION_have_value (cfg, "HOSTLIST", "BINDTOIPV4")) + { + GNUNET_break (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (cfg, "HOSTLIST", + "BINDTOIP", &ipv4)); + } + else + ipv4 = NULL; + if (GNUNET_CONFIGURATION_have_value (cfg, "HOSTLIST", "BINDTOIPV6")) + { + GNUNET_break (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (cfg, "HOSTLIST", + "BINDTOIP", &ipv6)); + } + else + ipv6 = NULL; + sa4 = NULL; + if (NULL != ipv4) + { + if (1 == inet_pton (AF_INET, ipv4, &i4)) + { + memset (&v4, 0, sizeof (v4)); + v4.sin_family = AF_INET; + v4.sin_addr = i4; + v4.sin_port = htons (port); +#if HAVE_SOCKADDR_IN_SIN_LEN + v4.sin_len = sizeof (v4); +#endif + sa4 = (const struct sockaddr *) &v4; + } + else + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("`%s' is not a valid IPv4 address! Ignoring BINDTOIPV4.\n"), + ipv4); + GNUNET_free (ipv4); + } + sa6 = NULL; + if (NULL != ipv6) + { + if (1 == inet_pton (AF_INET6, ipv6, &i6)) + { + memset (&v6, 0, sizeof (v6)); + v6.sin6_family = AF_INET6; + v6.sin6_addr = i6; + v6.sin6_port = htons (port); +#if HAVE_SOCKADDR_IN_SIN_LEN + v6.sin6_len = sizeof (v6); +#endif + sa6 = (const struct sockaddr *) &v6; + } + else + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("`%s' is not a valid IPv6 address! Ignoring BINDTOIPV6.\n"), + ipv6); + GNUNET_free (ipv6); + } + + daemon_handle_v6 = MHD_start_daemon (MHD_USE_IPv6 | MHD_USE_DEBUG, + (uint16_t) port, + &accept_policy_callback, NULL, + &access_handler_callback, NULL, + MHD_OPTION_CONNECTION_LIMIT, + (unsigned int) 16, + MHD_OPTION_PER_IP_CONNECTION_LIMIT, + (unsigned int) 1, + MHD_OPTION_CONNECTION_TIMEOUT, + (unsigned int) 16, + MHD_OPTION_CONNECTION_MEMORY_LIMIT, + (size_t) (16 * 1024), + MHD_OPTION_SOCK_ADDR, + sa6, + MHD_OPTION_END); + daemon_handle_v4 = MHD_start_daemon (MHD_NO_FLAG | MHD_USE_DEBUG, + (uint16_t) port, + &accept_policy_callback, NULL, + &access_handler_callback, NULL, + MHD_OPTION_CONNECTION_LIMIT, + (unsigned int) 16, + MHD_OPTION_PER_IP_CONNECTION_LIMIT, + (unsigned int) 1, + MHD_OPTION_CONNECTION_TIMEOUT, + (unsigned int) 16, + MHD_OPTION_CONNECTION_MEMORY_LIMIT, + (size_t) (16 * 1024), + MHD_OPTION_SOCK_ADDR, + sa4, + MHD_OPTION_END); + + if ( (NULL == daemon_handle_v6) && + (NULL == daemon_handle_v4) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Could not start hostlist HTTP server on port %u\n"), + (unsigned short) port); + return GNUNET_SYSERR; + } + + core = co; + *server_ch = &connect_handler; + *server_dh = &disconnect_handler; + if (NULL != daemon_handle_v4) + hostlist_task_v4 = prepare_daemon (daemon_handle_v4); + if (NULL != daemon_handle_v6) + hostlist_task_v6 = prepare_daemon (daemon_handle_v6); + notify = GNUNET_PEERINFO_notify (cfg, GNUNET_NO, + &process_notify, NULL); + return GNUNET_OK; +} + + +/** + * Stop server offering our hostlist. + */ +void +GNUNET_HOSTLIST_server_stop () +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hostlist server shutdown\n"); + if (GNUNET_SCHEDULER_NO_TASK != hostlist_task_v6) + { + GNUNET_SCHEDULER_cancel (hostlist_task_v6); + hostlist_task_v6 = GNUNET_SCHEDULER_NO_TASK; + } + if (GNUNET_SCHEDULER_NO_TASK != hostlist_task_v4) + { + GNUNET_SCHEDULER_cancel (hostlist_task_v4); + hostlist_task_v4 = GNUNET_SCHEDULER_NO_TASK; + } + if (NULL != daemon_handle_v4) + { + MHD_stop_daemon (daemon_handle_v4); + daemon_handle_v4 = NULL; + } + if (NULL != daemon_handle_v6) + { + MHD_stop_daemon (daemon_handle_v6); + daemon_handle_v6 = NULL; + } + if (NULL != response) + { + MHD_destroy_response (response); + response = NULL; + } + if (NULL != notify) + { + GNUNET_PEERINFO_notify_cancel (notify); + notify = NULL; + } + if (NULL != builder) + { + GNUNET_PEERINFO_iterate_cancel (builder->pitr); + builder->pitr = NULL; + GNUNET_free_non_null (builder->data); + GNUNET_free (builder); + } + if (NULL != peerinfo) + { + GNUNET_PEERINFO_disconnect (peerinfo); + peerinfo = NULL; + } + cfg = NULL; + stats = NULL; + core = NULL; +} + +/* end of gnunet-daemon-hostlist_server.c */ diff --git a/src/hostlist/gnunet-daemon-hostlist_server.h b/src/hostlist/gnunet-daemon-hostlist_server.h new file mode 100644 index 000000000..bfceda336 --- /dev/null +++ b/src/hostlist/gnunet-daemon-hostlist_server.h @@ -0,0 +1,63 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file hostlist/gnunet-daemon-hostlist_server.h + * @brief hostlist support. Downloads HELLOs via HTTP. + * @author Christian Grothoff + */ + +#ifndef GNUNET_DAEMON_HOSTLIST_SERVER_H +#define GNUNET_DAEMON_HOSTLIST_SERVER_H + +#include "gnunet_core_service.h" +#include "gnunet_statistics_service.h" +#include "gnunet_util_lib.h" + + +/** + * Start server offering our hostlist. + * + * @param c configuration to use + * @param st statistics handle to use + * @param co core handle to use + * @param server_ch[OUT] set to handler for CORE connect events + * @param server_dh[OUT] set to handler for CORE disconnect events + * @param advertise #GNUNET_YES if we should advertise our hostlist + * @return #GNUNET_OK on success + */ +int +GNUNET_HOSTLIST_server_start (const struct GNUNET_CONFIGURATION_Handle *c, + struct GNUNET_STATISTICS_Handle *st, + struct GNUNET_CORE_Handle *core, + GNUNET_CORE_ConnectEventHandler *server_ch, + GNUNET_CORE_DisconnectEventHandler *server_dh, + int advertise); + + +/** + * Stop server offering our hostlist. + */ +void +GNUNET_HOSTLIST_server_stop (void); + + +#endif +/* end of gnunet-daemon-hostlist_server.h */ diff --git a/src/hostlist/hostlist-client.c b/src/hostlist/hostlist-client.c deleted file mode 100644 index d4096abc0..000000000 --- a/src/hostlist/hostlist-client.c +++ /dev/null @@ -1,1654 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2010 Christian Grothoff (and other contributing authors) - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. -*/ - -/** - * @file hostlist/hostlist-client.c - * @brief hostlist support. Downloads HELLOs via HTTP. - * @author Christian Grothoff - * @author Matthias Wachs - */ - -#include "platform.h" -#include "hostlist-client.h" -#include "gnunet_core_service.h" -#include "gnunet_hello_lib.h" -#include "gnunet_statistics_service.h" -#include "gnunet_transport_service.h" -#include "gnunet-daemon-hostlist.h" -#include -#include "gnunet_util_lib.h" - - -/** - * Number of connections that we must have to NOT download - * hostlists anymore. - */ -#define MIN_CONNECTIONS 4 - -/** - * Interval between two advertised hostlist tests - */ -#define TESTING_INTERVAL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) - -/** - * A single hostlist obtained by hostlist advertisements - */ -struct Hostlist -{ - /** - * previous entry, used to manage entries in a double linked list - */ - struct Hostlist *prev; - - /** - * next entry, used to manage entries in a double linked list - */ - struct Hostlist *next; - - /** - * URI where hostlist can be obtained - */ - const char *hostlist_uri; - - /** - * Value describing the quality of the hostlist, the bigger the better but (should) never < 0 - * used for deciding which hostlist is replaced if MAX_NUMBER_HOSTLISTS in data structure is reached - * intial value = HOSTLIST_INITIAL - * increased every successful download by HOSTLIST_SUCCESSFULL_DOWNLOAD - * increased every successful download by number of obtained HELLO messages - * decreased every failed download by HOSTLIST_SUCCESSFULL_DOWNLOAD - */ - uint64_t quality; - - /** - * Time the hostlist advertisement was recieved and the entry was created - */ - struct GNUNET_TIME_Absolute time_creation; - - /** - * Last time the hostlist was obtained - */ - struct GNUNET_TIME_Absolute time_last_usage; - - /** - * Number of HELLO messages obtained during last download - */ - uint32_t hello_count; - - /** - * Number of times the hostlist was successfully obtained - */ - uint32_t times_used; - -}; - - -/** - * Our configuration. - */ -static const struct GNUNET_CONFIGURATION_Handle *cfg; - -/** - * Statistics handle. - */ -static struct GNUNET_STATISTICS_Handle *stats; - -/** - * Transport handle. - */ -static struct GNUNET_TRANSPORT_Handle *transport; - -/** - * Proxy hostname or ip we are using (can be NULL). - */ -static char *proxy; - -/** - * Proxy username we are using (can be NULL). - */ -static char *proxy_username; - -/** - * Proxy password we are using (can be NULL). - */ -static char *proxy_password; - -/** - * Proxy type we are using (can be NULL). - */ -static curl_proxytype proxy_type; - -/** - * Number of bytes valid in 'download_buffer'. - */ -static size_t download_pos; - -/** - * Current URL that we are using. - */ -static char *current_url; - -/** - * Current CURL handle. - */ -static CURL *curl; - -/** - * Current multi-CURL handle. - */ -static CURLM *multi; - -/** - * How many bytes did we download from the current hostlist URL? - */ -static uint32_t stat_bytes_downloaded; - -/** - * Amount of time we wait between hostlist downloads. - */ -static struct GNUNET_TIME_Relative hostlist_delay; - -/** - * ID of the task, checking if hostlist download should take plate - */ -static GNUNET_SCHEDULER_TaskIdentifier ti_check_download; - -/** - * ID of the task downloading the hostlist - */ -static GNUNET_SCHEDULER_TaskIdentifier ti_download; - -/** - * ID of the task saving the hostlsit in a regular intervall - */ -static GNUNET_SCHEDULER_TaskIdentifier ti_saving_task; - -/** - * ID of the task called to initiate a download - */ -static GNUNET_SCHEDULER_TaskIdentifier ti_download_dispatcher_task; - -/** - * ID of the task controlling the locking between two hostlist tests - */ -static GNUNET_SCHEDULER_TaskIdentifier ti_testing_intervall_task; - -/** - * At what time MUST the current hostlist request be done? - */ -static struct GNUNET_TIME_Absolute end_time; - -/** - * Head of the linked list used to store hostlists - */ -static struct Hostlist *linked_list_head; - -/** - * Tail of the linked list used to store hostlists - */ -static struct Hostlist *linked_list_tail; - -/** - * Current hostlist used for downloading - */ -static struct Hostlist *current_hostlist; - -/** - * Size of the linke list used to store hostlists - */ -static unsigned int linked_list_size; - -/** - * Head of the linked list used to store hostlists - */ -static struct Hostlist *hostlist_to_test; - -/** - * Handle for our statistics GET operation. - */ -static struct GNUNET_STATISTICS_GetHandle *sget; - -/** - * Set to GNUNET_YES if the current URL had some problems. - */ -static int stat_bogus_url; - -/** - * Value controlling if a hostlist is tested at the moment - */ -static int stat_testing_hostlist; - -/** - * Value controlling if a hostlist testing is allowed at the moment - */ -static int stat_testing_allowed; - -/** - * Value controlling if a hostlist download is running at the moment - */ -static int stat_download_in_progress; - -/** - * Value saying if a preconfigured bootstrap server is used - */ -static unsigned int stat_use_bootstrap; - -/** - * Set if we are allowed to learn new hostlists and use them - */ -static int stat_learning; - -/** - * Value saying if hostlist download was successful - */ -static unsigned int stat_download_successful; - -/** - * Value saying how many valid HELLO messages were obtained during download - */ -static unsigned int stat_hellos_obtained; - -/** - * Number of active connections (according to core service). - */ -static unsigned int stat_connection_count; - - -/** - * Process downloaded bits by calling callback on each HELLO. - * - * @param ptr buffer with downloaded data - * @param size size of a record - * @param nmemb number of records downloaded - * @param ctx unused - * @return number of bytes that were processed (always size*nmemb) - */ -static size_t -callback_download (void *ptr, size_t size, size_t nmemb, void *ctx) -{ - static char download_buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1]; - const char *cbuf = ptr; - const struct GNUNET_MessageHeader *msg; - size_t total; - size_t cpy; - size_t left; - uint16_t msize; - - total = size * nmemb; - stat_bytes_downloaded += total; - if ((total == 0) || (stat_bogus_url)) - { - return total; /* ok, no data or bogus data */ - } - - GNUNET_STATISTICS_update (stats, - gettext_noop - ("# bytes downloaded from hostlist servers"), - (int64_t) total, GNUNET_NO); - left = total; - while ((left > 0) || (download_pos > 0)) - { - cpy = GNUNET_MIN (left, GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - download_pos); - memcpy (&download_buffer[download_pos], cbuf, cpy); - cbuf += cpy; - download_pos += cpy; - left -= cpy; - if (download_pos < sizeof (struct GNUNET_MessageHeader)) - { - GNUNET_assert (0 == left); - break; - } - msg = (const struct GNUNET_MessageHeader *) download_buffer; - msize = ntohs (msg->size); - if (msize < sizeof (struct GNUNET_MessageHeader)) - { - GNUNET_STATISTICS_update (stats, - gettext_noop - ("# invalid HELLOs downloaded from hostlist servers"), - 1, GNUNET_NO); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _("Invalid `%s' message received from hostlist at `%s'\n"), - "HELLO", current_url); - stat_hellos_obtained++; - stat_bogus_url = 1; - return total; - } - if (download_pos < msize) - { - GNUNET_assert (left == 0); - break; - } - if (GNUNET_HELLO_size ((const struct GNUNET_HELLO_Message *) msg) == msize) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Received valid `%s' message from hostlist server.\n", - "HELLO"); - GNUNET_STATISTICS_update (stats, - gettext_noop - ("# valid HELLOs downloaded from hostlist servers"), - 1, GNUNET_NO); - stat_hellos_obtained++; - GNUNET_TRANSPORT_offer_hello (transport, msg, NULL, NULL); - } - else - { - GNUNET_STATISTICS_update (stats, - gettext_noop - ("# invalid HELLOs downloaded from hostlist servers"), - 1, GNUNET_NO); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _("Invalid `%s' message received from hostlist at `%s'\n"), - "HELLO", current_url); - stat_bogus_url = GNUNET_YES; - stat_hellos_obtained++; - return total; - } - memmove (download_buffer, &download_buffer[msize], download_pos - msize); - download_pos -= msize; - } - return total; -} - - -/** - * Obtain a hostlist URL that we should use. - * - * @return NULL if there is no URL available - */ -static char * -get_bootstrap_server () -{ - char *servers; - char *ret; - size_t urls; - size_t pos; - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, "HOSTLIST", "SERVERS", - &servers)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, - "hostlist", "SERVERS"); - return NULL; - } - - urls = 0; - if (strlen (servers) > 0) - { - urls++; - pos = strlen (servers) - 1; - while (pos > 0) - { - if (servers[pos] == ' ') - urls++; - pos--; - } - } - if (urls == 0) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, - "hostlist", "SERVERS"); - GNUNET_free (servers); - return NULL; - } - - urls = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, urls) + 1; - pos = strlen (servers) - 1; - while (pos > 0) - { - if (servers[pos] == ' ') - { - urls--; - servers[pos] = '\0'; - } - if (urls == 0) - { - pos++; - break; - } - pos--; - } - ret = GNUNET_strdup (&servers[pos]); - GNUNET_free (servers); - return ret; -} - - -/** - * Method deciding if a preconfigured or advertisied hostlist is used on a 50:50 ratio - * @return uri to use, NULL if there is no URL available - */ -static char * -download_get_url () -{ - uint32_t index; - unsigned int counter; - struct Hostlist *pos; - - if (GNUNET_NO == stat_learning) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Using preconfigured bootstrap server\n"); - current_hostlist = NULL; - return get_bootstrap_server (); - } - - if ((GNUNET_YES == stat_testing_hostlist) && (NULL != hostlist_to_test)) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Testing new advertised hostlist if it is obtainable\n"); - current_hostlist = hostlist_to_test; - return GNUNET_strdup (hostlist_to_test->hostlist_uri); - } - - if ((GNUNET_YES == stat_use_bootstrap) || (linked_list_size == 0)) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Using preconfigured bootstrap server\n"); - current_hostlist = NULL; - return get_bootstrap_server (); - } - index = - GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, linked_list_size); - counter = 0; - pos = linked_list_head; - while (counter < index) - { - pos = pos->next; - counter++; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Using learned hostlist `%s'\n", - pos->hostlist_uri); - current_hostlist = pos; - return GNUNET_strdup (pos->hostlist_uri); -} - - -#define CURL_EASY_SETOPT(c, a, b) do { ret = curl_easy_setopt (c, a, b); if (CURLE_OK != ret) GNUNET_log(GNUNET_ERROR_TYPE_WARNING, _("%s failed at %s:%d: `%s'\n"), "curl_easy_setopt", __FILE__, __LINE__, curl_easy_strerror (ret)); } while (0) - - -/** - * Method to save hostlist to a file during hostlist client shutdown - * @param shutdown set if called because of shutdown, entries in linked list will be destroyed - */ -static void -save_hostlist_file (int shutdown); - - -/** - * add val2 to val1 with overflow check - * - * @param val1 value 1 - * @param val2 value 2 - * @return result - */ -static uint64_t -checked_add (uint64_t val1, uint64_t val2) -{ - static uint64_t temp; - static uint64_t maxv; - - maxv = 0; - maxv--; - - temp = val1 + val2; - if (temp < val1) - return maxv; - return temp; -} - - -/** - * Subtract val2 from val1 with underflow check - * - * @param val1 value 1 - * @param val2 value 2 - * @return result - */ -static uint64_t -checked_sub (uint64_t val1, uint64_t val2) -{ - if (val1 <= val2) - return 0; - return (val1 - val2); -} - - -/** - * Method to check if a URI is in hostlist linked list - * - * @param uri uri to check - * @return #GNUNET_YES if existing in linked list, #GNUNET_NO if not - */ -static int -linked_list_contains (const char *uri) -{ - struct Hostlist *pos; - - pos = linked_list_head; - while (pos != NULL) - { - if (0 == strcmp (pos->hostlist_uri, uri)) - return GNUNET_YES; - pos = pos->next; - } - return GNUNET_NO; -} - - -/** - * Method returning the hostlist element with the lowest quality in the datastore - * @return hostlist with lowest quality - */ -static struct Hostlist * -linked_list_get_lowest_quality () -{ - struct Hostlist *pos; - struct Hostlist *lowest; - - if (linked_list_size == 0) - return NULL; - lowest = linked_list_head; - pos = linked_list_head->next; - while (pos != NULL) - { - if (pos->quality < lowest->quality) - lowest = pos; - pos = pos->next; - } - return lowest; -} - - -/** - * Method to insert a hostlist into the datastore. If datastore - * contains maximum number of elements, the elements with lowest - * quality is dismissed - */ -static void -insert_hostlist () -{ - struct Hostlist *lowest_quality; - - if (MAX_NUMBER_HOSTLISTS <= linked_list_size) - { - /* No free entries available, replace existing entry */ - lowest_quality = linked_list_get_lowest_quality (); - GNUNET_assert (lowest_quality != NULL); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Removing hostlist with URI `%s' which has the worst quality of all (%llu)\n", - lowest_quality->hostlist_uri, - (unsigned long long) lowest_quality->quality); - GNUNET_CONTAINER_DLL_remove (linked_list_head, linked_list_tail, - lowest_quality); - linked_list_size--; - GNUNET_free (lowest_quality); - } - GNUNET_CONTAINER_DLL_insert (linked_list_head, linked_list_tail, - hostlist_to_test); - linked_list_size++; - GNUNET_STATISTICS_set (stats, gettext_noop ("# advertised hostlist URIs"), - linked_list_size, GNUNET_NO); - stat_testing_hostlist = GNUNET_NO; -} - - -/** - * Method updating hostlist statistics - */ -static void -update_hostlist () -{ - char *stat; - - if (((stat_use_bootstrap == GNUNET_NO) && (NULL != current_hostlist)) || - ((stat_testing_hostlist == GNUNET_YES) && (NULL != current_hostlist))) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Updating hostlist statics for URI `%s'\n", - current_hostlist->hostlist_uri); - current_hostlist->hello_count = stat_hellos_obtained; - current_hostlist->time_last_usage = GNUNET_TIME_absolute_get (); - current_hostlist->quality = - checked_add (current_hostlist->quality, - (stat_hellos_obtained * HOSTLIST_SUCCESSFUL_HELLO)); - if (GNUNET_YES == stat_download_successful) - { - current_hostlist->times_used++; - current_hostlist->quality = - checked_add (current_hostlist->quality, HOSTLIST_SUCCESSFUL_DOWNLOAD); - GNUNET_asprintf (&stat, gettext_noop ("# advertised URI `%s' downloaded"), - current_hostlist->hostlist_uri); - - GNUNET_STATISTICS_update (stats, stat, 1, GNUNET_YES); - GNUNET_free (stat); - } - else - current_hostlist->quality = - checked_sub (current_hostlist->quality, HOSTLIST_FAILED_DOWNLOAD); - } - current_hostlist = NULL; - /* Alternating the usage of preconfigured and learned hostlists */ - - if (stat_testing_hostlist == GNUNET_YES) - return; - - if (GNUNET_YES == stat_learning) - { - if (stat_use_bootstrap == GNUNET_YES) - stat_use_bootstrap = GNUNET_NO; - else - stat_use_bootstrap = GNUNET_YES; - } - else - stat_use_bootstrap = GNUNET_YES; -} - - -/** - * Clean up the state from the task that downloaded the - * hostlist and schedule the next task. - */ -static void -clean_up () -{ - CURLMcode mret; - - if ((stat_testing_hostlist == GNUNET_YES) && - (GNUNET_NO == stat_download_successful) && (NULL != hostlist_to_test)) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _ - ("Advertised hostlist with URI `%s' could not be downloaded. Advertised URI gets dismissed.\n"), - hostlist_to_test->hostlist_uri); - } - - if (stat_testing_hostlist == GNUNET_YES) - { - stat_testing_hostlist = GNUNET_NO; - } - if (NULL != hostlist_to_test) - { - GNUNET_free (hostlist_to_test); - hostlist_to_test = NULL; - } - - if (multi != NULL) - { - mret = curl_multi_remove_handle (multi, curl); - if (mret != CURLM_OK) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"), - "curl_multi_remove_handle", __FILE__, __LINE__, - curl_multi_strerror (mret)); - } - mret = curl_multi_cleanup (multi); - if (mret != CURLM_OK) - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"), - "curl_multi_cleanup", __FILE__, __LINE__, - curl_multi_strerror (mret)); - multi = NULL; - } - if (curl != NULL) - { - curl_easy_cleanup (curl); - curl = NULL; - } - GNUNET_free_non_null (current_url); - current_url = NULL; - stat_bytes_downloaded = 0; - stat_download_in_progress = GNUNET_NO; -} - - -/** - * Task that is run when we are ready to receive more data from the hostlist - * server. - * - * @param cls closure, unused - * @param tc task context, unused - */ -static void -task_download (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); - - -/** - * Ask CURL for the select set and then schedule the - * receiving task with the scheduler. - */ -static void -download_prepare () -{ - CURLMcode mret; - fd_set rs; - fd_set ws; - fd_set es; - int max; - struct GNUNET_NETWORK_FDSet *grs; - struct GNUNET_NETWORK_FDSet *gws; - long timeout; - struct GNUNET_TIME_Relative rtime; - - max = -1; - FD_ZERO (&rs); - FD_ZERO (&ws); - FD_ZERO (&es); - mret = curl_multi_fdset (multi, &rs, &ws, &es, &max); - if (mret != CURLM_OK) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"), - "curl_multi_fdset", __FILE__, __LINE__, - curl_multi_strerror (mret)); - clean_up (); - return; - } - mret = curl_multi_timeout (multi, &timeout); - if (mret != CURLM_OK) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"), - "curl_multi_timeout", __FILE__, __LINE__, - curl_multi_strerror (mret)); - clean_up (); - return; - } - rtime = - GNUNET_TIME_relative_min (GNUNET_TIME_absolute_get_remaining (end_time), - GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_MILLISECONDS, timeout)); - grs = GNUNET_NETWORK_fdset_create (); - gws = GNUNET_NETWORK_fdset_create (); - GNUNET_NETWORK_fdset_copy_native (grs, &rs, max + 1); - GNUNET_NETWORK_fdset_copy_native (gws, &ws, max + 1); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Scheduling task for hostlist download using cURL\n"); - ti_download = - GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, - rtime, grs, gws, - &task_download, multi); - GNUNET_NETWORK_fdset_destroy (gws); - GNUNET_NETWORK_fdset_destroy (grs); -} - - -/** - * Task that is run when we are ready to receive more data from the hostlist - * server. - * - * @param cls closure, unused - * @param tc task context, unused - */ -static void -task_download (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - int running; - struct CURLMsg *msg; - CURLMcode mret; - - ti_download = GNUNET_SCHEDULER_NO_TASK; - if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Shutdown requested while trying to download hostlist from `%s'\n", - current_url); - update_hostlist (); - clean_up (); - return; - } - if (0 == GNUNET_TIME_absolute_get_remaining (end_time).rel_value_us) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _("Timeout trying to download hostlist from `%s'\n"), - current_url); - update_hostlist (); - clean_up (); - return; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Ready for processing hostlist client request\n"); - do - { - running = 0; - if (stat_bytes_downloaded > MAX_BYTES_PER_HOSTLISTS) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _("Download limit of %u bytes exceeded, stopping download\n"), - MAX_BYTES_PER_HOSTLISTS); - clean_up (); - return; - } - mret = curl_multi_perform (multi, &running); - if (running == 0) - { - do - { - msg = curl_multi_info_read (multi, &running); - GNUNET_break (msg != NULL); - if (msg == NULL) - break; - switch (msg->msg) - { - case CURLMSG_DONE: - if ((msg->data.result != CURLE_OK) && - (msg->data.result != CURLE_GOT_NOTHING)) - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _("Download of hostlist from `%s' failed: `%s'\n"), - current_url, - curl_easy_strerror (msg->data.result)); - else - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _("Download of hostlist `%s' completed.\n"), - current_url); - stat_download_successful = GNUNET_YES; - update_hostlist (); - if (GNUNET_YES == stat_testing_hostlist) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _ - ("Adding successfully tested hostlist `%s' datastore.\n"), - current_url); - insert_hostlist (); - hostlist_to_test = NULL; - stat_testing_hostlist = GNUNET_NO; - } - } - clean_up (); - return; - default: - break; - } - - } - while ((running > 0)); - } - } - while (mret == CURLM_CALL_MULTI_PERFORM); - - if (mret != CURLM_OK) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("%s failed at %s:%d: `%s'\n"), - "curl_multi_perform", __FILE__, __LINE__, - curl_multi_strerror (mret)); - clean_up (); - } - download_prepare (); -} - - -/** - * Main function that will download a hostlist and process its - * data. - */ -static void -download_hostlist () -{ - CURLcode ret; - CURLMcode mret; - - - current_url = download_get_url (); - if (current_url == NULL) - return; - curl = curl_easy_init (); - multi = NULL; - if (curl == NULL) - { - GNUNET_break (0); - clean_up (); - return; - } - GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK, - _("Bootstrapping using hostlist at `%s'.\n"), current_url); - - stat_download_in_progress = GNUNET_YES; - stat_download_successful = GNUNET_NO; - stat_hellos_obtained = 0; - stat_bytes_downloaded = 0; - - GNUNET_STATISTICS_update (stats, - gettext_noop ("# hostlist downloads initiated"), 1, - GNUNET_NO); - if (proxy != NULL) - { - CURL_EASY_SETOPT (curl, CURLOPT_PROXY, proxy); - CURL_EASY_SETOPT (curl, CURLOPT_PROXYTYPE, proxy_type); - if (NULL != proxy_username) - CURL_EASY_SETOPT (curl, CURLOPT_PROXYUSERNAME, proxy_username); - if (NULL != proxy_password) - CURL_EASY_SETOPT (curl, CURLOPT_PROXYPASSWORD, proxy_password); - } - download_pos = 0; - stat_bogus_url = 0; - CURL_EASY_SETOPT (curl, CURLOPT_WRITEFUNCTION, &callback_download); - if (ret != CURLE_OK) - { - clean_up (); - return; - } - CURL_EASY_SETOPT (curl, CURLOPT_WRITEDATA, NULL); - if (ret != CURLE_OK) - { - clean_up (); - return; - } - CURL_EASY_SETOPT (curl, CURLOPT_FOLLOWLOCATION, 1); - CURL_EASY_SETOPT (curl, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS); - CURL_EASY_SETOPT (curl, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS); - CURL_EASY_SETOPT (curl, CURLOPT_MAXREDIRS, 4); - /* no need to abort if the above failed */ - CURL_EASY_SETOPT (curl, CURLOPT_URL, current_url); - if (ret != CURLE_OK) - { - clean_up (); - return; - } - CURL_EASY_SETOPT (curl, CURLOPT_FAILONERROR, 1); -#if 0 - CURL_EASY_SETOPT (curl, CURLOPT_VERBOSE, 1); -#endif - CURL_EASY_SETOPT (curl, CURLOPT_BUFFERSIZE, GNUNET_SERVER_MAX_MESSAGE_SIZE); - if (0 == strncmp (current_url, "http", 4)) - CURL_EASY_SETOPT (curl, CURLOPT_USERAGENT, "GNUnet"); - CURL_EASY_SETOPT (curl, CURLOPT_CONNECTTIMEOUT, 60L); - CURL_EASY_SETOPT (curl, CURLOPT_TIMEOUT, 60L); -#if 0 - /* this should no longer be needed; we're now single-threaded! */ - CURL_EASY_SETOPT (curl, CURLOPT_NOSIGNAL, 1); -#endif - multi = curl_multi_init (); - if (multi == NULL) - { - GNUNET_break (0); - /* clean_up (); */ - return; - } - mret = curl_multi_add_handle (multi, curl); - if (mret != CURLM_OK) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"), - "curl_multi_add_handle", __FILE__, __LINE__, - curl_multi_strerror (mret)); - mret = curl_multi_cleanup (multi); - if (mret != CURLM_OK) - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"), - "curl_multi_cleanup", __FILE__, __LINE__, - curl_multi_strerror (mret)); - multi = NULL; - clean_up (); - return; - } - end_time = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES); - download_prepare (); -} - - -static void -task_download_dispatcher (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - ti_download_dispatcher_task = GNUNET_SCHEDULER_NO_TASK; - if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) - return; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download is initiated...\n"); - if (GNUNET_NO == stat_download_in_progress) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download can start immediately...\n"); - download_hostlist (); - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Download in progess, have to wait...\n"); - ti_download_dispatcher_task = - GNUNET_SCHEDULER_add_delayed (WAITING_INTERVALL, - &task_download_dispatcher, NULL); - } -} - - -/** - * Task that checks if we should try to download a hostlist. - * If so, we initiate the download, otherwise we schedule - * this task again for a later time. - */ -static void -task_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - static int once; - struct GNUNET_TIME_Relative delay; - - ti_check_download = GNUNET_SCHEDULER_NO_TASK; - if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) - return; - if (stats == NULL) - { - curl_global_cleanup (); - return; /* in shutdown */ - } - if ( (stat_connection_count < MIN_CONNECTIONS) && - (GNUNET_SCHEDULER_NO_TASK == ti_download_dispatcher_task) ) - ti_download_dispatcher_task = - GNUNET_SCHEDULER_add_now (&task_download_dispatcher, NULL); - - delay = hostlist_delay; - if (0 == hostlist_delay.rel_value_us) - hostlist_delay = GNUNET_TIME_UNIT_SECONDS; - else - hostlist_delay = GNUNET_TIME_relative_multiply (hostlist_delay, 2); - if (hostlist_delay.rel_value_us > - GNUNET_TIME_UNIT_HOURS.rel_value_us * (1 + stat_connection_count)) - hostlist_delay = - GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, - (1 + stat_connection_count)); - GNUNET_STATISTICS_set (stats, - gettext_noop - ("# milliseconds between hostlist downloads"), - hostlist_delay.rel_value_us / 1000LL, - GNUNET_YES); - if (0 == once) - { - delay = GNUNET_TIME_UNIT_ZERO; - once = 1; - } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _("Have %u/%u connections. Will consider downloading hostlist in %s\n"), - stat_connection_count, MIN_CONNECTIONS, - GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES)); - ti_check_download = GNUNET_SCHEDULER_add_delayed (delay, &task_check, NULL); -} - - -/** - * This tasks sets hostlist testing to allowed after intervall between to testings is reached - * - * @param cls closure - * @param tc TaskContext - */ -static void -task_testing_intervall_reset (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - ti_testing_intervall_task = GNUNET_SCHEDULER_NO_TASK; - if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) - return; - stat_testing_allowed = GNUNET_OK; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Testing new hostlist advertisements is allowed again\n"); -} - - -/** - * Task that writes hostlist entries to a file on a regular base - * - * @param cls closure - * @param tc TaskContext - */ -static void -task_hostlist_saving (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - ti_saving_task = GNUNET_SCHEDULER_NO_TASK; - if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) - return; - save_hostlist_file (GNUNET_NO); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Hostlists will be saved to file again in %s\n", - GNUNET_STRINGS_relative_time_to_string(SAVING_INTERVALL, GNUNET_YES)); - ti_saving_task = - GNUNET_SCHEDULER_add_delayed (SAVING_INTERVALL, &task_hostlist_saving, - NULL); -} - - -/** - * Method called whenever a given peer connects. - * - * @param cls closure - * @param peer peer identity this notification is about - */ -static void -handler_connect (void *cls, const struct GNUNET_PeerIdentity *peer) -{ - GNUNET_assert (stat_connection_count < UINT_MAX); - stat_connection_count++; - GNUNET_STATISTICS_update (stats, gettext_noop ("# active connections"), 1, - GNUNET_NO); -} - - -/** - * Method called whenever a given peer disconnects. - * - * @param cls closure - * @param peer peer identity this notification is about - */ -static void -handler_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) -{ - GNUNET_assert (stat_connection_count > 0); - stat_connection_count--; - GNUNET_STATISTICS_update (stats, gettext_noop ("# active connections"), -1, - GNUNET_NO); -} - - -/** - * Method called whenever an advertisement message arrives. - * - * @param cls closure (always NULL) - * @param peer the peer sending the message - * @param message the actual message - * @return #GNUNET_OK to keep the connection open, - * #GNUNET_SYSERR to close it (signal serious error) - */ -static int -handler_advertisement (void *cls, const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_MessageHeader *message) -{ - size_t size; - size_t uri_size; - const struct GNUNET_MessageHeader *incoming; - const char *uri; - struct Hostlist *hostlist; - - GNUNET_assert (ntohs (message->type) == - GNUNET_MESSAGE_TYPE_HOSTLIST_ADVERTISEMENT); - size = ntohs (message->size); - if (size <= sizeof (struct GNUNET_MessageHeader)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - incoming = (const struct GNUNET_MessageHeader *) message; - uri = (const char *) &incoming[1]; - uri_size = size - sizeof (struct GNUNET_MessageHeader); - if (uri[uri_size - 1] != '\0') - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Hostlist client recieved advertisement from `%s' containing URI `%s'\n", - GNUNET_i2s (peer), uri); - if (GNUNET_NO != linked_list_contains (uri)) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "URI `%s' is already known\n", uri); - return GNUNET_OK; - } - - if (GNUNET_NO == stat_testing_allowed) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Currently not accepting new advertisements: interval between to advertisements is not reached\n"); - return GNUNET_SYSERR; - } - if (GNUNET_YES == stat_testing_hostlist) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Currently not accepting new advertisements: we are already testing a hostlist\n"); - return GNUNET_SYSERR; - } - - hostlist = GNUNET_malloc (sizeof (struct Hostlist) + uri_size); - hostlist->hostlist_uri = (const char *) &hostlist[1]; - memcpy (&hostlist[1], uri, uri_size); - hostlist->time_creation = GNUNET_TIME_absolute_get (); - hostlist->quality = HOSTLIST_INITIAL; - hostlist_to_test = hostlist; - - stat_testing_hostlist = GNUNET_YES; - stat_testing_allowed = GNUNET_NO; - ti_testing_intervall_task = - GNUNET_SCHEDULER_add_delayed (TESTING_INTERVAL, - &task_testing_intervall_reset, NULL); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Testing new hostlist advertisements is locked for the next %s\n", - GNUNET_STRINGS_relative_time_to_string (TESTING_INTERVAL, - GNUNET_YES)); - - ti_download_dispatcher_task = - GNUNET_SCHEDULER_add_now (&task_download_dispatcher, NULL); - - return GNUNET_OK; -} - - -/** - * Continuation called by the statistics code once - * we go the stat. Initiates hostlist download scheduling. - * - * @param cls closure - * @param success #GNUNET_OK if statistics were - * successfully obtained, #GNUNET_SYSERR if not. - */ -static void -primary_task (void *cls, int success) -{ - sget = NULL; - GNUNET_assert (stats != NULL); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Statistics request done, scheduling hostlist download\n"); - ti_check_download = GNUNET_SCHEDULER_add_now (&task_check, NULL); -} - - -/** - * We've received the previous delay value from statistics. Remember it. - * - * @param cls NULL, unused - * @param subsystem should be "hostlist", unused - * @param name will be "milliseconds between hostlist downloads", unused - * @param value previous delay value, in milliseconds (!) - * @param is_persistent unused, will be GNUNET_YES - */ -static int -process_stat (void *cls, const char *subsystem, const char *name, - uint64_t value, int is_persistent) -{ - hostlist_delay.rel_value_us = value * 1000LL; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Initial time between hostlist downloads is %s\n", - GNUNET_STRINGS_relative_time_to_string (hostlist_delay, GNUNET_YES)); - return GNUNET_OK; -} - - -/** - * Method to load persistent hostlist file during hostlist client startup - */ -static void -load_hostlist_file () -{ - char *filename; - char *uri; - char *emsg; - struct Hostlist *hostlist; - uint32_t times_used; - uint32_t hellos_returned; - uint64_t quality; - uint64_t last_used; - uint64_t created; - uint32_t counter; - - uri = NULL; - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_filename (cfg, "HOSTLIST", "HOSTLISTFILE", - &filename)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, - "hostlist", "HOSTLISTFILE"); - return; - } - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _("Loading saved hostlist entries from file `%s' \n"), - filename); - if (GNUNET_NO == GNUNET_DISK_file_test (filename)) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _("Hostlist file `%s' does not exist\n"), filename); - GNUNET_free (filename); - return; - } - - struct GNUNET_BIO_ReadHandle *rh = GNUNET_BIO_read_open (filename); - - if (NULL == rh) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _ - ("Could not open file `%s' for reading to load hostlists: %s\n"), - filename, STRERROR (errno)); - GNUNET_free (filename); - return; - } - - counter = 0; - while ((GNUNET_OK == GNUNET_BIO_read_string (rh, "url", &uri, MAX_URL_LEN)) && - (NULL != uri) && (GNUNET_OK == GNUNET_BIO_read_int32 (rh, ×_used)) - && (GNUNET_OK == GNUNET_BIO_read_int64 (rh, &quality)) && - (GNUNET_OK == GNUNET_BIO_read_int64 (rh, &last_used)) && - (GNUNET_OK == GNUNET_BIO_read_int64 (rh, &created)) && - (GNUNET_OK == GNUNET_BIO_read_int32 (rh, &hellos_returned))) - { - hostlist = GNUNET_malloc (sizeof (struct Hostlist) + strlen (uri) + 1); - hostlist->hello_count = hellos_returned; - hostlist->hostlist_uri = (const char *) &hostlist[1]; - memcpy (&hostlist[1], uri, strlen (uri) + 1); - hostlist->quality = quality; - hostlist->time_creation.abs_value_us = created; - hostlist->time_last_usage.abs_value_us = last_used; - GNUNET_CONTAINER_DLL_insert (linked_list_head, linked_list_tail, hostlist); - linked_list_size++; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Added hostlist entry eith URI `%s' \n", - hostlist->hostlist_uri); - GNUNET_free (uri); - uri = NULL; - counter++; - if (counter >= MAX_NUMBER_HOSTLISTS) - break; - } - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("%u hostlist URIs loaded from file\n"), - counter); - GNUNET_STATISTICS_set (stats, gettext_noop ("# hostlist URIs read from file"), - counter, GNUNET_YES); - GNUNET_STATISTICS_set (stats, gettext_noop ("# advertised hostlist URIs"), - linked_list_size, GNUNET_NO); - - GNUNET_free_non_null (uri); - emsg = NULL; - (void) GNUNET_BIO_read_close (rh, &emsg); - if (emsg != NULL) - GNUNET_free (emsg); - GNUNET_free (filename); -} - - -/** - * Method to save persistent hostlist file during hostlist client shutdown - * @param shutdown set if called because of shutdown, entries in linked list will be destroyed - */ -static void -save_hostlist_file (int shutdown) -{ - char *filename; - struct Hostlist *pos; - struct GNUNET_BIO_WriteHandle *wh; - int ok; - uint32_t counter; - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_filename (cfg, "HOSTLIST", "HOSTLISTFILE", - &filename)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, - "hostlist", "HOSTLISTFILE"); - return; - } - if (GNUNET_SYSERR == GNUNET_DISK_directory_create_for_file (filename)) - { - GNUNET_free (filename); - return; - } - wh = GNUNET_BIO_write_open (filename); - if (NULL == wh) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _ - ("Could not open file `%s' for writing to save hostlists: %s\n"), - filename, STRERROR (errno)); - GNUNET_free (filename); - return; - } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Writing %u hostlist URIs to `%s'\n"), - linked_list_size, filename); - /* add code to write hostlists to file using bio */ - ok = GNUNET_YES; - counter = 0; - while (NULL != (pos = linked_list_head)) - { - if (GNUNET_YES == shutdown) - { - GNUNET_CONTAINER_DLL_remove (linked_list_head, linked_list_tail, pos); - linked_list_size--; - } - if (GNUNET_YES == ok) - { - if ((GNUNET_OK != GNUNET_BIO_write_string (wh, pos->hostlist_uri)) || - (GNUNET_OK != GNUNET_BIO_write_int32 (wh, pos->times_used)) || - (GNUNET_OK != GNUNET_BIO_write_int64 (wh, pos->quality)) || - (GNUNET_OK != - GNUNET_BIO_write_int64 (wh, pos->time_last_usage.abs_value_us)) || - (GNUNET_OK != - GNUNET_BIO_write_int64 (wh, pos->time_creation.abs_value_us)) || - (GNUNET_OK != GNUNET_BIO_write_int32 (wh, pos->hello_count))) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _("Error writing hostlist URIs to file `%s'\n"), filename); - ok = GNUNET_NO; - } - } - - if (GNUNET_YES == shutdown) - GNUNET_free (pos); - counter++; - if (counter >= MAX_NUMBER_HOSTLISTS) - break; - } - GNUNET_STATISTICS_set (stats, - gettext_noop ("# hostlist URIs written to file"), - counter, GNUNET_YES); - - if (GNUNET_OK != GNUNET_BIO_write_close (wh)) - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _("Error writing hostlist URIs to file `%s'\n"), filename); - GNUNET_free (filename); -} - - -/** - * Start downloading hostlists from hostlist servers as necessary. - */ -int -GNUNET_HOSTLIST_client_start (const struct GNUNET_CONFIGURATION_Handle *c, - struct GNUNET_STATISTICS_Handle *st, - GNUNET_CORE_ConnectEventHandler *ch, - GNUNET_CORE_DisconnectEventHandler *dh, - GNUNET_CORE_MessageCallback *msgh, int learn) -{ - char *filename; - char *proxytype_str; - int result; - - GNUNET_assert (NULL != st); - if (0 != curl_global_init (CURL_GLOBAL_WIN32)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - transport = GNUNET_TRANSPORT_connect (c, NULL, NULL, NULL, NULL, NULL); - if (NULL == transport) - { - curl_global_cleanup (); - return GNUNET_SYSERR; - } - cfg = c; - stats = st; - - /* Read proxy configuration */ - if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, - "HOSTLIST", "PROXY", &proxy)) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Found proxy host: `%s'\n", - proxy); - /* proxy username */ - if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, - "HOSTLIST", "PROXY_USERNAME", &proxy_username)) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Found proxy username name: `%s'\n", - proxy_username); - } - - /* proxy password */ - if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, - "HOSTLIST", "PROXY_PASSWORD", &proxy_password)) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Found proxy password name: `%s'\n", - proxy_password); - } - - /* proxy type */ - if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, - "HOSTLIST", "PROXY_TYPE", &proxytype_str)) - { - GNUNET_STRINGS_utf8_toupper (proxytype_str, proxytype_str); - - proxy_type = CURLPROXY_HTTP; - if (0 == strcmp(proxytype_str, "HTTP")) - proxy_type = CURLPROXY_HTTP; - else if (0 == strcmp(proxytype_str, "HTTP_1_0")) - proxy_type = CURLPROXY_HTTP_1_0; - else if (0 == strcmp(proxytype_str, "SOCKS4")) - proxy_type = CURLPROXY_SOCKS4; - else if (0 == strcmp(proxytype_str, "SOCKS5")) - proxy_type = CURLPROXY_SOCKS5; - else if (0 == strcmp(proxytype_str, "SOCKS4A")) - proxy_type = CURLPROXY_SOCKS4A; - else if (0 == strcmp(proxytype_str, "SOCKS5_HOSTNAME")) - proxy_type = CURLPROXY_SOCKS5_HOSTNAME ; - else - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Invalid proxy type: `%s', disabling proxy! Check configuration!\n"), - proxytype_str); - GNUNET_free (proxytype_str); - - GNUNET_free (proxy); - proxy = NULL; - GNUNET_free_non_null (proxy_username); - proxy_username = NULL; - GNUNET_free_non_null (proxy_password); - proxy_password = NULL; - - return GNUNET_SYSERR; - } - } - GNUNET_free_non_null (proxytype_str); - } - - stat_learning = learn; - *ch = &handler_connect; - *dh = &handler_disconnect; - linked_list_head = NULL; - linked_list_tail = NULL; - stat_use_bootstrap = GNUNET_YES; - stat_testing_hostlist = GNUNET_NO; - stat_testing_allowed = GNUNET_YES; - - if (GNUNET_YES == stat_learning) - { - *msgh = &handler_advertisement; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _("Learning is enabled on this peer\n")); - load_hostlist_file (); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Hostlists will be saved to file again in %s\n", - GNUNET_STRINGS_relative_time_to_string (SAVING_INTERVALL, GNUNET_YES)); - ti_saving_task = - GNUNET_SCHEDULER_add_delayed (SAVING_INTERVALL, &task_hostlist_saving, - NULL); - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _("Learning is not enabled on this peer\n")); - *msgh = NULL; - if (GNUNET_OK == - GNUNET_CONFIGURATION_get_value_filename (cfg, "HOSTLIST", - "HOSTLISTFILE", &filename)) - { - if (GNUNET_YES == GNUNET_DISK_file_test (filename)) - { - result = remove (filename); - if (result == 0) - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _ - ("Since learning is not enabled on this peer, hostlist file `%s' was removed\n"), - filename); - else - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Hostlist file `%s' could not be removed\n"), filename); - } - } - GNUNET_free (filename); - } - sget = GNUNET_STATISTICS_get (stats, "hostlist", - gettext_noop - ("# milliseconds between hostlist downloads"), - GNUNET_TIME_UNIT_MINUTES, &primary_task, &process_stat, - NULL); - return GNUNET_OK; -} - - -/** - * Stop downloading hostlists from hostlist servers as necessary. - */ -void -GNUNET_HOSTLIST_client_stop () -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hostlist client shutdown\n"); - if (NULL != sget) - { - GNUNET_STATISTICS_get_cancel (sget); - sget = NULL; - } - stats = NULL; - if (GNUNET_YES == stat_learning) - save_hostlist_file (GNUNET_YES); - if (ti_saving_task != GNUNET_SCHEDULER_NO_TASK) - { - GNUNET_SCHEDULER_cancel (ti_saving_task); - ti_saving_task = GNUNET_SCHEDULER_NO_TASK; - } - - if (ti_download_dispatcher_task != GNUNET_SCHEDULER_NO_TASK) - { - GNUNET_SCHEDULER_cancel (ti_download_dispatcher_task); - ti_download_dispatcher_task = GNUNET_SCHEDULER_NO_TASK; - } - if (ti_testing_intervall_task != GNUNET_SCHEDULER_NO_TASK) - { - GNUNET_SCHEDULER_cancel (ti_testing_intervall_task); - ti_testing_intervall_task = GNUNET_SCHEDULER_NO_TASK; - } - if (ti_download != GNUNET_SCHEDULER_NO_TASK) - { - GNUNET_SCHEDULER_cancel (ti_download); - ti_download = GNUNET_SCHEDULER_NO_TASK; - } - if (ti_check_download != GNUNET_SCHEDULER_NO_TASK) - { - GNUNET_SCHEDULER_cancel (ti_check_download); - ti_check_download = GNUNET_SCHEDULER_NO_TASK; - curl_global_cleanup (); - } - if (transport != NULL) - { - GNUNET_TRANSPORT_disconnect (transport); - transport = NULL; - } - GNUNET_free_non_null (proxy); - proxy = NULL; - GNUNET_free_non_null (proxy_username); - proxy_username = NULL; - GNUNET_free_non_null (proxy_password); - proxy_password = NULL; - - cfg = NULL; -} - -/* end of hostlist-client.c */ diff --git a/src/hostlist/hostlist-client.h b/src/hostlist/hostlist-client.h deleted file mode 100644 index 3def865e4..000000000 --- a/src/hostlist/hostlist-client.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2009 Christian Grothoff (and other contributing authors) - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. -*/ - -/** - * @file hostlist/hostlist-client.h - * @brief hostlist support. Downloads HELLOs via HTTP. - * @author Christian Grothoff - */ - -#ifndef HOSTLIST_CLIENT_H -#define HOSTLIST_CLIENT_H - -#include "gnunet_core_service.h" -#include "gnunet_statistics_service.h" -#include "gnunet_util_lib.h" -#include "gnunet_time_lib.h" - -/** - * Maximum number of hostlist that are saved - */ -#define MAX_NUMBER_HOSTLISTS 30 - -/** - * Time intervall hostlists are saved to disk - */ -#define SAVING_INTERVALL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30) - -/** - * Time interval between two hostlist tests - */ -#define TESTING_INTERVALL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3) - -/** - * Time interval for download dispatcher before a download is re-scheduled - */ -#define WAITING_INTERVALL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1) - -/** - * Defines concerning the hostlist quality metric - */ - -/** - * Initial quality of a new created hostlist - */ -#define HOSTLIST_INITIAL 10000 - -/** - * Value subtracted each time a hostlist download fails - */ -#define HOSTLIST_FAILED_DOWNLOAD 100 - -/** - * Value added each time a hostlist download is successful - */ -#define HOSTLIST_SUCCESSFUL_DOWNLOAD 100 - -/** - * Value added for each valid HELLO recived during a hostlist download - */ -#define HOSTLIST_SUCCESSFUL_HELLO 1 - - - -/** - * Start downloading hostlists from hostlist servers as necessary. - * - * @param c the configuration to use - * @param st hande for publishing statistics - * @param ch set to handler for connect notifications - * @param dh set to handler for disconnect notifications - * @param msgh set to handler for message handler notifications - * @param learn set if client is learning new hostlists - * @return GNUNET_OK on success - */ -int -GNUNET_HOSTLIST_client_start (const struct GNUNET_CONFIGURATION_Handle *c, - struct GNUNET_STATISTICS_Handle *st, - GNUNET_CORE_ConnectEventHandler *ch, - GNUNET_CORE_DisconnectEventHandler *dh, - GNUNET_CORE_MessageCallback *msgh, int learn); - - -/** - * Stop downloading hostlists from hostlist servers as necessary. - */ -void -GNUNET_HOSTLIST_client_stop (void); - - -#endif -/* end of hostlist-client.h */ diff --git a/src/hostlist/hostlist-server.c b/src/hostlist/hostlist-server.c deleted file mode 100644 index adf9359c6..000000000 --- a/src/hostlist/hostlist-server.c +++ /dev/null @@ -1,802 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2008, 2009, 2010, 2014 Christian Grothoff (and other contributing authors) - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. -*/ - -/** - * @file hostlist/hostlist-server.c - * @author Christian Grothoff, Matthias Wachs, David Barksdale - * @brief application to provide an integrated hostlist HTTP server - */ - -#include "platform.h" -#include -#include "hostlist-server.h" -#include "gnunet_hello_lib.h" -#include "gnunet_peerinfo_service.h" -#include "gnunet-daemon-hostlist.h" -#include "gnunet_resolver_service.h" - - -/** - * Handle to the HTTP server as provided by libmicrohttpd for IPv6. - */ -static struct MHD_Daemon *daemon_handle_v6; - -/** - * Handle to the HTTP server as provided by libmicrohttpd for IPv4. - */ -static struct MHD_Daemon *daemon_handle_v4; - -/** - * Our configuration. - */ -static const struct GNUNET_CONFIGURATION_Handle *cfg; - -/** - * For keeping statistics. - */ -static struct GNUNET_STATISTICS_Handle *stats; - -/** - * Handle to the core service (NULL until we've connected to it). - */ -static struct GNUNET_CORE_Handle *core; - -/** - * Handle to the peerinfo notify service (NULL until we've connected to it). - */ -static struct GNUNET_PEERINFO_NotifyContext *notify; - -/** - * Our primary task for IPv4. - */ -static GNUNET_SCHEDULER_TaskIdentifier hostlist_task_v4; - -/** - * Our primary task for IPv6. - */ -static GNUNET_SCHEDULER_TaskIdentifier hostlist_task_v6; - -/** - * Our canonical response. - */ -static struct MHD_Response *response; - -/** - * Handle for accessing peerinfo service. - */ -static struct GNUNET_PEERINFO_Handle *peerinfo; - -/** - * Set if we are allowed to advertise our hostlist to others. - */ -static int advertising; - -/** - * Buffer for the hostlist address - */ -static char *hostlist_uri; - - -/** - * Context for host processor. - */ -struct HostSet -{ - unsigned int size; - - char *data; - - struct GNUNET_PEERINFO_IteratorContext *pitr; -}; - - -/** - * NULL if we are not currenlty iterating over peer information. - */ -static struct HostSet *builder; - - -/** - * Function that assembles our response. - */ -static void -finish_response () -{ - if (NULL != response) - MHD_destroy_response (response); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Creating hostlist response with %u bytes\n", - (unsigned int) builder->size); - response = - MHD_create_response_from_data (builder->size, builder->data, MHD_YES, - MHD_NO); - if ((NULL == daemon_handle_v4) && (NULL == daemon_handle_v6)) - { - MHD_destroy_response (response); - response = NULL; - } - GNUNET_STATISTICS_set (stats, gettext_noop ("bytes in hostlist"), - builder->size, GNUNET_YES); - GNUNET_free (builder); - builder = NULL; -} - - -/** - * Set @a cls to #GNUNET_YES (we have an address!). - * - * @param cls closure, an `int *` - * @param address the address (ignored) - * @param expiration expiration time (call is ignored if this is in the past) - * @return #GNUNET_SYSERR to stop iterating (unless expiration has occured) - */ -static int -check_has_addr (void *cls, const struct GNUNET_HELLO_Address *address, - struct GNUNET_TIME_Absolute expiration) -{ - int *arg = cls; - - if (0 == GNUNET_TIME_absolute_get_remaining (expiration).rel_value_us) - { - GNUNET_STATISTICS_update (stats, - gettext_noop ("expired addresses encountered"), 1, - GNUNET_YES); - return GNUNET_YES; /* ignore this address */ - } - *arg = GNUNET_YES; - return GNUNET_SYSERR; -} - - -/** - * Callback that processes each of the known HELLOs for the - * hostlist response construction. - */ -static void -host_processor (void *cls, - const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_HELLO_Message *hello, - const char *err_msg) -{ - size_t old; - size_t s; - int has_addr; - - if (NULL != err_msg) - { - GNUNET_assert (NULL == peer); - builder->pitr = NULL; - GNUNET_free_non_null (builder->data); - GNUNET_free (builder); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _("Error in communication with PEERINFO service: %s\n"), - err_msg); - return; - } - if (NULL == peer) - { - builder->pitr = NULL; - finish_response (); - return; - } - if (NULL == hello) - return; - has_addr = GNUNET_NO; - GNUNET_HELLO_iterate_addresses (hello, GNUNET_NO, &check_has_addr, &has_addr); - if (GNUNET_NO == has_addr) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "HELLO for peer `%4s' has no address, not suitable for hostlist!\n", - GNUNET_i2s (peer)); - GNUNET_STATISTICS_update (stats, - gettext_noop - ("HELLOs without addresses encountered (ignored)"), - 1, GNUNET_NO); - return; - } - old = builder->size; - s = GNUNET_HELLO_size (hello); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Received %u bytes of `%s' from peer `%s' for hostlist.\n", - (unsigned int) s, "HELLO", GNUNET_i2s (peer)); - if ((old + s >= GNUNET_MAX_MALLOC_CHECKED) || - (old + s >= MAX_BYTES_PER_HOSTLISTS)) - { - GNUNET_STATISTICS_update (stats, - gettext_noop - ("bytes not included in hostlist (size limit)"), - s, GNUNET_NO); - return; /* too large, skip! */ - } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Adding peer `%s' to hostlist (%u bytes)\n", GNUNET_i2s (peer), - (unsigned int) s); - GNUNET_array_grow (builder->data, builder->size, old + s); - memcpy (&builder->data[old], hello, s); -} - - - -/** - * Hostlist access policy (very permissive, allows everything). - */ -static int -accept_policy_callback (void *cls, const struct sockaddr *addr, - socklen_t addrlen) -{ - if (NULL == response) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Received request for hostlist, but I am not yet ready; rejecting!\n"); - return MHD_NO; - } - return MHD_YES; /* accept all */ -} - - -/** - * Add headers to a request indicating that we allow Cross-Origin Resource - * Sharing. - */ -static void -add_cors_headers(struct MHD_Response *response) -{ - MHD_add_response_header (response, - "Access-Control-Allow-Origin", - "*"); - MHD_add_response_header (response, - "Access-Control-Allow-Methods", - "GET, OPTIONS"); - MHD_add_response_header (response, - "Access-Control-Max-Age", - "86400"); -} - - -/** - * Main request handler. - */ -static int -access_handler_callback (void *cls, struct MHD_Connection *connection, - const char *url, const char *method, - const char *version, const char *upload_data, - size_t * upload_data_size, void **con_cls) -{ - static int dummy; - - /* CORS pre-flight request */ - if (0 == strcmp (MHD_HTTP_METHOD_OPTIONS, method)) - { - struct MHD_Response *options_response; - int rc; - - options_response = MHD_create_response_from_buffer (0, NULL, - MHD_RESPMEM_PERSISTENT); - add_cors_headers(options_response); - rc = MHD_queue_response (connection, MHD_HTTP_OK, options_response); - MHD_destroy_response (options_response); - return rc; - } - if (0 != strcmp (method, MHD_HTTP_METHOD_GET)) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _("Refusing `%s' request to hostlist server\n"), method); - GNUNET_STATISTICS_update (stats, - gettext_noop - ("hostlist requests refused (not HTTP GET)"), 1, - GNUNET_YES); - return MHD_NO; - } - if (NULL == *con_cls) - { - (*con_cls) = &dummy; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Sending 100 CONTINUE reply\n"); - return MHD_YES; /* send 100 continue */ - } - if (0 != *upload_data_size) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _("Refusing `%s' request with %llu bytes of upload data\n"), - method, (unsigned long long) *upload_data_size); - GNUNET_STATISTICS_update (stats, - gettext_noop - ("hostlist requests refused (upload data)"), 1, - GNUNET_YES); - return MHD_NO; /* do not support upload data */ - } - if (NULL == response) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _("Could not handle hostlist request since I do not have a response yet\n")); - GNUNET_STATISTICS_update (stats, - gettext_noop - ("hostlist requests refused (not ready)"), 1, - GNUNET_YES); - return MHD_NO; /* internal error, no response yet */ - } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _("Received request for our hostlist\n")); - GNUNET_STATISTICS_update (stats, - gettext_noop ("hostlist requests processed"), - 1, GNUNET_YES); - add_cors_headers (response); - return MHD_queue_response (connection, MHD_HTTP_OK, response); -} - - -/** - * Handler called by core when core is ready to transmit message - * @param cls closure - * @param size size of buffer to copy message to - * @param buf buffer to copy message to - */ -static size_t -adv_transmit_ready (void *cls, size_t size, void *buf) -{ - static uint64_t hostlist_adv_count; - size_t transmission_size; - size_t uri_size; /* Including \0 termination! */ - struct GNUNET_MessageHeader header; - char *cbuf; - - if (NULL == buf) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Transmission failed, buffer invalid!\n"); - return 0; - } - uri_size = strlen (hostlist_uri) + 1; - transmission_size = sizeof (struct GNUNET_MessageHeader) + uri_size; - header.type = htons (GNUNET_MESSAGE_TYPE_HOSTLIST_ADVERTISEMENT); - header.size = htons (transmission_size); - GNUNET_assert (size >= transmission_size); - memcpy (buf, &header, sizeof (struct GNUNET_MessageHeader)); - cbuf = buf; - memcpy (&cbuf[sizeof (struct GNUNET_MessageHeader)], hostlist_uri, uri_size); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Sent advertisement message: Copied %u bytes into buffer!\n", - (unsigned int) transmission_size); - hostlist_adv_count++; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " # Sent advertisement message: %u\n", - hostlist_adv_count); - GNUNET_STATISTICS_update (stats, - gettext_noop ("# hostlist advertisements send"), 1, - GNUNET_NO); - return transmission_size; -} - - -/** - * Method called whenever a given peer connects. - * - * @param cls closure - * @param peer peer identity this notification is about - */ -static void -connect_handler (void *cls, const struct GNUNET_PeerIdentity *peer) -{ - size_t size; - - if (!advertising) - return; - if (NULL == hostlist_uri) - return; - size = strlen (hostlist_uri) + 1; - if (size + sizeof (struct GNUNET_MessageHeader) >= - GNUNET_SERVER_MAX_MESSAGE_SIZE) - { - GNUNET_break (0); - return; - } - size += sizeof (struct GNUNET_MessageHeader); - if (NULL == core) - { - GNUNET_break (0); - return; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Asked core to transmit advertisement message with a size of %u bytes to peer `%s'\n", - size, GNUNET_i2s (peer)); - if (NULL == - GNUNET_CORE_notify_transmit_ready (core, GNUNET_YES, - GNUNET_CORE_PRIO_BEST_EFFORT, - GNUNET_ADV_TIMEOUT, peer, size, - &adv_transmit_ready, NULL)) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _("Advertisement message could not be queued by core\n")); - } -} - - -/** - * Method called whenever a given peer disconnects. - * - * @param cls closure - * @param peer peer identity this notification is about - */ -static void -disconnect_handler (void *cls, const struct GNUNET_PeerIdentity *peer) -{ - /* nothing to do */ -} - - -/** - * PEERINFO calls this function to let us know about a possible peer - * that we might want to connect to. - * - * @param cls closure (not used) - * @param peer potential peer to connect to - * @param hello HELLO for this peer (or NULL) - * @param err_msg NULL if successful, otherwise contains error message - */ -static void -process_notify (void *cls, const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_HELLO_Message *hello, const char *err_msg) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Peerinfo is notifying us to rebuild our hostlist\n"); - if (NULL != err_msg) - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _("Error in communication with PEERINFO service: %s\n"), - err_msg); - if (NULL != builder) - { - /* restart re-build already in progress ... */ - GNUNET_PEERINFO_iterate_cancel (builder->pitr); - GNUNET_free_non_null (builder->data); - builder->size = 0; - builder->data = NULL; - } - else - { - builder = GNUNET_new (struct HostSet); - } - GNUNET_assert (NULL != peerinfo); - builder->pitr = - GNUNET_PEERINFO_iterate (peerinfo, GNUNET_NO, NULL, GNUNET_TIME_UNIT_MINUTES, - &host_processor, NULL); -} - - -/** - * Function that queries MHD's select sets and - * starts the task waiting for them. - */ -static GNUNET_SCHEDULER_TaskIdentifier -prepare_daemon (struct MHD_Daemon *daemon_handle); - - -/** - * Call MHD to process pending requests and then go back - * and schedule the next run. - */ -static void -run_daemon (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct MHD_Daemon *daemon_handle = cls; - - if (daemon_handle == daemon_handle_v4) - hostlist_task_v4 = GNUNET_SCHEDULER_NO_TASK; - else - hostlist_task_v6 = GNUNET_SCHEDULER_NO_TASK; - - if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) - return; - GNUNET_assert (MHD_YES == MHD_run (daemon_handle)); - if (daemon_handle == daemon_handle_v4) - hostlist_task_v4 = prepare_daemon (daemon_handle); - else - hostlist_task_v6 = prepare_daemon (daemon_handle); -} - - -/** - * Function that queries MHD's select sets and - * starts the task waiting for them. - */ -static GNUNET_SCHEDULER_TaskIdentifier -prepare_daemon (struct MHD_Daemon *daemon_handle) -{ - GNUNET_SCHEDULER_TaskIdentifier ret; - fd_set rs; - fd_set ws; - fd_set es; - struct GNUNET_NETWORK_FDSet *wrs; - struct GNUNET_NETWORK_FDSet *wws; - int max; - MHD_UNSIGNED_LONG_LONG timeout; - int haveto; - struct GNUNET_TIME_Relative tv; - - FD_ZERO (&rs); - FD_ZERO (&ws); - FD_ZERO (&es); - wrs = GNUNET_NETWORK_fdset_create (); - wws = GNUNET_NETWORK_fdset_create (); - max = -1; - GNUNET_assert (MHD_YES == MHD_get_fdset (daemon_handle, &rs, &ws, &es, &max)); - haveto = MHD_get_timeout (daemon_handle, &timeout); - if (haveto == MHD_YES) - tv.rel_value_us = (uint64_t) timeout * 1000LL; - else - tv = GNUNET_TIME_UNIT_FOREVER_REL; - GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1); - GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1); - ret = - GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH, - tv, wrs, wws, - &run_daemon, daemon_handle); - GNUNET_NETWORK_fdset_destroy (wrs); - GNUNET_NETWORK_fdset_destroy (wws); - return ret; -} - - -/** - * Start server offering our hostlist. - * - * @return #GNUNET_OK on success - */ -int -GNUNET_HOSTLIST_server_start (const struct GNUNET_CONFIGURATION_Handle *c, - struct GNUNET_STATISTICS_Handle *st, - struct GNUNET_CORE_Handle *co, - GNUNET_CORE_ConnectEventHandler *server_ch, - GNUNET_CORE_DisconnectEventHandler *server_dh, - int advertise) -{ - unsigned long long port; - char *hostname; - char *ipv4; - char *ipv6; - size_t size; - struct in_addr i4; - struct in6_addr i6; - struct sockaddr_in v4; - struct sockaddr_in6 v6; - const struct sockaddr *sa4; - const struct sockaddr *sa6; - - advertising = advertise; - if (! advertising) - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Advertising not enabled on this hostlist server\n"); - else - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Advertising enabled on this hostlist server\n"); - cfg = c; - stats = st; - peerinfo = GNUNET_PEERINFO_connect (cfg); - if (NULL == peerinfo) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Could not access PEERINFO service. Exiting.\n")); - return GNUNET_SYSERR; - } - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (cfg, - "HOSTLIST", - "HTTPPORT", - &port)) - return GNUNET_SYSERR; - if ((0 == port) || (port > UINT16_MAX)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Invalid port number %llu. Exiting.\n"), - port); - return GNUNET_SYSERR; - } - - if (GNUNET_SYSERR == - GNUNET_CONFIGURATION_get_value_string (cfg, - "HOSTLIST", - "EXTERNAL_DNS_NAME", - &hostname)) - hostname = GNUNET_RESOLVER_local_fqdn_get (); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _("Hostlist service starts on %s:%llu\n"), - hostname, port); - if (NULL != hostname) - { - size = strlen (hostname); - if (size + 15 > MAX_URL_LEN) - { - GNUNET_break (0); - } - else - { - GNUNET_asprintf (&hostlist_uri, - "http://%s:%u/", hostname, - (unsigned int) port); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _("Address to obtain hostlist: `%s'\n"), - hostlist_uri); - } - GNUNET_free (hostname); - } - - if (GNUNET_CONFIGURATION_have_value (cfg, "HOSTLIST", "BINDTOIPV4")) - { - GNUNET_break (GNUNET_OK == - GNUNET_CONFIGURATION_get_value_string (cfg, "HOSTLIST", - "BINDTOIP", &ipv4)); - } - else - ipv4 = NULL; - if (GNUNET_CONFIGURATION_have_value (cfg, "HOSTLIST", "BINDTOIPV6")) - { - GNUNET_break (GNUNET_OK == - GNUNET_CONFIGURATION_get_value_string (cfg, "HOSTLIST", - "BINDTOIP", &ipv6)); - } - else - ipv6 = NULL; - sa4 = NULL; - if (NULL != ipv4) - { - if (1 == inet_pton (AF_INET, ipv4, &i4)) - { - memset (&v4, 0, sizeof (v4)); - v4.sin_family = AF_INET; - v4.sin_addr = i4; - v4.sin_port = htons (port); -#if HAVE_SOCKADDR_IN_SIN_LEN - v4.sin_len = sizeof (v4); -#endif - sa4 = (const struct sockaddr *) &v4; - } - else - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _("`%s' is not a valid IPv4 address! Ignoring BINDTOIPV4.\n"), - ipv4); - GNUNET_free (ipv4); - } - sa6 = NULL; - if (NULL != ipv6) - { - if (1 == inet_pton (AF_INET6, ipv6, &i6)) - { - memset (&v6, 0, sizeof (v6)); - v6.sin6_family = AF_INET6; - v6.sin6_addr = i6; - v6.sin6_port = htons (port); -#if HAVE_SOCKADDR_IN_SIN_LEN - v6.sin6_len = sizeof (v6); -#endif - sa6 = (const struct sockaddr *) &v6; - } - else - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _("`%s' is not a valid IPv6 address! Ignoring BINDTOIPV6.\n"), - ipv6); - GNUNET_free (ipv6); - } - - daemon_handle_v6 = MHD_start_daemon (MHD_USE_IPv6 | MHD_USE_DEBUG, - (uint16_t) port, - &accept_policy_callback, NULL, - &access_handler_callback, NULL, - MHD_OPTION_CONNECTION_LIMIT, - (unsigned int) 16, - MHD_OPTION_PER_IP_CONNECTION_LIMIT, - (unsigned int) 1, - MHD_OPTION_CONNECTION_TIMEOUT, - (unsigned int) 16, - MHD_OPTION_CONNECTION_MEMORY_LIMIT, - (size_t) (16 * 1024), - MHD_OPTION_SOCK_ADDR, - sa6, - MHD_OPTION_END); - daemon_handle_v4 = MHD_start_daemon (MHD_NO_FLAG | MHD_USE_DEBUG, - (uint16_t) port, - &accept_policy_callback, NULL, - &access_handler_callback, NULL, - MHD_OPTION_CONNECTION_LIMIT, - (unsigned int) 16, - MHD_OPTION_PER_IP_CONNECTION_LIMIT, - (unsigned int) 1, - MHD_OPTION_CONNECTION_TIMEOUT, - (unsigned int) 16, - MHD_OPTION_CONNECTION_MEMORY_LIMIT, - (size_t) (16 * 1024), - MHD_OPTION_SOCK_ADDR, - sa4, - MHD_OPTION_END); - - if ( (NULL == daemon_handle_v6) && - (NULL == daemon_handle_v4) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Could not start hostlist HTTP server on port %u\n"), - (unsigned short) port); - return GNUNET_SYSERR; - } - - core = co; - *server_ch = &connect_handler; - *server_dh = &disconnect_handler; - if (NULL != daemon_handle_v4) - hostlist_task_v4 = prepare_daemon (daemon_handle_v4); - if (NULL != daemon_handle_v6) - hostlist_task_v6 = prepare_daemon (daemon_handle_v6); - notify = GNUNET_PEERINFO_notify (cfg, GNUNET_NO, - &process_notify, NULL); - return GNUNET_OK; -} - - -/** - * Stop server offering our hostlist. - */ -void -GNUNET_HOSTLIST_server_stop () -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hostlist server shutdown\n"); - if (GNUNET_SCHEDULER_NO_TASK != hostlist_task_v6) - { - GNUNET_SCHEDULER_cancel (hostlist_task_v6); - hostlist_task_v6 = GNUNET_SCHEDULER_NO_TASK; - } - if (GNUNET_SCHEDULER_NO_TASK != hostlist_task_v4) - { - GNUNET_SCHEDULER_cancel (hostlist_task_v4); - hostlist_task_v4 = GNUNET_SCHEDULER_NO_TASK; - } - if (NULL != daemon_handle_v4) - { - MHD_stop_daemon (daemon_handle_v4); - daemon_handle_v4 = NULL; - } - if (NULL != daemon_handle_v6) - { - MHD_stop_daemon (daemon_handle_v6); - daemon_handle_v6 = NULL; - } - if (NULL != response) - { - MHD_destroy_response (response); - response = NULL; - } - if (NULL != notify) - { - GNUNET_PEERINFO_notify_cancel (notify); - notify = NULL; - } - if (NULL != builder) - { - GNUNET_PEERINFO_iterate_cancel (builder->pitr); - builder->pitr = NULL; - GNUNET_free_non_null (builder->data); - GNUNET_free (builder); - } - if (NULL != peerinfo) - { - GNUNET_PEERINFO_disconnect (peerinfo); - peerinfo = NULL; - } - cfg = NULL; - stats = NULL; - core = NULL; -} - -/* end of hostlist-server.c */ diff --git a/src/hostlist/hostlist-server.h b/src/hostlist/hostlist-server.h deleted file mode 100644 index e0f8eb4a6..000000000 --- a/src/hostlist/hostlist-server.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2009 Christian Grothoff (and other contributing authors) - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. -*/ - -/** - * @file hostlist/hostlist-server.h - * @brief hostlist support. Downloads HELLOs via HTTP. - * @author Christian Grothoff - */ - -#ifndef HOSTLIST_SERVER_H -#define HOSTLIST_SERVER_H - -#include "gnunet_core_service.h" -#include "gnunet_statistics_service.h" -#include "gnunet_util_lib.h" - -#define GNUNET_ADV_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5) - -/** - * Start server offering our hostlist. - * - * @return GNUNET_OK on success - */ -int -GNUNET_HOSTLIST_server_start (const struct GNUNET_CONFIGURATION_Handle *c, - struct GNUNET_STATISTICS_Handle *st, - struct GNUNET_CORE_Handle *core, - GNUNET_CORE_ConnectEventHandler *server_ch, - GNUNET_CORE_DisconnectEventHandler *server_dh, - int advertise); - - -/** - * Stop server offering our hostlist. - */ -void -GNUNET_HOSTLIST_server_stop (void); - - -#endif -/* end of hostlist-server.h */ diff --git a/src/hostlist/test_gnunet_daemon_hostlist_learning.c b/src/hostlist/test_gnunet_daemon_hostlist_learning.c index 8a5cdac7a..9f4d8e3d7 100644 --- a/src/hostlist/test_gnunet_daemon_hostlist_learning.c +++ b/src/hostlist/test_gnunet_daemon_hostlist_learning.c @@ -37,7 +37,7 @@ */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 180) -#define CHECK_INTERVALL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1) +#define CHECK_INTERVAL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1) struct PeerContext @@ -304,7 +304,7 @@ check_statistics (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) &process_adv_sent, NULL); } check_task = - GNUNET_SCHEDULER_add_delayed (CHECK_INTERVALL, &check_statistics, NULL); + GNUNET_SCHEDULER_add_delayed (CHECK_INTERVAL, &check_statistics, NULL); } @@ -452,7 +452,7 @@ run (void *cls, char *const *args, const char *cfgfile, timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &timeout_error, NULL); check_task = - GNUNET_SCHEDULER_add_delayed (CHECK_INTERVALL, &check_statistics, NULL); + GNUNET_SCHEDULER_add_delayed (CHECK_INTERVAL, &check_statistics, NULL); } -- cgit v1.2.3