updated configuration files
[oweals/gnunet.git] / src / ats / gnunet-service-ats-solver_proportional.c
index d62cface9f34c60d6fc2917b6680f03a3303894b..24d359c71b9ba7da10ef5fe823f69212d1920ba3 100644 (file)
@@ -37,9 +37,9 @@
  * on gnunet.org:/vcs/fsnsg/ats-paper.git/tech-doku/ats-tech-guide.tex
  * use build_txt.sh to generate plaintext output
  *
- * ATS addresses : simplistic solver
+ * ATS addresses : proportional solver
  *
- *    The simplistic solver ("simplistic") distributes the available
+ *    The proportional solver ("proportional") distributes the available
  *    bandwidth fair over all the addresses influenced by the
  *    preference values. For each available network type an in- and
  *    outbound quota is configured and the bandwidth available in
  *    is used to specify network related information as total adresses
  *    and active addresses in this network and the configured in- and
  *    outbound quota. Each network also contains a list of addresses
- *    added to the solver located in this network. The simplistic
+ *    added to the solver located in this network. The proportional
  *    solver uses the addresses' solver_information field to store the
- *    simplistic network it belongs to for each address.
+ *    proportional network it belongs to for each address.
  *
  *     3.2 Initializing
  *
- *    When the simplistic solver is initialized the solver creates a
+ *    When the proportional solver is initialized the solver creates a
  *    new solver handle and initializes the network structures with
  *    the quotas passed from addresses and returns the handle solver.
  *
@@ -95,7 +95,7 @@
  *     3.4 Updating an address
  *
  *    The main purpose of address updates is to update the ATS
- *    information for addresse selection. Important for the simplistic
+ *    information for addresse selection. Important for the proportional
  *    solver is when an address switches network it is located
  *    in. This is common because addresses added by transport's
  *    validation mechanism are commonly located in
  *    return of payload data transport switches to the real network
  *    the address is located in.  When an address changes networks it
  *    is first of all removed from the old network using the solver
- *    API function GAS_simplistic_address_delete and the network in
+ *    API function GAS_proportional_address_delete and the network in
  *    the address struct is updated. A lookup for the respective new
- *    simplistic network is done and stored in the addresse's
+ *    proportional network is done and stored in the addresse's
  *    solver_information field. Next the address is re-added to the
  *    solver using the solver API function
- *    GAS_simplistic_address_add. If the address was marked as in
+ *    GAS_proportional_address_add. If the address was marked as in
  *    active, the solver checks if bandwidth is available in the
  *    network and if yes sets the address to active and updates the
  *    bandwidth distribution in this network. If no bandwidth is
@@ -228,6 +228,11 @@ struct GAS_PROPORTIONAL_Handle
    */
   const struct GNUNET_CONTAINER_MultiHashMap *addresses;
 
+  /**
+   * Pending address requests
+   */
+  struct GNUNET_CONTAINER_MultiHashMap *requests;
+
   /**
    * Bandwidth changed callback
    */
@@ -533,44 +538,44 @@ distribute_bandwidth_in_network (struct GAS_PROPORTIONAL_Handle *s,
 
   }
   LOG (GNUNET_ERROR_TYPE_DEBUG,
-                          "Total bandwidth assigned is (in/out): %llu /%llu\n",
-                          quota_in_used,
-                          quota_out_used);
+    "Total bandwidth assigned is (in/out): %llu /%llu\n",
+    quota_in_used,
+    quota_out_used);
   if (quota_out_used > net->total_quota_out + 1) /* +1 is required due to rounding errors */
   {
-      LOG (GNUNET_ERROR_TYPE_ERROR,
-                            "Total outbound bandwidth assigned is larger than allowed (used/allowed) for %u active addresses: %llu / %llu\n",
-                            net->active_addresses,
-                            quota_out_used,
-                            net->total_quota_out);
+    LOG (GNUNET_ERROR_TYPE_ERROR,
+      "Total outbound bandwidth assigned is larger than allowed (used/allowed) for %u active addresses: %llu / %llu\n",
+      net->active_addresses,
+      quota_out_used,
+      net->total_quota_out);
   }
   if (quota_in_used > net->total_quota_in + 1) /* +1 is required due to rounding errors */
   {
       LOG (GNUNET_ERROR_TYPE_ERROR,
-                            "Total inbound bandwidth assigned is larger than allowed (used/allowed) for %u active addresses: %llu / %llu\n",
-                            net->active_addresses,
-                            quota_in_used,
-                            net->total_quota_in);
+        "Total inbound bandwidth assigned is larger than allowed (used/allowed) for %u active addresses: %llu / %llu\n",
+        net->active_addresses,
+        quota_in_used,
+        net->total_quota_in);
   }
 }
 
 
 struct FindBestAddressCtx
 {
-       struct GAS_PROPORTIONAL_Handle *s;
-       struct ATS_Address *best;
+  struct GAS_PROPORTIONAL_Handle *s;
+  struct ATS_Address *best;
 };
 
 
 static int
 find_property_index (uint32_t type)
 {
-       int existing_types[] = GNUNET_ATS_QualityProperties;
-       int c;
-       for (c = 0; c < GNUNET_ATS_QualityPropertiesCount; c++)
-               if (existing_types[c] == type)
-                       return c;
-       return GNUNET_SYSERR;
+  int existing_types[] = GNUNET_ATS_QualityProperties;
+  int c;
+  for (c = 0; c < GNUNET_ATS_QualityPropertiesCount; c++)
+          if (existing_types[c] == type)
+                  return c;
+  return GNUNET_SYSERR;
 }
 
 /**
@@ -586,7 +591,7 @@ find_property_index (uint32_t type)
 static int
 find_best_address_it (void *cls, const struct GNUNET_HashCode * key, void *value)
 {
-       struct FindBestAddressCtx *fba_ctx = (struct FindBestAddressCtx *) cls;
+  struct FindBestAddressCtx *fba_ctx = (struct FindBestAddressCtx *) cls;
   struct ATS_Address *current = (struct ATS_Address *) value;
   struct GNUNET_TIME_Absolute now;
   struct Network *net = (struct Network *) current->solver_information;
@@ -695,11 +700,9 @@ find_best_address_it (void *cls, const struct GNUNET_HashCode * key, void *value
 static void
 distribute_bandwidth_in_all_networks (struct GAS_PROPORTIONAL_Handle *s)
 {
-       int i;
-
-       for (i = 0; i < s->networks; i++)
-               distribute_bandwidth_in_network (s, &s->network_entries[i], NULL);
-
+  int i;
+  for (i = 0; i < s->networks; i++)
+          distribute_bandwidth_in_network (s, &s->network_entries[i], NULL);
 }
 
 
@@ -892,6 +895,7 @@ GAS_proportional_address_change_preference (void *solver,
  * @param solver the solver handle
  * @param application the application
  * @param peer the peer to change the preference for
+ * @param scope the time interval for this feedback: [now - scope .. now]
  * @param kind the kind to change the preference
  * @param score the score
  */
@@ -899,6 +903,7 @@ void
 GAS_proportional_address_preference_feedback (void *solver,
                                                                                        void *application,
                                                                                        const struct GNUNET_PeerIdentity *peer,
+                                                                                       const struct GNUNET_TIME_Relative scope,
                                                                                        enum GNUNET_ATS_PreferenceKind kind,
                                                                                        double score)
 {
@@ -930,6 +935,11 @@ GAS_proportional_get_preferred_address (void *solver,
   GNUNET_assert (s != NULL);
   GNUNET_assert (peer != NULL);
 
+  /* Add to list of pending requests */
+  if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (s->requests, &peer->hashPubKey))
+    GNUNET_CONTAINER_multihashmap_put (s->requests, &peer->hashPubKey,
+        NULL, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
+
   /* Get address with: stick to current address, lower distance, lower latency */
   fba_ctx.s = s;
   fba_ctx.best = NULL;
@@ -938,11 +948,11 @@ GAS_proportional_get_preferred_address (void *solver,
                                               &find_best_address_it, &fba_ctx);
   if (NULL == fba_ctx.best)
   {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "Cannot suggest address for peer `%s'\n", GNUNET_i2s (peer));
+    LOG (GNUNET_ERROR_TYPE_INFO, "Cannot suggest address for peer `%s'\n", GNUNET_i2s (peer));
     return NULL;
   }
 
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Suggesting %s address %p for peer `%s'\n",
+  LOG (GNUNET_ERROR_TYPE_INFO, "Suggesting %s address %p for peer `%s'\n",
       (GNUNET_NO == fba_ctx.best->active) ? "inactive" : "active",
                fba_ctx.best, GNUNET_i2s (peer));
   net_cur = (struct Network *) fba_ctx.best->solver_information;
@@ -965,18 +975,16 @@ GAS_proportional_get_preferred_address (void *solver,
    * - update quota for previous address network
    * - update quota for this address network
    */
-
   prev = get_active_address (s, (struct GNUNET_CONTAINER_MultiHashMap *) s->addresses, peer);
   if (NULL != prev)
   {
       net_prev = (struct Network *) prev->solver_information;
       prev->active = GNUNET_NO; /* No active any longer */
-      prev->assigned_bw_in = GNUNET_BANDWIDTH_value_init (0); /* no bw assigned */
-      prev->assigned_bw_out = GNUNET_BANDWIDTH_value_init (0); /* no bw assigned */
-      s->bw_changed (s->bw_changed_cls, prev); /* notify about bw change, REQUIRED? */
+      prev->assigned_bw_in = BANDWIDTH_ZERO; /* no bandwidth assigned */
+      prev->assigned_bw_out = BANDWIDTH_ZERO; /* no bandwidth assigned */
       if (GNUNET_SYSERR == addresse_decrement (s, net_prev, GNUNET_NO, GNUNET_YES))
         GNUNET_break (0);
-       distribute_bandwidth_in_network (s, net_prev, NULL);
+      distribute_bandwidth_in_network (s, net_prev, NULL);
   }
 
   if (GNUNET_NO == (is_bandwidth_available_in_network (fba_ctx.best->solver_information)))
@@ -986,8 +994,8 @@ GAS_proportional_get_preferred_address (void *solver,
   }
 
   fba_ctx.best->active = GNUNET_YES;
-  addresse_increment(s, net_cur, GNUNET_NO, GNUNET_YES);
-  distribute_bandwidth_in_network (s, net_cur, fba_ctx.best);
+  addresse_increment (s, net_cur, GNUNET_NO, GNUNET_YES);
+  distribute_bandwidth_in_network (s, net_cur, NULL);
   return fba_ctx.best;
 }
 
@@ -1002,7 +1010,26 @@ void
 GAS_proportional_stop_get_preferred_address (void *solver,
                                      const struct GNUNET_PeerIdentity *peer)
 {
-       return;
+  struct GAS_PROPORTIONAL_Handle *s = solver;
+       struct ATS_Address *cur;
+       struct Network *cur_net;
+
+  if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (s->requests, &peer->hashPubKey))
+    GNUNET_CONTAINER_multihashmap_remove (s->requests, &peer->hashPubKey, NULL);
+
+  cur = get_active_address (s, (struct GNUNET_CONTAINER_MultiHashMap *) s->addresses, peer);
+  if (NULL != cur)
+  {
+    /* Disabling current address */
+    cur_net = (struct Network *) cur->solver_information;
+    cur->active = GNUNET_NO; /* No active any longer */
+    cur->assigned_bw_in = BANDWIDTH_ZERO; /* no bandwidth assigned */
+    cur->assigned_bw_out = BANDWIDTH_ZERO; /* no bandwidth assigned */
+    if (GNUNET_SYSERR == addresse_decrement (s, cur_net, GNUNET_NO, GNUNET_YES))
+      GNUNET_break (0);
+    distribute_bandwidth_in_network (s, cur_net, NULL);
+  }
+  return;
 }
 
 
@@ -1067,6 +1094,9 @@ GAS_proportional_address_delete (void *solver,
   {
       /* Address was active, remove from network and update quotas*/
       address->active = GNUNET_NO;
+      address->assigned_bw_in = BANDWIDTH_ZERO;
+      address->assigned_bw_out = BANDWIDTH_ZERO;
+
       if (GNUNET_SYSERR == addresse_decrement (s, net, GNUNET_NO, GNUNET_YES))
         GNUNET_break (0);
       distribute_bandwidth_in_network (s, net, NULL);
@@ -1144,10 +1174,10 @@ GAS_proportional_address_add (void *solver,
  */
 void
 GAS_proportional_address_property_changed (void *solver,
-                                                                                                                       struct ATS_Address *address,
-                                                                                                                       uint32_t type,
-                                                                                                                       uint32_t abs_value,
-                                                                                                                       double rel_value)
+                                          struct ATS_Address *address,
+                                          uint32_t type,
+                                          uint32_t abs_value,
+                                          double rel_value)
 {
        struct GAS_PROPORTIONAL_Handle *s;
        struct Network *n;
@@ -1196,9 +1226,9 @@ GAS_proportional_address_property_changed (void *solver,
  */
 void
 GAS_proportional_address_session_changed (void *solver,
-                                                                                                                       struct ATS_Address *address,
-                                                                                                                       uint32_t cur_session,
-                                                                                                                       uint32_t new_session)
+struct ATS_Address *address,
+uint32_t cur_session,
+uint32_t new_session)
 {
   if (cur_session!= new_session)
   {
@@ -1219,8 +1249,8 @@ GAS_proportional_address_session_changed (void *solver,
  */
 void
 GAS_proportional_address_inuse_changed (void *solver,
-                                                                                                                       struct ATS_Address *address,
-                                                                                                                       int in_use)
+struct ATS_Address *address,
+int in_use)
 {
        LOG (GNUNET_ERROR_TYPE_DEBUG,
                                                        "Usage changed to %s\n",
@@ -1262,31 +1292,40 @@ GAS_proportional_address_change_network (void *solver,
                         GNUNET_ATS_print_network_type (new_network));
 
   save_active = address->active;
-       /* remove from old network */
+
+  /* Disable and assign no bandwidth */
+       address->active = GNUNET_NO;
+       address->assigned_bw_in = BANDWIDTH_ZERO; /* no bandwidth assigned */
+       address->assigned_bw_out = BANDWIDTH_ZERO; /* no bandwidth assigned */
+
+       /* Remove from old network */
        GAS_proportional_address_delete (solver, address, GNUNET_NO);
 
-       /* set new network type */
-       new_net = get_network (solver, new_network);
-       if (NULL == new_net)
+       /* Set new network type */
+       if (NULL == (new_net = get_network (solver, new_network)))
        {
                /* Address changed to invalid network... */
-               LOG (GNUNET_ERROR_TYPE_ERROR, _("Cannot find network of type `%u' %s\n"),
+               LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid network type `%u' `%s': Disconnect!\n"),
                                new_network, GNUNET_ATS_print_network_type (new_network));
-               address->assigned_bw_in = GNUNET_BANDWIDTH_value_init (0);
-               address->assigned_bw_out = GNUNET_BANDWIDTH_value_init (0);
-               s->bw_changed  (s->bw_changed_cls, address);
+
+               /* Find new address to suggest since no bandwidth in network*/
+               if (NULL == (new = (struct ATS_Address *) GAS_proportional_get_preferred_address (s, &address->peer)))
+               {
+                       /* No alternative address found, disconnect peer */
+                       s->bw_changed  (s->bw_changed_cls, address);
+               }
                return;
        }
-       address->solver_information = new_net;
 
        /* Add to new network and update*/
+       address->solver_information = new_net;
        GAS_proportional_address_add (solver, address, new_network);
        if (GNUNET_YES == save_active)
        {
                /* check if bandwidth available in new network */
                if (GNUNET_YES == (is_bandwidth_available_in_network (new_net)))
                {
-                               /* Suggest updated address */
+                               /* Assign bandwidth to updated address */
                                address->active = GNUNET_YES;
                                addresse_increment (s, new_net, GNUNET_NO, GNUNET_YES);
                                distribute_bandwidth_in_network (solver, new_net, NULL);
@@ -1294,18 +1333,11 @@ GAS_proportional_address_change_network (void *solver,
                else
                {
                        LOG (GNUNET_ERROR_TYPE_DEBUG, "Not enough bandwidth in new network, suggesting alternative address ..\n");
-
-                       /* Set old address to zero bw */
-                       address->assigned_bw_in = GNUNET_BANDWIDTH_value_init (0);
-                       address->assigned_bw_out = GNUNET_BANDWIDTH_value_init (0);
-                       s->bw_changed  (s->bw_changed_cls, address);
-
                        /* Find new address to suggest since no bandwidth in network*/
-                       new = (struct ATS_Address *) GAS_proportional_get_preferred_address (s, &address->peer);
-                       if (NULL != new)
+                       if (NULL == (new = (struct ATS_Address *) GAS_proportional_get_preferred_address (s, &address->peer)))
                        {
-                                       /* Have an alternative address to suggest */
-                                       s->bw_changed  (s->bw_changed_cls, new);
+                               /* No alternative address found, disconnect peer */
+                               s->bw_changed  (s->bw_changed_cls, address);
                        }
                }
   }
@@ -1320,8 +1352,8 @@ GAS_proportional_address_change_network (void *solver,
  */
 void
 GAS_proportional_address_add (void *solver,
-                                                                                                                       struct ATS_Address *address,
-                                                                                                                       uint32_t network)
+                              struct ATS_Address *address,
+                              uint32_t network)
 {
   struct GAS_PROPORTIONAL_Handle *s = solver;
   struct Network *net = NULL;
@@ -1341,6 +1373,11 @@ GAS_proportional_address_add (void *solver,
   addresse_increment (s, net, GNUNET_YES, GNUNET_NO);
   aw->addr->solver_information = net;
 
+  if ((GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(s->requests, &address->peer.hashPubKey)) &&
+      (NULL == get_active_address (s,
+          (struct GNUNET_CONTAINER_MultiHashMap *) s->addresses, &address->peer)))
+      GAS_proportional_get_preferred_address (s, &address->peer);
+
   LOG (GNUNET_ERROR_TYPE_DEBUG, "After adding address now total %u and active %u addresses in network `%s'\n",
       net->total_addresses,
       net->active_addresses,
@@ -1418,6 +1455,8 @@ GAS_proportional_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
   s->bulk_lock = GNUNET_NO;
   s->addresses = addresses;
 
+  s->requests = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_YES);
+
   for (c = 0; c < dest_length; c++)
   {
       cur = &s->network_entries[c];
@@ -1495,6 +1534,7 @@ GAS_proportional_done (void *solver)
     GNUNET_break (0);
   }
   GNUNET_free (s->network_entries);
+  GNUNET_CONTAINER_multihashmap_destroy (s->requests);
   GNUNET_free (s);
 }