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 2, or (at your
+ 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
#include "gnunet_common.h"
#include "gnunet_bio_lib.h"
-#define DEBUG_HOSTLIST_CLIENT GNUNET_YES
+#define DEBUG_HOSTLIST_CLIENT GNUNET_NO
/**
*/
#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
*/
*/
static const struct GNUNET_CONFIGURATION_Handle *cfg;
-/**
- * Our scheduler.
- */
-static struct GNUNET_SCHEDULER_Handle *sched;
-
/**
* Statistics handle.
*/
-struct GNUNET_STATISTICS_Handle *stats;
+static struct GNUNET_STATISTICS_Handle *stats;
/**
* Transport handle.
*/
-struct GNUNET_TRANSPORT_Handle *transport;
+static struct GNUNET_TRANSPORT_Handle *transport;
/**
* Proxy that we are using (can be NULL).
*/
static char *proxy;
-/**
- * Buffer for data downloaded via HTTP.
- */
-static char download_buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE];
-
/**
* Number of bytes valid in 'download_buffer'.
*/
static CURLM *multi;
/**
- * ID of the current task scheduled.
+ * 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 current_task;
+static GNUNET_SCHEDULER_TaskIdentifier ti_check_download;
/**
- * ID of the current hostlist saving task scheduled.
+ * ID of the task downloading the hostlist
*/
-static GNUNET_SCHEDULER_TaskIdentifier saving_task;
+static GNUNET_SCHEDULER_TaskIdentifier ti_download;
/**
- * Amount of time we wait between hostlist downloads.
+ * ID of the task saving the hostlsit in a regular intervall
*/
-static struct GNUNET_TIME_Relative hostlist_delay;
+static GNUNET_SCHEDULER_TaskIdentifier ti_saving_task;
/**
- * Set to GNUNET_YES if the current URL had some problems.
- */
-static int bogus_url;
+ * ID of the task called to initiate a download
+ */
+static GNUNET_SCHEDULER_TaskIdentifier ti_download_dispatcher_task;
/**
- * Number of active connections (according to core service).
+ * ID of the task controlling the locking between two hostlist tests
*/
-static unsigned int connection_count;
+static GNUNET_SCHEDULER_TaskIdentifier ti_testing_intervall_task;
/**
* At what time MUST the current hostlist request be done?
static unsigned int linked_list_size;
/**
- * Value saying if preconfigured is used
+ * Head of the linked list used to store hostlists
+ */
+static struct Hostlist * hostlist_to_test;
+
+/**
+ * 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 unsigned int use_preconfigured_list;
+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 learning;
+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 hellos_obtained;
+static unsigned int stat_hellos_obtained;
/**
- * Value saying if hostlist download was successful
+ * Number of active connections (according to core service).
*/
-static unsigned int download_successful;
+static unsigned int stat_connection_count;
+
/**
* Process downloaded bits by calling callback on each HELLO.
* @return number of bytes that were processed (always size*nmemb)
*/
static size_t
-download_hostlist_processor (void *ptr,
+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;
uint16_t msize;
total = size * nmemb;
- if ( (total == 0) || (bogus_url) )
+ 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,
while ( (left > 0) ||
(download_pos > 0) )
{
- cpy = GNUNET_MIN (left, GNUNET_SERVER_MAX_MESSAGE_SIZE - download_pos);
+ cpy = GNUNET_MIN (left, GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - download_pos);
memcpy (&download_buffer[download_pos],
cbuf,
cpy);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
_("Invalid `%s' message received from hostlist at `%s'\n"),
"HELLO",
- current_url);
- bogus_url = 1;
+ current_url);
+ stat_hellos_obtained++;
+ stat_bogus_url = 1;
return total;
}
if (download_pos < msize)
gettext_noop ("# valid HELLOs downloaded from hostlist servers"),
1,
GNUNET_NO);
- hellos_obtained++;
+ stat_hellos_obtained++;
GNUNET_TRANSPORT_offer_hello (transport, msg);
}
else
_("Invalid `%s' message received from hostlist at `%s'\n"),
"HELLO",
current_url);
- bogus_url = GNUNET_YES;
+ stat_bogus_url = GNUNET_YES;
+ stat_hellos_obtained++;
return total;
}
memmove (download_buffer,
* @return NULL if there is no URL available
*/
static char *
-get_bootstrap_url ()
+get_bootstrap_server ()
{
char *servers;
char *ret;
* @return uri to use, NULL if there is no URL available
*/
static char *
-get_list_url ()
+download_get_url ()
{
uint32_t index;
unsigned int counter;
struct Hostlist * pos;
- if ( GNUNET_NO == learning)
+ if ( GNUNET_NO == stat_learning)
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Using preconfigured bootstrap server\n");
current_hostlist = NULL;
- return get_bootstrap_url();
+ 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 strdup(hostlist_to_test->hostlist_uri);
}
- if ( (GNUNET_YES == use_preconfigured_list) ||
+
+ 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_url();
+ return get_bootstrap_server();
}
index = GNUNET_CRYPTO_random_u32 ( GNUNET_CRYPTO_QUALITY_WEAK, linked_list_size);
counter = 0;
}
-#define CURL_EASY_SETOPT(c, a, b) do { ret = curl_easy_setopt(c, a, b); if (ret != CURLE_OK) GNUNET_log(GNUNET_ERROR_TYPE_WARNING, _("%s failed at %s:%d: `%s'\n"), "curl_easy_setopt", __FILE__, __LINE__, curl_easy_strerror(ret)); } while (0);
-
-
-/**
- * Schedule the background task that will (possibly)
- * download a hostlist.
- */
-static void
-schedule_hostlist_task (void);
+#define CURL_EASY_SETOPT(c, a, b) do { ret = curl_easy_setopt(c, a, b); if (ret != CURLE_OK) GNUNET_log(GNUNET_ERROR_TYPE_WARNING, _("%s failed at %s:%d: `%s'\n"), "curl_easy_setopt", __FILE__, __LINE__, curl_easy_strerror(ret)); } while (0)
/**
- * Method to load persistent hostlist file during hostlist client shutdown
+ * 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 );
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 ( (use_preconfigured_list == GNUNET_NO) && ( NULL != current_hostlist ) )
+ 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 = hellos_obtained;
+ current_hostlist->hello_count = stat_hellos_obtained;
current_hostlist->time_last_usage = GNUNET_TIME_absolute_get();
- current_hostlist->quality = checked_add ( current_hostlist->quality, (hellos_obtained * HOSTLIST_SUCCESSFUL_HELLO));
- if ( GNUNET_YES == download_successful )
+ 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);
current_hostlist = NULL;
/* Alternating the usage of preconfigured and learned hostlists */
- if ( GNUNET_YES == learning)
+ if (stat_testing_hostlist == GNUNET_YES)
+ return;
+
+ if ( GNUNET_YES == stat_learning)
{
- if (use_preconfigured_list == GNUNET_YES)
- use_preconfigured_list = GNUNET_NO;
+ if (stat_use_bootstrap == GNUNET_YES)
+ stat_use_bootstrap = GNUNET_NO;
else
- use_preconfigured_list = GNUNET_YES;
+ stat_use_bootstrap = GNUNET_YES;
}
else
- use_preconfigured_list = GNUNET_YES;
+ stat_use_bootstrap = GNUNET_YES;
}
/**
{
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);
}
GNUNET_free_non_null (current_url);
current_url = NULL;
-
- schedule_hostlist_task ();
+ 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
-run_multi (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);
+#if DEBUG_HOSTLIST_CLIENT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Scheduling task for hostlist download using cURL\n");
+#endif
+ ti_download
+ = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+ GNUNET_SCHEDULER_NO_TASK,
+ rtime,
+ grs,
+ gws,
+ &task_download,
+ multi);
+ GNUNET_NETWORK_fdset_destroy (gws);
+ GNUNET_NETWORK_fdset_destroy (grs);
+}
/**
* @param tc task context, unused
*/
static void
-multi_ready (void *cls,
+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))
{
#if DEBUG_HOSTLIST_CLIENT
clean_up ();
return;
}
- if (GNUNET_TIME_absolute_get_remaining (end_time).value == 0)
+ if (GNUNET_TIME_absolute_get_remaining (end_time).rel_value == 0)
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
_("Timeout trying to download hostlist from `%s'\n"),
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Ready for processing hostlist client request\n");
#endif
+
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)
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
_("Download of hostlist `%s' completed.\n"),
current_url);
- download_successful = GNUNET_YES;
- update_hostlist();
+ 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 ( (running > 0) );
}
}
while (mret == CURLM_CALL_MULTI_PERFORM);
+
if (mret != CURLM_OK)
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
curl_multi_strerror (mret));
clean_up ();
}
- run_multi ();
-}
-
-
-/**
- * Ask CURL for the select set and then schedule the
- * receiving task with the scheduler.
- */
-static void
-run_multi ()
-{
- 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);
-#if DEBUG_HOSTLIST_CLIENT
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Scheduling task for hostlist download using cURL\n");
-#endif
- current_task
- = GNUNET_SCHEDULER_add_select (sched,
- GNUNET_SCHEDULER_PRIORITY_DEFAULT,
- GNUNET_SCHEDULER_NO_TASK,
- rtime,
- grs,
- gws,
- &multi_ready,
- multi);
- GNUNET_NETWORK_fdset_destroy (gws);
- GNUNET_NETWORK_fdset_destroy (grs);
+ download_prepare ();
}
CURLcode ret;
CURLMcode mret;
- current_url = get_list_url ();
+
+ current_url = download_get_url ();
if (current_url == NULL)
return;
curl = curl_easy_init ();
GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
_("Bootstrapping using hostlist at `%s'.\n"),
current_url);
- hellos_obtained = 0;
- download_successful = GNUNET_NO;
+
+ 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,
if (proxy != NULL)
CURL_EASY_SETOPT (curl, CURLOPT_PROXY, proxy);
download_pos = 0;
- bogus_url = 0;
+ stat_bogus_url = 0;
CURL_EASY_SETOPT (curl,
CURLOPT_WRITEFUNCTION,
- &download_hostlist_processor);
+ &callback_download);
if (ret != CURLE_OK)
{
clean_up ();
if (multi == NULL)
{
GNUNET_break (0);
- clean_up ();
+ /* clean_up (); */
return;
}
mret = curl_multi_add_handle (multi, curl);
return;
}
end_time = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES);
- run_multi ();
+ 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
-check_task (void *cls,
+task_check (void *cls,
const struct GNUNET_SCHEDULER_TaskContext *tc)
{
- current_task = GNUNET_SCHEDULER_NO_TASK;
+ 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 (connection_count < MIN_CONNECTIONS)
- download_hostlist ();
- else
- schedule_hostlist_task ();
-}
-
-/**
- * Compute when we should check the next time about downloading
- * a hostlist; then schedule the task accordingly.
- */
-static void
-schedule_hostlist_task ()
-{
- static int once;
- struct GNUNET_TIME_Relative delay;
+ if (stat_connection_count < MIN_CONNECTIONS)
+ {
+ ti_download_dispatcher_task = GNUNET_SCHEDULER_add_now (&task_download_dispatcher,
+ NULL);
+ }
if (stats == NULL)
- {
- curl_global_cleanup ();
- return; /* in shutdown */
- }
+ {
+ curl_global_cleanup ();
+ return; /* in shutdown */
+ }
delay = hostlist_delay;
- if (hostlist_delay.value == 0)
+ if (hostlist_delay.rel_value == 0)
hostlist_delay = GNUNET_TIME_UNIT_SECONDS;
else
hostlist_delay = GNUNET_TIME_relative_multiply (hostlist_delay, 2);
- if (hostlist_delay.value > GNUNET_TIME_UNIT_HOURS.value * (1 + connection_count))
+ if (hostlist_delay.rel_value > GNUNET_TIME_UNIT_HOURS.rel_value * (1 + stat_connection_count))
hostlist_delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS,
- (1 + connection_count));
+ (1 + stat_connection_count));
GNUNET_STATISTICS_set (stats,
- gettext_noop("# seconds between hostlist downloads"),
- hostlist_delay.value,
- GNUNET_YES);
+ gettext_noop("# milliseconds between hostlist downloads"),
+ hostlist_delay.rel_value,
+ 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 %llums\n"),
- connection_count,
- MIN_CONNECTIONS,
- (unsigned long long) delay.value);
- current_task = GNUNET_SCHEDULER_add_delayed (sched,
- delay,
- &check_task,
- NULL);
+ _("Have %u/%u connections. Will consider downloading hostlist in %llums\n"),
+ stat_connection_count,
+ MIN_CONNECTIONS,
+ (unsigned long long) delay.rel_value);
+ 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
+ * cls closure
+ * 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
* cls closure
* tc TaskContext
*/
static void
-hostlist_saving_task (void *cls,
+task_hostlist_saving (void *cls,
const struct GNUNET_SCHEDULER_TaskContext *tc)
{
- saving_task = GNUNET_SCHEDULER_NO_TASK;
+ ti_saving_task = GNUNET_SCHEDULER_NO_TASK;
if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
return;
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
_("Hostlists will be saved to file again in %llums\n"),
- (unsigned long long) SAVING_INTERVALL.value);
- saving_task = GNUNET_SCHEDULER_add_delayed (sched,
- SAVING_INTERVALL,
- &hostlist_saving_task,
+ (unsigned long long) SAVING_INTERVALL.rel_value);
+ ti_saving_task = GNUNET_SCHEDULER_add_delayed (SAVING_INTERVALL,
+ &task_hostlist_saving,
NULL);
}
*
* @param cls closure
* @param peer peer identity this notification is about
- * @param latency reported latency of the connection with 'other'
- * @param distance reported distance (DV) to 'other'
+ * @param atsi performance data
*/
static void
-connect_handler (void *cls,
+handler_connect (void *cls,
const struct
GNUNET_PeerIdentity * peer,
- struct GNUNET_TIME_Relative latency,
- uint32_t distance)
+ const struct GNUNET_TRANSPORT_ATS_Information *atsi)
{
- connection_count++;
+ GNUNET_assert (stat_connection_count < UINT_MAX);
+ stat_connection_count++;
GNUNET_STATISTICS_update (stats,
gettext_noop ("# active connections"),
1,
- GNUNET_NO);
+ GNUNET_NO);
}
* @param peer peer identity this notification is about
*/
static void
-disconnect_handler (void *cls,
+handler_disconnect (void *cls,
const struct
GNUNET_PeerIdentity * peer)
{
- connection_count--;
- GNUNET_STATISTICS_update (stats,
- gettext_noop ("# active connections"),
- -1,
- GNUNET_NO);
+ GNUNET_assert (stat_connection_count > 0);
+ stat_connection_count--;
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# active connections"),
+ -1,
+ GNUNET_NO);
}
-
-/**
- * Method to check if 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;
-}
-
-
-/* linked_list_? */
-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 called whenever an advertisement message arrives.
*
* @param cls closure (always NULL)
* @param peer the peer sending the message
* @param message the actual message
- * @param latency latency
- * @param distance distance
+ * @param atsi performance data
* @return GNUNET_OK to keep the connection open,
* GNUNET_SYSERR to close it (signal serious error)
*/
static int
-advertisement_handler (void *cls,
- const struct GNUNET_PeerIdentity * peer,
- const struct GNUNET_MessageHeader * message,
- struct GNUNET_TIME_Relative latency,
- uint32_t distance)
+handler_advertisement (void *cls,
+ const struct GNUNET_PeerIdentity * peer,
+ const struct GNUNET_MessageHeader * message,
+ const struct GNUNET_TRANSPORT_ATS_Information *atsi)
{
size_t size;
size_t uri_size;
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->time_last_usage = GNUNET_TIME_absolute_get_zero();
- hostlist->quality = HOSTLIST_INITIAL;
+ hostlist->quality = HOSTLIST_INITIAL;
+ hostlist_to_test = hostlist;
- GNUNET_CONTAINER_DLL_insert(linked_list_head, linked_list_tail, hostlist);
- linked_list_size++;
-
- GNUNET_STATISTICS_set (stats,
- gettext_noop("# advertised hostlist URIs"),
- linked_list_size,
- GNUNET_NO);
-
- if (MAX_NUMBER_HOSTLISTS >= linked_list_size)
- return GNUNET_OK;
+ 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);
- /* No free entries available, replace existing entry */
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Removing lowest quality entry\n" );
- struct Hostlist * lowest_quality = linked_list_get_lowest_quality();
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Hostlist with URI `%s' has the worst quality of all with value %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--;
+ "Testing new hostlist advertisements is locked for the next %u ms\n",
+ TESTING_INTERVAL.rel_value);
- GNUNET_STATISTICS_set (stats,
- gettext_noop("# advertised hostlist URIs"),
- linked_list_size,
- GNUNET_NO);
+ ti_download_dispatcher_task = GNUNET_SCHEDULER_add_now (&task_download_dispatcher,
+ NULL);
- GNUNET_free (lowest_quality);
return GNUNET_OK;
}
+
/**
* Continuation called by the statistics code once
* we go the stat. Initiates hostlist download scheduling.
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Statistics request done, scheduling hostlist download\n");
#endif
- schedule_hostlist_task ();
+ ti_check_download = GNUNET_SCHEDULER_add_now (&task_check,
+ NULL);
}
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
_("Initial time between hostlist downloads is %llums\n"),
(unsigned long long) value);
- hostlist_delay.value = value;
+ hostlist_delay.rel_value = value;
return GNUNET_OK;
}
uint32_t counter;
if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "HOSTLIST",
- "HOSTLISTFILE",
- &filename))
+ GNUNET_CONFIGURATION_get_value_filename (cfg,
+ "HOSTLIST",
+ "HOSTLISTFILE",
+ &filename))
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
_("No `%s' specified in `%s' configuration, cannot load hostlists from file.\n"),
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)) &&
hostlist->hostlist_uri = (const char *) &hostlist[1];
memcpy (&hostlist[1], uri, strlen(uri)+1);
hostlist->quality = quality;
- hostlist->time_creation.value = created;
- hostlist->time_last_usage.value = last_used;
+ hostlist->time_creation.abs_value = created;
+ hostlist->time_last_usage.abs_value = last_used;
GNUNET_CONTAINER_DLL_insert(linked_list_head, linked_list_tail, hostlist);
linked_list_size++;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
uint32_t counter;
if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
+ GNUNET_CONFIGURATION_get_value_filename (cfg,
"HOSTLIST",
"HOSTLISTFILE",
&filename))
"HOSTLISTFILE", "HOSTLIST");
return;
}
+ if (GNUNET_SYSERR != GNUNET_DISK_directory_create_for_file (filename))
+ {
wh = GNUNET_BIO_write_open (filename);
if ( NULL == wh)
{
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;
(GNUNET_OK !=
GNUNET_BIO_write_int64 (wh, pos->quality)) ||
(GNUNET_OK !=
- GNUNET_BIO_write_int64 (wh, pos->time_last_usage.value)) ||
+ GNUNET_BIO_write_int64 (wh, pos->time_last_usage.abs_value)) ||
(GNUNET_OK !=
- GNUNET_BIO_write_int64 (wh, pos->time_creation.value)) ||
+ GNUNET_BIO_write_int64 (wh, pos->time_creation.abs_value)) ||
(GNUNET_OK !=
GNUNET_BIO_write_int32 (wh, pos->hello_count)))
{
*/
int
GNUNET_HOSTLIST_client_start (const struct GNUNET_CONFIGURATION_Handle *c,
- struct GNUNET_SCHEDULER_Handle *s,
struct GNUNET_STATISTICS_Handle *st,
GNUNET_CORE_ConnectEventHandler *ch,
GNUNET_CORE_DisconnectEventHandler *dh,
GNUNET_break (0);
return GNUNET_SYSERR;
}
- transport = GNUNET_TRANSPORT_connect (s, c, NULL, NULL, NULL, NULL);
+ transport = GNUNET_TRANSPORT_connect (c, NULL, NULL, NULL, NULL, NULL);
if (NULL == transport)
{
curl_global_cleanup ();
return GNUNET_SYSERR;
}
cfg = c;
- sched = s;
stats = st;
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_string (cfg,
"HTTP-PROXY",
&proxy))
proxy = NULL;
- learning = learn;
- *ch = &connect_handler;
- *dh = &disconnect_handler;
+ stat_learning = learn;
+ *ch = &handler_connect;
+ *dh = &handler_disconnect;
linked_list_head = NULL;
linked_list_tail = NULL;
- use_preconfigured_list = GNUNET_YES;
+ stat_use_bootstrap = GNUNET_YES;
+ stat_testing_hostlist = GNUNET_NO;
+ stat_testing_allowed = GNUNET_YES;
- if ( GNUNET_YES == learning )
+ if ( GNUNET_YES == stat_learning )
{
- *msgh = &advertisement_handler;
+ *msgh = &handler_advertisement;
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
_("Learning is enabled on this peer\n"));
load_hostlist_file ();
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
_("Hostlists will be saved to file again in %llums\n"),
- (unsigned long long) SAVING_INTERVALL.value);
- saving_task = GNUNET_SCHEDULER_add_delayed (sched,
- SAVING_INTERVALL,
- &hostlist_saving_task,
+ (unsigned long long) SAVING_INTERVALL.rel_value);
+ 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_string (cfg,
+ if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg,
"HOSTLIST",
"HOSTLISTFILE",
&filename))
}
GNUNET_STATISTICS_get (stats,
"hostlist",
- gettext_noop("# seconds between hostlist downloads"),
+ gettext_noop("# milliseconds between hostlist downloads"),
GNUNET_TIME_UNIT_MINUTES,
&primary_task,
&process_stat,
void
GNUNET_HOSTLIST_client_stop ()
{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Hostlist client shutdown\n");
#if DEBUG_HOSTLIST_CLIENT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Hostlist client shutdown\n");
#endif
- if ( GNUNET_YES == learning )
+ if ( GNUNET_YES == stat_learning )
save_hostlist_file ( GNUNET_YES );
- if (current_task != GNUNET_SCHEDULER_NO_TASK)
+ if (ti_saving_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (ti_saving_task);
+ }
+
+ if (ti_download_dispatcher_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (ti_download_dispatcher_task);
+ }
+ if (ti_testing_intervall_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (ti_testing_intervall_task);
+ }
+ if (ti_download != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (ti_download);
+ }
+ if (ti_check_download != GNUNET_SCHEDULER_NO_TASK)
{
- GNUNET_SCHEDULER_cancel (sched,
- current_task);
+ GNUNET_SCHEDULER_cancel (ti_check_download);
curl_global_cleanup ();
}
if (transport != NULL)
GNUNET_free_non_null (proxy);
proxy = NULL;
cfg = NULL;
- sched = NULL;
}
/* end of hostlist-client.c */