make clang static analysis happy
[oweals/gnunet.git] / src / hostlist / hostlist-client.c
index ecdd578af24109a2be0aa0abacf0fb4862a92ebe..90fdfb63a3d35e59525b8217490c45c91b937c11 100644 (file)
@@ -38,7 +38,6 @@
 
 #define DEBUG_HOSTLIST_CLIENT GNUNET_YES
 
-#define MAX_URL_LEN 1000
 
 /**
  * Number of connections that we must have to NOT download
@@ -92,7 +91,7 @@ struct Hostlist
   uint32_t hello_count;
 
   /**
-   * Number of times the hostlist was obtained
+   * Number of times the hostlist was successfully obtained
    */
   uint32_t times_used;
 
@@ -189,7 +188,12 @@ static struct Hostlist * linked_list_head;
  */
 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;
@@ -199,6 +203,21 @@ static unsigned int linked_list_size;
  */
 static unsigned int use_preconfigured_list;
 
+/**
+ * Set if we are allowed to learn new hostlists and use them
+ */
+static int learning;
+
+/**
+ * Value saying how many valid HELLO messages were obtained during download
+ */
+static unsigned int hellos_obtained;
+
+/**
+ * Value saying if hostlist download was successful
+ */
+static unsigned int download_successful;
+
 /**
  * Process downloaded bits by calling callback on each HELLO.
  *
@@ -276,7 +295,8 @@ download_hostlist_processor (void *ptr,
          GNUNET_STATISTICS_update (stats, 
                                    gettext_noop ("# valid HELLOs downloaded from hostlist servers"), 
                                    1, 
-                                   GNUNET_NO);  
+                                   GNUNET_NO);
+         hellos_obtained++;
          GNUNET_TRANSPORT_offer_hello (transport, msg);
        }
       else
@@ -379,11 +399,19 @@ get_list_url ()
   unsigned int counter;
   struct Hostlist * pos;
 
-  if ( GNUNET_YES == use_preconfigured_list)
+  if ( GNUNET_NO == learning)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Using preconfigured bootstrap server\n");
+    current_hostlist = NULL;
+    return get_bootstrap_url();
+  }
+  if ( (GNUNET_YES == use_preconfigured_list) ||
+       (linked_list_size == 0) )
   {
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "Using preconfigured bootstrap server\n");
-    use_preconfigured_list = GNUNET_NO;
+    current_hostlist = NULL;
     return get_bootstrap_url();
   }
   index = GNUNET_CRYPTO_random_u32 ( GNUNET_CRYPTO_QUALITY_WEAK, linked_list_size);
@@ -394,9 +422,9 @@ get_list_url ()
       pos = pos->next;
       counter ++;
     }
-  use_preconfigured_list = GNUNET_YES;
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Using learned hostlist `%s'\n", pos->hostlist_uri);
+  current_hostlist = pos;
   return strdup(pos->hostlist_uri);
 }
 
@@ -417,6 +445,86 @@ schedule_hostlist_task (void);
  */
 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;
+  else
+    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;
+  else
+    return (val1-val2);
+}
+
+
+/**
+ * Method updating hostlist statistics
+ */
+static void update_hostlist ( )
+{
+  char *stat;
+  if ( (use_preconfigured_list == GNUNET_NO) && ( 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->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->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 ( GNUNET_YES == learning)
+    {
+    if (use_preconfigured_list == GNUNET_YES)
+      use_preconfigured_list = GNUNET_NO;
+    else
+      use_preconfigured_list = GNUNET_YES;
+    }
+  else
+    use_preconfigured_list = GNUNET_YES;
+}
+
 /**
  * Clean up the state from the task that downloaded the
  * hostlist and schedule the next task.
@@ -451,6 +559,7 @@ clean_up ()
     }  
   GNUNET_free_non_null (current_url);
   current_url = NULL;
+
   schedule_hostlist_task ();
 }
 
@@ -485,6 +594,7 @@ multi_ready (void *cls,
                  "Shutdown requested while trying to download hostlist from `%s'\n",
                  current_url);
 #endif
+      update_hostlist();
       clean_up ();
       return;
     }
@@ -493,6 +603,7 @@ multi_ready (void *cls,
       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                  _("Timeout trying to download hostlist from `%s'\n"),
                  current_url);
+      update_hostlist();
       clean_up ();
       return;
     }
@@ -525,9 +636,13 @@ multi_ready (void *cls,
                               __LINE__,
                               curl_easy_strerror (msg->data.result));            
                  else
+                   {
                    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
                                _("Download of hostlist `%s' completed.\n"),
                                current_url);
+                   download_successful = GNUNET_YES;
+                   update_hostlist();
+                   }
                  clean_up ();
                  return;
                default:
@@ -626,6 +741,9 @@ download_hostlist ()
   CURLcode ret;
   CURLMcode mret;
 
+  current_url = get_list_url ();
+  if (current_url == NULL)
+    return;
   curl = curl_easy_init ();
   multi = NULL;
   if (curl == NULL)
@@ -634,10 +752,11 @@ download_hostlist ()
       clean_up ();
       return;
     }
-  current_url = get_list_url ();
   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;
   GNUNET_STATISTICS_update (stats, 
                            gettext_noop ("# hostlist downloads initiated"), 
                            1, 
@@ -902,8 +1021,10 @@ linked_list_get_lowest_quality ( )
  * Method called whenever an advertisement message arrives.
  *
  * @param cls closure (always NULL)
- * @param client identification of the client
+ * @param peer the peer sending the message
  * @param message the actual message
+ * @param latency latency
+ * @param distance distance
  * @return GNUNET_OK to keep the connection open,
  *         GNUNET_SYSERR to close it (signal serious error)
  */
@@ -956,6 +1077,11 @@ advertisement_handler (void *cls,
   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;
 
@@ -969,6 +1095,12 @@ advertisement_handler (void *cls,
              (unsigned long long) lowest_quality->quality);
   GNUNET_CONTAINER_DLL_remove (linked_list_head, linked_list_tail, lowest_quality);
   linked_list_size--;
+
+  GNUNET_STATISTICS_set (stats,
+                         gettext_noop("# advertised hostlist URIs"),
+                         linked_list_size,
+                         GNUNET_NO);
+
   GNUNET_free (lowest_quality);
   return GNUNET_OK;
 }
@@ -1041,6 +1173,13 @@ load_hostlist_file ()
 
   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' is not existing\n"), filename);
+    GNUNET_free ( filename );
+    return;
+  }
 
   struct GNUNET_BIO_ReadHandle * rh = GNUNET_BIO_read_open (filename);
   if (NULL == rh)
@@ -1053,7 +1192,7 @@ load_hostlist_file ()
       return;
     }
 
-
+  counter = 0;
   while ( (GNUNET_OK == GNUNET_BIO_read_string (rh, "url" , &uri, MAX_URL_LEN)) &&
          (GNUNET_OK == GNUNET_BIO_read_int32 (rh, &times_used)) &&
          (GNUNET_OK == GNUNET_BIO_read_int64 (rh, &quality)) &&
@@ -1072,6 +1211,7 @@ load_hostlist_file ()
       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;
@@ -1080,9 +1220,13 @@ load_hostlist_file ()
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
               _("%u hostlist URIs loaded from file\n"), counter);
   GNUNET_STATISTICS_set (stats,
-                         gettext_noop("# hostlis URIs read from file"),
+                         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;
@@ -1094,7 +1238,7 @@ load_hostlist_file ()
 
 
 /**
- * Method to load persistent hostlist file during hostlist client shutdown
+ * 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 )
@@ -1123,6 +1267,7 @@ static void save_hostlist_file ( int shutdown )
                   _("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,
@@ -1190,6 +1335,9 @@ GNUNET_HOSTLIST_client_start (const struct GNUNET_CONFIGURATION_Handle *c,
                              GNUNET_CORE_MessageCallback *msgh,
                              int learn)
 {
+  char *filename;
+  int result;
+
   if (0 != curl_global_init (CURL_GLOBAL_WIN32))
     {
       GNUNET_break (0);
@@ -1210,25 +1358,50 @@ GNUNET_HOSTLIST_client_start (const struct GNUNET_CONFIGURATION_Handle *c,
                                             "HTTP-PROXY", 
                                             &proxy))
     proxy = NULL;
+  learning = learn;
   *ch = &connect_handler;
   *dh = &disconnect_handler;
-  if (learn)
-    *msgh = &advertisement_handler;
-  else
-    *msgh = NULL;
   linked_list_head = NULL;
   linked_list_tail = NULL;
   use_preconfigured_list = GNUNET_YES;
-  load_hostlist_file ();
 
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+  if ( GNUNET_YES == learning )
+  {
+    *msgh = &advertisement_handler;
+    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_task = GNUNET_SCHEDULER_add_delayed (sched,
                                                SAVING_INTERVALL,
                                                &hostlist_saving_task,
                                                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,
+                                                            "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 );
+  }
   GNUNET_STATISTICS_get (stats,
                         "hostlist",
                         gettext_noop("# seconds between hostlist downloads"),
@@ -1250,7 +1423,8 @@ GNUNET_HOSTLIST_client_stop ()
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Hostlist client shutdown\n");
 #endif
-  save_hostlist_file ( GNUNET_YES );
+  if ( GNUNET_YES == learning )
+    save_hostlist_file ( GNUNET_YES );
 
   if (current_task != GNUNET_SCHEDULER_NO_TASK)
     {