add address test
[oweals/gnunet.git] / src / ats / gnunet-service-ats_addresses.c
index 6da979d73968180141cda5d1452ddad4a9d59437..9388a66b4caca10779ab4841a0310c28daad527b 100644 (file)
 #include "gnunet-service-ats_scheduling.h"
 #include "gnunet-service-ats_reservations.h"
 #if HAVE_LIBGLPK
-#include "gnunet-service-ats_addresses_mlp.h"
+#include "gnunet-service-ats-solver_mlp.h"
 #endif
 #include "gnunet-service-ats-solver_proportional.h"
+#include "gnunet-service-ats-solver_ril.h"
 
 /**
  * NOTE: Do not change this documentation. This documentation is based on
  *    it as a value_number. If no configuration value is found it will assign
  *    GNUNET_ATS_DefaultBandwidth. The most important step is to load the
  *    configured solver using configuration "[ats]:MODE". Current solvers are
- *    MODE_SIMPLISTIC, MODE_MLP. Interaction is done using a solver API
+ *    MODE_PROPORTIONAL, MODE_MLP. Interaction is done using a solver API
  *
  *     1.4 Solver API
  *
 enum ATS_Mode
 {
   /*
-   * Simplistic mode:
+   * proportional mode:
    *
    * Assign each peer an equal amount of bandwidth (bw)
    *
    * bw_per_peer = bw_total / #active addresses
    */
-  MODE_SIMPLISTIC,
+  MODE_PROPORTIONAL,
 
   /*
    * MLP mode:
@@ -250,7 +251,14 @@ enum ATS_Mode
    * Solve ressource assignment as an optimization problem
    * Uses an mixed integer programming solver
    */
-  MODE_MLP
+  MODE_MLP,
+
+  /*
+   * Reinforcement Learning mode:
+   *
+   * Solve resource assignment using a learning agent
+   */
+  MODE_RIL
 };
 
 
@@ -338,10 +346,14 @@ struct GAS_Addresses_Handle
    */
   GAS_solver_address_add s_add;
 
-  /**
-   * Update address in solver
-   */
-  GAS_solver_address_update s_update;
+
+  GAS_solver_address_property_changed s_address_update_property;
+
+  GAS_solver_address_session_changed s_address_update_session;
+
+  GAS_solver_address_inuse_changed s_address_update_inuse;
+
+  GAS_solver_address_network_changed s_address_update_network;
 
   /**
    * Get address from solver
@@ -363,6 +375,21 @@ struct GAS_Addresses_Handle
    */
   GAS_solver_address_change_preference s_pref;
 
+  /**
+   * Give feedback about the current assignment
+   */
+  GAS_solver_address_feedback_preference s_feedback;
+
+  /**
+   * Start a bulk operation
+   */
+  GAS_solver_bulk_start s_bulk_start;
+
+  /**
+   * Bulk operation done
+   */
+  GAS_solver_bulk_stop s_bulk_stop;
+
   /**
    * Shutdown solver
    */
@@ -385,7 +412,7 @@ struct GAS_Addresses_Handle
  */
 static unsigned int
 disassemble_ats_information (struct ATS_Address *dest,
-                                                                                                                const struct GNUNET_ATS_Information *update,
+                             const struct GNUNET_ATS_Information *update,
                              uint32_t update_count,
                              struct GNUNET_ATS_Information **delta_dest,
                              uint32_t *delta_count)
@@ -411,72 +438,71 @@ disassemble_ats_information (struct ATS_Address *dest,
 
   if (NULL == dest->atsi)
   {
-               /* Create performance information */
-               dest->atsi = GNUNET_malloc (update_count * sizeof (struct GNUNET_ATS_Information));
-               dest->atsi_count = update_count;
-               memcpy (dest->atsi, update, update_count * sizeof (struct GNUNET_ATS_Information));
-               delta_atsi_count = update_count;
-               (*delta_dest) = GNUNET_malloc (update_count * sizeof (struct GNUNET_ATS_Information));
-               for (c1 = 0; c1 < update_count; c1 ++)
-               {
-                       (*delta_dest)[c1].type = update[c1].type;
-                       (*delta_dest)[c1].value = htonl(GNUNET_ATS_VALUE_UNDEFINED);
-               }
-               (*delta_count) = update_count;
-               return GNUNET_YES;
+    /* Create performance information */
+    dest->atsi = GNUNET_malloc (update_count * sizeof (struct GNUNET_ATS_Information));
+    dest->atsi_count = update_count;
+    memcpy (dest->atsi, update, update_count * sizeof (struct GNUNET_ATS_Information));
+    (*delta_dest) = GNUNET_malloc (update_count * sizeof (struct GNUNET_ATS_Information));
+    for (c1 = 0; c1 < update_count; c1 ++)
+    {
+      (*delta_dest)[c1].type = update[c1].type;
+      (*delta_dest)[c1].value = htonl(GNUNET_ATS_VALUE_UNDEFINED);
+    }
+    (*delta_count) = update_count;
+    return GNUNET_YES;
   }
 
   for (c1 = 0; c1 < update_count; c1++)
   {
-       /* Update existing performance information */
-       found = GNUNET_NO;
-       for (c2 = 0; c2 < dest->atsi_count; c2++)
-       {
-                       if (update[c1].type == dest->atsi[c2].type)
-                       {
-                               if (update[c1].value != dest->atsi[c2].value)
-                               {
-                                               /* Save previous value in delta */
-                                               delta_atsi[delta_atsi_count] = dest->atsi[c2];
-                                               delta_atsi_count ++;
-                                               /* Set new value */
-                                               dest->atsi[c2].value = update[c1].value;
-                                               change = GNUNET_YES;
-                               }
-                               found = GNUNET_YES;
-                               break;
-                       }
-       }
-               if (GNUNET_NO == found)
-               {
-                               add_atsi[add_atsi_count] = update[c1];
-                               add_atsi_count ++;
-                               delta_atsi[delta_atsi_count].type = update[c1].type;
-                               delta_atsi[delta_atsi_count].value = htonl (GNUNET_ATS_VALUE_UNDEFINED);
-                               delta_atsi_count ++;
-               }
+    /* Update existing performance information */
+    found = GNUNET_NO;
+    for (c2 = 0; c2 < dest->atsi_count; c2++)
+    {
+      if (update[c1].type == dest->atsi[c2].type)
+      {
+        if (update[c1].value != dest->atsi[c2].value)
+        {
+          /* Save previous value in delta */
+          delta_atsi[delta_atsi_count] = dest->atsi[c2];
+          delta_atsi_count ++;
+          /* Set new value */
+          dest->atsi[c2].value = update[c1].value;
+          change = GNUNET_YES;
+        }
+        found = GNUNET_YES;
+        break;
+      }
+    }
+    if (GNUNET_NO == found)
+    {
+      add_atsi[add_atsi_count] = update[c1];
+      add_atsi_count ++;
+      delta_atsi[delta_atsi_count].type = update[c1].type;
+      delta_atsi[delta_atsi_count].value = htonl (GNUNET_ATS_VALUE_UNDEFINED);
+      delta_atsi_count ++;
+    }
   }
 
   if (add_atsi_count > 0)
   {
-               /* Extend ats performance information */
-
-               tmp_atsi = GNUNET_malloc ((dest->atsi_count + add_atsi_count) *
-                                                                                                                       (sizeof (struct GNUNET_ATS_Information)));
-               memcpy (tmp_atsi, dest->atsi, dest->atsi_count * sizeof (struct GNUNET_ATS_Information));
-               memcpy (&tmp_atsi[dest->atsi_count], add_atsi, add_atsi_count * sizeof (struct GNUNET_ATS_Information));
-               GNUNET_free (dest->atsi);
-               dest->atsi = tmp_atsi;
-               dest->atsi_count = dest->atsi_count + add_atsi_count;
-                       change = GNUNET_YES;
+    /* Extend ats performance information */
+
+    tmp_atsi = GNUNET_malloc ((dest->atsi_count + add_atsi_count) *
+                              (sizeof (struct GNUNET_ATS_Information)));
+    memcpy (tmp_atsi, dest->atsi, dest->atsi_count * sizeof (struct GNUNET_ATS_Information));
+    memcpy (&tmp_atsi[dest->atsi_count], add_atsi, add_atsi_count * sizeof (struct GNUNET_ATS_Information));
+    GNUNET_free (dest->atsi);
+    dest->atsi = tmp_atsi;
+    dest->atsi_count = dest->atsi_count + add_atsi_count;
+    change = GNUNET_YES;
   }
 
   if (delta_atsi_count > 0)
   {
-               /* Copy delta */
-               (*delta_dest) = GNUNET_malloc (delta_atsi_count * sizeof (struct GNUNET_ATS_Information));
-               memcpy ((*delta_dest), delta_atsi, delta_atsi_count * sizeof (struct GNUNET_ATS_Information));
-               (*delta_count) = delta_atsi_count;
+    /* Copy delta */
+    (*delta_dest) = GNUNET_malloc (delta_atsi_count * sizeof (struct GNUNET_ATS_Information));
+    memcpy ((*delta_dest), delta_atsi, delta_atsi_count * sizeof (struct GNUNET_ATS_Information));
+    (*delta_count) = delta_atsi_count;
   }
 
   return change;
@@ -512,6 +538,8 @@ create_address (const struct GNUNET_PeerIdentity *peer,
                 uint32_t session_id)
 {
   struct ATS_Address *aa = NULL;
+  int c1;
+  int c2;
 
   aa = GNUNET_malloc (sizeof (struct ATS_Address) + plugin_addr_len);
   aa->peer = *peer;
@@ -527,29 +555,15 @@ create_address (const struct GNUNET_PeerIdentity *peer,
   aa->atsi_count = 0;
   aa->assigned_bw_in = GNUNET_BANDWIDTH_value_init(0);
   aa->assigned_bw_out = GNUNET_BANDWIDTH_value_init(0);
-  return aa;
-}
 
+  for (c1 = 0; c1 < GNUNET_ATS_QualityPropertiesCount; c1 ++)
+  {
+       aa->atsin[c1].avg_queue_index = 0;
+       for (c2 = 0; c2 < GAS_normalization_queue_length; c2++)
+               aa->atsin[c1].atsi_abs[c2] = GNUNET_ATS_VALUE_UNDEFINED;
+  }
 
-/**
- * Destroy the given address.
- *
- * @param handle the address handle
- * @param addr address to destroy
- * @return GNUNET_YES if bandwidth allocations should be recalcualted
- */
-static int
-destroy_address (struct GAS_Addresses_Handle *handle, struct ATS_Address *addr)
-{
-  int ret;
-
-  ret = GNUNET_NO;
-  GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multihashmap_remove (handle->addresses,
-                                                       &addr->peer.hashPubKey,
-                                                       addr));
-  free_address (addr);
-  return ret;
+  return aa;
 }
 
 
@@ -668,8 +682,7 @@ find_equivalent_address (struct GAS_Addresses_Handle *handle,
 
 
 /**
- * Lookup an ATS address by the address properties and session or return an
- * equivalent address with a session == 0
+ * Find the exact address
  *
  * @param handle the address handle to use
  * @param peer peer
@@ -677,20 +690,16 @@ find_equivalent_address (struct GAS_Addresses_Handle *handle,
  * @param plugin_addr plugin address
  * @param plugin_addr_len length of the plugin address
  * @param session_id session id, can be 0
- * @param atsi performance information for this address
- * @param atsi_count number of performance information contained
  * @return an ATS_address or NULL
  */
 
 static struct ATS_Address *
-lookup_address (struct GAS_Addresses_Handle *handle,
+find_exact_address (struct GAS_Addresses_Handle *handle,
                 const struct GNUNET_PeerIdentity *peer,
                 const char *plugin_name,
                 const void *plugin_addr,
                 size_t plugin_addr_len,
-                uint32_t session_id,
-                const struct GNUNET_ATS_Information *atsi,
-                uint32_t atsi_count)
+                uint32_t session_id)
 {
   struct ATS_Address *aa;
   struct ATS_Address *ea;
@@ -704,16 +713,13 @@ lookup_address (struct GAS_Addresses_Handle *handle,
   ea = find_equivalent_address (handle, peer, aa);
   free_address (aa);
   if (ea == NULL)
-  {
     return NULL;
-  }
   else if (ea->session_id != session_id)
-  {
     return NULL;
-  }
   return ea;
 }
 
+
 /**
  * Extract an ATS performance info from an address
  *
@@ -754,17 +760,20 @@ get_performance_info (struct ATS_Address *address, uint32_t type)
 void
 GAS_addresses_add (struct GAS_Addresses_Handle *handle,
                    const struct GNUNET_PeerIdentity *peer,
-                   const char *plugin_name, const void *plugin_addr,
-                   size_t plugin_addr_len, uint32_t session_id,
+                   const char *plugin_name,
+                   const void *plugin_addr,
+                   size_t plugin_addr_len,
+                   uint32_t session_id,
                    const struct GNUNET_ATS_Information *atsi,
                    uint32_t atsi_count)
 {
-  struct ATS_Address *aa;
-  struct ATS_Address *ea;
+  struct ATS_Address *new_address;
+  struct ATS_Address *existing_address;
   struct GNUNET_ATS_Information *atsi_delta;
   uint32_t atsi_delta_count;
   uint32_t addr_net;
-
+  uint32_t previous_session;
+  int c1;
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Received `%s' for peer `%s'\n",
@@ -776,78 +785,122 @@ GAS_addresses_add (struct GAS_Addresses_Handle *handle,
 
   GNUNET_assert (NULL != handle->addresses);
 
-  aa = create_address (peer, plugin_name, plugin_addr, plugin_addr_len,
+  new_address = create_address (peer, plugin_name, plugin_addr, plugin_addr_len,
                        session_id);
   atsi_delta = NULL;
-  disassemble_ats_information (aa, atsi, atsi_count, &atsi_delta, &atsi_delta_count);
+  disassemble_ats_information (new_address, atsi, atsi_count, &atsi_delta, &atsi_delta_count);
   GNUNET_free_non_null (atsi_delta);
-  addr_net = get_performance_info (aa, GNUNET_ATS_NETWORK_TYPE);
+  addr_net = get_performance_info (new_address, GNUNET_ATS_NETWORK_TYPE);
   if (GNUNET_ATS_VALUE_UNDEFINED == addr_net)
                addr_net = GNUNET_ATS_NET_UNSPECIFIED;
 
   /* Get existing address or address with session == 0 */
-  ea = find_equivalent_address (handle, peer, aa);
-  if (ea == NULL)
+  existing_address = find_equivalent_address (handle, peer, new_address);
+  if (existing_address == NULL)
   {
-    /* We have a new address */
+    /* Add a new address */
     GNUNET_assert (GNUNET_OK ==
                    GNUNET_CONTAINER_multihashmap_put (handle->addresses,
-                                                      &peer->hashPubKey, aa,
-                                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Added new address for peer `%s' session id %u, %p\n",
-                GNUNET_i2s (peer), session_id, aa);
+                      &peer->hashPubKey, new_address,
+                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
+
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Adding new address %p for peer `%s', length %u, session id %u, %s\n",
+               new_address, GNUNET_i2s (peer), plugin_addr_len, session_id, GNUNET_ATS_print_network_type(addr_net));
+
     /* Tell solver about new address */
-    handle->s_add (handle->solver, handle->addresses, aa, addr_net);
+    handle->s_add (handle->solver, new_address, addr_net);
+
+    handle->s_bulk_start (handle->solver);
+    GAS_normalization_normalize_property (handle->addresses, new_address, atsi, atsi_count);
+    handle->s_bulk_stop (handle->solver);
+
     /* Notify performance clients about new address */
-    GAS_performance_notify_all_clients (&aa->peer,
-        aa->plugin,
-        aa->addr, aa->addr_len,
-        aa->session_id,
-        aa->atsi, aa->atsi_count,
-        aa->assigned_bw_out,
-        aa->assigned_bw_in);
+    GAS_performance_notify_all_clients (&new_address->peer,
+        new_address->plugin,
+        new_address->addr, new_address->addr_len,
+        new_address->session_id,
+        new_address->atsi, new_address->atsi_count,
+        new_address->assigned_bw_out,
+        new_address->assigned_bw_in);
     return;
   }
 
-  GNUNET_free (aa->plugin);
-  GNUNET_free_non_null (aa->atsi);
-  GNUNET_free (aa);
-  aa = NULL;
+  /* We have an existing address we can use, clean up new */
+  GNUNET_free (new_address->plugin);
+  GNUNET_free_non_null (new_address->atsi);
+  GNUNET_free (new_address);
+  new_address = NULL;
 
-  if (ea->session_id != 0)
+  if (0 != existing_address->session_id)
   {
-      /* This address with the same session is already existing
-       * Should not happen */
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "Added already existing address for peer `%s' `%s' %p with new session %u\n",
-                GNUNET_i2s (peer), plugin_name, session_id);
+      /* Should not happen */
       GNUNET_break (0);
       return;
   }
 
+  addr_net = get_performance_info (existing_address, GNUNET_ATS_NETWORK_TYPE);
+  if (GNUNET_ATS_VALUE_UNDEFINED == addr_net)
+               addr_net = GNUNET_ATS_NET_UNSPECIFIED;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+           "Found existing address for peer `%s' %p with new session %u in network %s\n",
+           GNUNET_i2s (peer),
+           existing_address,
+           session_id,
+           GNUNET_ATS_print_network_type (addr_net));
   /* We have an address without an session, update this address */
   atsi_delta = NULL;
   atsi_delta_count = 0;
-  if (GNUNET_YES == disassemble_ats_information (ea, atsi, atsi_count, &atsi_delta, &atsi_delta_count))
+  if (GNUNET_YES == disassemble_ats_information (existing_address, atsi, atsi_count, &atsi_delta, &atsi_delta_count))
   {
-               GAS_performance_notify_all_clients (&ea->peer,
-                               ea->plugin,
-                               ea->addr, ea->addr_len,
-                               ea->session_id,
-                               ea->atsi, ea->atsi_count,
-                               ea->assigned_bw_out,
-                               ea->assigned_bw_in);
+    /* Notify performance clients about properties */
+    GAS_performance_notify_all_clients (&existing_address->peer,
+                existing_address->plugin,
+                existing_address->addr, existing_address->addr_len,
+                existing_address->session_id,
+                existing_address->atsi, existing_address->atsi_count,
+                existing_address->assigned_bw_out,
+                existing_address->assigned_bw_in);
+
+    for (c1 = 0; c1 < atsi_delta_count; c1++)
+    {
+      if ((GNUNET_ATS_NETWORK_TYPE == ntohl (atsi_delta[c1].type)) &&
+              (addr_net != ntohl (atsi_delta[c1].value)))
+      {
+          /* Network type changed */
+          GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Address for peer `%s' %p changed from network %s to %s\n",
+                  GNUNET_i2s (peer), existing_address,
+                  GNUNET_ATS_print_network_type (addr_net),
+                  GNUNET_ATS_print_network_type (ntohl (atsi_delta[c1].value)));
+          handle->s_address_update_network (handle->solver, existing_address,
+                  ntohl (atsi_delta[c1].value),
+                  get_performance_info (existing_address, GNUNET_ATS_NETWORK_TYPE));
+          addr_net = get_performance_info (existing_address, GNUNET_ATS_NETWORK_TYPE);
+      }
+    }
+    /* Notify solver about update with atsi information and session */
+    handle->s_bulk_start (handle->solver);
+    GAS_normalization_normalize_property (handle->addresses, existing_address, atsi, atsi_count);
+    handle->s_bulk_stop (handle->solver);
   }
-
-  /* Notify solver about update with atsi information and session */
-  handle->s_update (handle->solver, handle->addresses, ea, session_id, ea->used, atsi_delta, atsi_delta_count);
   GNUNET_free_non_null (atsi_delta);
 
-  /* Do the update */
-  ea->session_id = session_id;
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-           "Updated existing address for peer `%s' %p with new session %u\n",
-           GNUNET_i2s (peer), ea, session_id);
+  /* Notify solver about new session */
+  if (existing_address->session_id == session_id)
+       return; /* possible, can both be 0 since address is revalidated */
+
+  previous_session = existing_address->session_id;
+  existing_address->session_id = session_id;
+  handle->s_address_update_session (handle->solver, existing_address,
+               previous_session, session_id);
+
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+           "Updated existing address for peer `%s' %p length %u with new session %u in network %s\n",
+           GNUNET_i2s (peer),
+           existing_address,
+           existing_address->addr_len,
+           session_id,
+           GNUNET_ATS_print_network_type(addr_net));
 }
 
 
@@ -878,6 +931,7 @@ GAS_addresses_update (struct GAS_Addresses_Handle *handle,
   struct GNUNET_ATS_Information *atsi_delta;
   uint32_t atsi_delta_count;
   uint32_t prev_session;
+  int c1;
 
   if (GNUNET_NO == handle->running)
     return;
@@ -885,8 +939,8 @@ GAS_addresses_update (struct GAS_Addresses_Handle *handle,
   GNUNET_assert (NULL != handle->addresses);
 
   /* Get existing address */
-  aa = lookup_address (handle, peer, plugin_name, plugin_addr, plugin_addr_len,
-                       session_id, atsi, atsi_count);
+  aa = find_exact_address (handle, peer, plugin_name,
+        plugin_addr, plugin_addr_len, session_id);
   if (aa == NULL)
   {
     /* GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Tried to update unknown address for peer `%s' `%s' session id %u\n", */
@@ -895,31 +949,56 @@ GAS_addresses_update (struct GAS_Addresses_Handle *handle,
     return;
   }
 
+  if (NULL == aa->solver_information)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Tried to update unknown address for peer `%s' `%s' session id %u\n",
+                 GNUNET_i2s (peer), plugin_name, session_id);
+    return;
+  }
+
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "Received `%s' for peer `%s' address \n",
                 "ADDRESS UPDATE",
                 GNUNET_i2s (peer), aa);
 
   /* Update address */
+  if (session_id != aa->session_id)
+  {
+       /* Session changed */
+    prev_session = aa->session_id;
+    aa->session_id = session_id;
+    handle->s_address_update_session (handle->solver, aa, prev_session, aa->session_id);
+  }
+
   atsi_delta = NULL;
   atsi_delta_count = 0;
   if (GNUNET_YES == disassemble_ats_information (aa, atsi, atsi_count, &atsi_delta, &atsi_delta_count))
   {
-               /* Notify performance clients about updated address */
-               GAS_performance_notify_all_clients (&aa->peer,
-                               aa->plugin,
-                               aa->addr, aa->addr_len,
-                               aa->session_id,
-                               aa->atsi, aa->atsi_count,
-                               aa->assigned_bw_out,
-                               aa->assigned_bw_in);
-  }
-  prev_session = aa->session_id;
-  aa->session_id = session_id;
-
+    /* ATS properties changed */
+    for (c1 = 0; c1 < atsi_delta_count; c1++)
+    {
+        if (GNUNET_ATS_NETWORK_TYPE == ntohl (atsi_delta[c1].type))
+        {
+            /* Network type changed */
+            handle->s_address_update_network (handle->solver, aa,
+                      ntohl (atsi_delta[c1].value),
+                      get_performance_info (aa, GNUNET_ATS_NETWORK_TYPE));
+        }
+    }
 
-  /* Tell solver about update */
-  handle->s_update (handle->solver, handle->addresses, aa, prev_session, aa->used, atsi_delta, atsi_delta_count);
+    /* Notify performance clients about updated address */
+    GAS_performance_notify_all_clients (&aa->peer,
+                    aa->plugin,
+                    aa->addr, aa->addr_len,
+                    aa->session_id,
+                    aa->atsi, aa->atsi_count,
+                    aa->assigned_bw_out,
+                    aa->assigned_bw_in);
+
+    handle->s_bulk_start (handle->solver);
+    GAS_normalization_normalize_property (handle->addresses, aa, atsi, atsi_count);
+    handle->s_bulk_stop (handle->solver);
+  }
   GNUNET_free_non_null (atsi_delta);
 }
 
@@ -970,13 +1049,16 @@ destroy_by_session_id (void *cls, const struct GNUNET_HashCode * key, void *valu
         (0 == memcmp (des->addr, aa->addr, aa->addr_len)))
     {
 
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
                   "Deleting full address for peer `%s' session %u %p\n",
                   GNUNET_i2s (&aa->peer), aa->session_id, aa);
 
       /* Notify solver about deletion */
-      handle->s_del (handle->solver, handle->addresses, aa, GNUNET_NO);
-      destroy_address (handle, aa);
+      GNUNET_assert (GNUNET_YES ==
+               GNUNET_CONTAINER_multihashmap_remove (handle->addresses,
+                       &aa->peer.hashPubKey, aa));
+      handle->s_del (handle->solver, aa, GNUNET_NO);
+      free_address (aa);
       dc->result = GNUNET_NO;
       return GNUNET_OK; /* Continue iteration */
     }
@@ -990,7 +1072,7 @@ destroy_by_session_id (void *cls, const struct GNUNET_HashCode * key, void *valu
     if ((aa->session_id != 0) &&
         (0 != strcmp (des->plugin, aa->plugin)))
     {
-        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                     "Different plugins during removal: `%s' vs `%s' \n",
                     des->plugin, aa->plugin);
         GNUNET_break (0);
@@ -1000,25 +1082,29 @@ destroy_by_session_id (void *cls, const struct GNUNET_HashCode * key, void *valu
     if (aa->addr_len == 0)
     {
         /* Inbound connection died, delete full address */
-        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+        GNUNET_log (GNUNET_ERROR_TYPE_INFO,
                     "Deleting inbound address for peer `%s': `%s' session %u\n",
                     GNUNET_i2s (&aa->peer), aa->plugin, aa->session_id);
 
         /* Notify solver about deletion */
-        handle->s_del (handle->solver, handle->addresses, aa, GNUNET_NO);
-        destroy_address (handle, aa);
+        GNUNET_assert (GNUNET_YES ==
+                       GNUNET_CONTAINER_multihashmap_remove (handle->addresses,
+                       &aa->peer.hashPubKey, aa));
+        handle->s_del (handle->solver, aa, GNUNET_NO);
+        free_address (aa);
         dc->result = GNUNET_NO;
         return GNUNET_OK; /* Continue iteration */
     }
     else
     {
         /* Session died */
-        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+        GNUNET_log (GNUNET_ERROR_TYPE_INFO,
                     "Deleting session for peer `%s': `%s' %u\n",
                     GNUNET_i2s (&aa->peer), aa->plugin, aa->session_id);
         /* Notify solver to delete session */
-        handle->s_del (handle->solver, handle->addresses, aa, GNUNET_YES);
+        handle->s_del (handle->solver, aa, GNUNET_YES);
         aa->session_id = 0;
+        aa->active = GNUNET_NO;
         return GNUNET_OK;
     }
   }
@@ -1046,19 +1132,12 @@ GAS_addresses_destroy (struct GAS_Addresses_Handle *handle,
 {
   struct ATS_Address *ea;
   struct DestroyContext dc;
-
   if (GNUNET_NO == handle->running)
     return;
 
   /* Get existing address */
-  ea = lookup_address (handle, peer, plugin_name, plugin_addr, plugin_addr_len,
-                       session_id, NULL, 0);
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Received `%s' for peer `%s' address %p session %u\n",
-              "ADDRESS DESTROY",
-              GNUNET_i2s (peer), ea, session_id);
-
+  ea = find_exact_address (handle, peer, plugin_name, plugin_addr,
+               plugin_addr_len, session_id);
   if (ea == NULL)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Tried to destroy unknown address for peer `%s' `%s' session id %u\n",
@@ -1066,6 +1145,11 @@ GAS_addresses_destroy (struct GAS_Addresses_Handle *handle,
     return;
   }
 
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Received `%s' for peer `%s' address %p session %u\n",
+              "ADDRESS DESTROY",
+              GNUNET_i2s (peer), ea, session_id);
+
   GNUNET_break (0 < strlen (plugin_name));
   dc.handle = handle;
   dc.aa = create_address (peer, plugin_name, plugin_addr, plugin_addr_len, session_id);
@@ -1105,8 +1189,6 @@ GAS_addresses_in_use (struct GAS_Addresses_Handle *handle,
                       int in_use)
 {
   struct ATS_Address *ea;
-  int prev_inuse;
-
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "Received `%s' for peer `%s'\n",
                 "ADDRESS IN USE",
@@ -1115,13 +1197,12 @@ GAS_addresses_in_use (struct GAS_Addresses_Handle *handle,
   if (GNUNET_NO == handle->running)
     return GNUNET_SYSERR;
 
-  ea = lookup_address (handle, peer, plugin_name,
-                        plugin_addr, plugin_addr_len,
-                        session_id, NULL, 0);
+  ea = find_exact_address (handle, peer, plugin_name,
+               plugin_addr, plugin_addr_len, session_id);
   if (NULL == ea)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "Trying to set unknown address `%s', %s %u %s \n",
+                "Trying to set unknown address `%s' `%s' `%u' to %s \n",
                 GNUNET_i2s (peer),
                 plugin_name, session_id,
                 (GNUNET_NO == in_use) ? "NO" : "YES");
@@ -1140,11 +1221,8 @@ GAS_addresses_in_use (struct GAS_Addresses_Handle *handle,
   }
 
   /* Tell solver about update */
-  prev_inuse = ea->used;
   ea->used = in_use;
-  handle->s_update (handle->solver, handle->addresses, ea, session_id, prev_inuse, NULL, 0);
-
-
+  handle->s_address_update_inuse (handle->solver, ea, ea->used);
   return GNUNET_OK;
 }
 
@@ -1177,7 +1255,7 @@ GAS_addresses_request_address_cancel (struct GAS_Addresses_Handle *handle,
                   "No address requests pending for peer `%s', cannot remove!\n", GNUNET_i2s (peer));
       return;
   }
-  handle->s_get_stop (handle->solver, handle->addresses, peer);
+  handle->s_get_stop (handle->solver, peer);
   GAS_addresses_handle_backoff_reset (handle, peer);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Removed request pending for peer `%s\n", GNUNET_i2s (peer));
@@ -1185,6 +1263,23 @@ GAS_addresses_request_address_cancel (struct GAS_Addresses_Handle *handle,
   GNUNET_free (cur);
 }
 
+/*
+static int
+addrinfo_it (void *cls, const struct GNUNET_HashCode *key, void *value)
+{
+       static int count = 0;
+       struct GNUNET_PeerIdentity *id = cls;
+       struct ATS_Address *aa = value;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "[%u] Peer `%s' %s length %u session %u active %s\n",
+              count, GNUNET_i2s (id), aa->plugin, aa->addr_len, aa->session_id,
+              (GNUNET_YES == aa->active) ? "active" : "inactive");
+
+  count ++;
+       return GNUNET_OK;
+}
+*/
 
 /**
  * Request address suggestions for a peer
@@ -1199,7 +1294,7 @@ GAS_addresses_request_address (struct GAS_Addresses_Handle *handle,
   struct GAS_Addresses_Suggestion_Requests *cur = handle->r_head;
   struct ATS_Address *aa;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
               "Received `%s' for peer `%s'\n",
               "REQUEST ADDRESS",
               GNUNET_i2s (peer));
@@ -1219,11 +1314,18 @@ GAS_addresses_request_address (struct GAS_Addresses_Handle *handle,
       GNUNET_CONTAINER_DLL_insert (handle->r_head, handle->r_tail, cur);
   }
 
+  /*
+   * Debuging information about addresses
+   *
+   * GNUNET_CONTAINER_multihashmap_get_multiple(handle->addresses,
+   *  &peer->hashPubKey, &addrinfo_it, (void *) peer);
+   */
+
   /* Get prefered address from solver */
-  aa = (struct ATS_Address *) handle->s_get (handle->solver, handle->addresses, peer);
+  aa = (struct ATS_Address *) handle->s_get (handle->solver, peer);
   if (NULL == aa)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
                 "Cannot suggest address for peer `%s'\n", GNUNET_i2s (peer));
     return;
   }
@@ -1295,19 +1397,84 @@ GAS_addresses_handle_backoff_reset (struct GAS_Addresses_Handle *handle,
                                               NULL));
 }
 
+
+/**
+ * The preference changed for a peer
+ *
+ * @param cls the address handle
+ * @param peer the peer
+ * @param kind the ATS kind
+ * @param pref_rel the new relative preference value
+ */
 static void
 normalized_preference_changed_cb (void *cls,
-                                                                                                                                       const struct GNUNET_PeerIdentity *peer,
-                                                                                                                               enum GNUNET_ATS_PreferenceKind kind,
-                                                                                                                               double pref_rel)
+                                  const struct GNUNET_PeerIdentity *peer,
+                                  enum GNUNET_ATS_PreferenceKind kind,
+                                  double pref_rel)
 {
-       GNUNET_assert (NULL != cls);
-       struct GAS_Addresses_Handle *handle = cls;
+  GNUNET_assert (NULL != cls);
+  struct GAS_Addresses_Handle *handle = cls;
+
   /* Tell solver about update */
-  handle->s_pref (handle->solver, handle->addresses, peer, kind, pref_rel);
+  handle->s_pref (handle->solver, peer, kind, pref_rel);
 }
 
 
+/**
+ * The relative value for a property changed
+ *
+ * @param cls the address handle
+ * @param address the peer
+ * @param type the ATS type
+ * @param prop_rel the new relative preference value
+ */
+static void
+normalized_property_changed_cb (void *cls,
+                                struct ATS_Address *address,
+                                uint32_t type,
+                                double prop_rel)
+{
+  struct GAS_Addresses_Handle *ah = (struct GAS_Addresses_Handle *) cls;
+  GNUNET_assert (NULL != ah);
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+        "Normalized property %s for peer `%s' changed to %.3f \n",
+        GNUNET_ATS_print_property_type (type),
+        GNUNET_i2s (&address->peer),
+        prop_rel);
+
+  ah->s_address_update_property (ah->solver, address, type, 0, prop_rel);
+}
+
+
+/**
+ * Function allowing the solver to obtain normalized preference
+ * values from solver
+ *
+ * @param cls unused
+ * @param id the peer to return the normalized properties for
+ * @return array of double values with |GNUNET_ATS_PreferenceCount| elements
+ */
+const double *
+get_preferences_cb (void *cls, const struct GNUNET_PeerIdentity *id)
+{
+       return GAS_normalization_get_preferences (id);
+}
+
+/**
+ * Function allowing the solver to obtain normalized property
+ * values for an address from solver
+ *
+ * @param cls unused
+ * @param address the address
+ * @return array of double values with |GNUNET_ATS_QualityPropertiesCount| elements
+ */
+const double *
+get_property_cb (void *cls, const struct ATS_Address *address)
+{
+       return GAS_normalization_get_properties ((struct ATS_Address *) address);
+}
+
 /**
  * Change the preference for a peer
  *
@@ -1324,10 +1491,10 @@ GAS_addresses_change_preference (struct GAS_Addresses_Handle *handle,
                                  enum GNUNET_ATS_PreferenceKind kind,
                                  float score_abs)
 {
-       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Received `%s' for peer `%s' for client %p\n",
-              "CHANGE PREFERENCE",
-              GNUNET_i2s (peer), client);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+        "Received `%s' for peer `%s' for client %p\n",
+        "CHANGE PREFERENCE",
+        GNUNET_i2s (peer), client);
 
   if (GNUNET_NO == handle->running)
     return;
@@ -1341,8 +1508,51 @@ GAS_addresses_change_preference (struct GAS_Addresses_Handle *handle,
                   GNUNET_i2s (peer), client);
       return;
   }
+
+  handle->s_bulk_start (handle->solver);
   /* Tell normalization about change, normalization will call callback if preference changed */
-  GAS_normalization_change_preference (client, peer, kind, score_abs);
+  GAS_normalization_normalize_preference (client, peer, kind, score_abs);
+  handle->s_bulk_stop (handle->solver);
+}
+
+
+/**
+ * Change the preference for a peer
+ *
+ * @param handle the address handle
+ * @param application the client sending this request
+ * @param peer the peer id
+ * @param scope the time interval for this feedback: [now - scope .. now]
+ * @param kind the preference kind to change
+ * @param score_abs the new preference score
+ */
+void
+GAS_addresses_preference_feedback (struct GAS_Addresses_Handle *handle,
+                                  void *application,
+                                  const struct GNUNET_PeerIdentity *peer,
+                                  const struct GNUNET_TIME_Relative scope,
+                                  enum GNUNET_ATS_PreferenceKind kind,
+                                  float score_abs)
+{
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+        "Received `%s' for peer `%s' for client %p\n",
+        "PREFERENCE FEEDBACK",
+        GNUNET_i2s (peer), application);
+
+  if (GNUNET_NO == handle->running)
+    return;
+
+  if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->addresses,
+                                                          &peer->hashPubKey))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "Received `%s' for unknown peer `%s' from client %p\n",
+                "PREFERENCE FEEDBACK",
+                GNUNET_i2s (peer), application);
+    return;
+  }
+
+  handle->s_feedback (handle->solver, application, peer, scope, kind, score_abs);
 }
 
 
@@ -1356,7 +1566,10 @@ GAS_addresses_change_preference (struct GAS_Addresses_Handle *handle,
  * @return number of networks loaded
  */
 static unsigned int
-load_quotas (const struct GNUNET_CONFIGURATION_Handle *cfg, unsigned long long *out_dest, unsigned long long *in_dest, int dest_length)
+load_quotas (const struct GNUNET_CONFIGURATION_Handle *cfg,
+            unsigned long long *out_dest,
+            unsigned long long *in_dest,
+            int dest_length)
 {
   char *network_str[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkTypeString;
   char * entry_in = NULL;
@@ -1463,7 +1676,8 @@ bandwidth_changed_cb (void *cls, struct ATS_Address *address)
   GNUNET_assert (handle != NULL);
   GNUNET_assert (address != NULL);
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Bandwidth assignment changed for peer %s \n", GNUNET_i2s(&address->peer));
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Bandwidth assignment changed for peer %s \n",
+               GNUNET_i2s(&address->peer));
 
   /* Notify performance clients about changes to address */
   GAS_performance_notify_all_clients (&address->peer,
@@ -1482,13 +1696,26 @@ bandwidth_changed_cb (void *cls, struct ATS_Address *address)
   }
   if (NULL == cur)
   {
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
                   "Nobody is interested in peer `%s' :(\n",GNUNET_i2s (&address->peer));
       return;
   }
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Sending bandwidth update for peer `%s'\n",GNUNET_i2s (&address->peer));
+  if ((0 == ntohl (address->assigned_bw_in.value__)) &&
+               (0 == ntohl (address->assigned_bw_out.value__)))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "Telling transport to disconnect peer `%s'\n",
+                GNUNET_i2s (&address->peer));
+  }
+  else
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "Sending bandwidth update for peer `%s': %llu %llu\n",
+                GNUNET_i2s (&address->peer),
+                address->assigned_bw_out,
+                address->assigned_bw_out);
+  }
 
   /* *Notify scheduling clients about suggestion */
   GAS_scheduling_transmit_address_suggestion (&address->peer,
@@ -1505,7 +1732,7 @@ bandwidth_changed_cb (void *cls, struct ATS_Address *address)
  * Initialize address subsystem. The addresses subsystem manages the addresses
  * known and current performance information. It has a solver component
  * responsible for the resource allocation. It tells the solver about changes
- * and receives updates when the solver changes the ressource allocation.
+ * and receives updates when the solver changes the resource allocation.
  *
  * @param cfg configuration to use
  * @param stats the statistics handle to use
@@ -1534,29 +1761,33 @@ GAS_addresses_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
   /* Figure out configured solution method */
   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg, "ats", "MODE", &mode_str))
   {
-      GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "No ressource assignment method configured, using simplistic approch\n");
-      ah->ats_mode = MODE_SIMPLISTIC;
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "No resource assignment method configured, using proportional approach\n");
+      ah->ats_mode = MODE_PROPORTIONAL;
   }
   else
   {
       for (c = 0; c < strlen (mode_str); c++)
         mode_str[c] = toupper (mode_str[c]);
-      if (0 == strcmp (mode_str, "SIMPLISTIC"))
+      if (0 == strcmp (mode_str, "PROPORTIONAL"))
       {
-          ah->ats_mode = MODE_SIMPLISTIC;
+          ah->ats_mode = MODE_PROPORTIONAL;
       }
       else if (0 == strcmp (mode_str, "MLP"))
       {
           ah->ats_mode = MODE_MLP;
 #if !HAVE_LIBGLPK
-          GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Assignment method `%s' configured, but GLPK is not availabe, please install \n", mode_str);
-          ah->ats_mode = MODE_SIMPLISTIC;
+          GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Assignment method `%s' configured, but GLPK is not available, please install \n", mode_str);
+          ah->ats_mode = MODE_PROPORTIONAL;
 #endif
       }
+      else if (0 == strcmp (mode_str, "RIL"))
+      {
+         ah->ats_mode = MODE_RIL;
+      }
       else
       {
-          GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid ressource assignment method `%s' configured, using simplistic approch\n", mode_str);
-          ah->ats_mode = MODE_SIMPLISTIC;
+          GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid resource assignment method `%s' configured, using proportional approach\n", mode_str);
+          ah->ats_mode = MODE_PROPORTIONAL;
       }
       GNUNET_free (mode_str);
   }
@@ -1566,33 +1797,61 @@ GAS_addresses_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
     case MODE_MLP:
       /* Init the MLP solver with default values */
 #if HAVE_LIBGLPK
-      ah->ats_mode = MODE_MLP;
       ah->s_init = &GAS_mlp_init;
       ah->s_add = &GAS_mlp_address_add;
-      ah->s_update = &GAS_mlp_address_update;
+      ah->s_address_update_property = &GAS_mlp_address_property_changed;
+      ah->s_address_update_session = &GAS_mlp_address_session_changed;
+      ah->s_address_update_inuse = &GAS_mlp_address_inuse_changed;
+      ah->s_address_update_network = &GAS_mlp_address_change_network;
       ah->s_get = &GAS_mlp_get_preferred_address;
       ah->s_get_stop = &GAS_mlp_stop_get_preferred_address;
       ah->s_pref = &GAS_mlp_address_change_preference;
+      ah->s_feedback = &GAS_mlp_address_preference_feedback;
       ah->s_del =  &GAS_mlp_address_delete;
+      ah->s_bulk_start = &GAS_mlp_bulk_start;
+      ah->s_bulk_stop = &GAS_mlp_bulk_stop;
       ah->s_done = &GAS_mlp_done;
 #else
       GNUNET_free (ah);
       return NULL;
 #endif
       break;
-    case MODE_SIMPLISTIC:
-      /* Init the simplistic solver with default values */
-      ah->ats_mode = MODE_SIMPLISTIC;
+    case MODE_PROPORTIONAL:
+      /* Init the proportional solver with default values */
       ah->s_init = &GAS_proportional_init;
       ah->s_add = &GAS_proportional_address_add;
-      ah->s_update = &GAS_proportional_address_update;
+      ah->s_address_update_property = &GAS_proportional_address_property_changed;
+      ah->s_address_update_session = &GAS_proportional_address_session_changed;
+      ah->s_address_update_inuse = &GAS_proportional_address_inuse_changed;
+      ah->s_address_update_network = &GAS_proportional_address_change_network;
       ah->s_get = &GAS_proportional_get_preferred_address;
       ah->s_get_stop = &GAS_proportional_stop_get_preferred_address;
       ah->s_pref = &GAS_proportional_address_change_preference;
+      ah->s_feedback = &GAS_proportional_address_preference_feedback;
       ah->s_del  = &GAS_proportional_address_delete;
+      ah->s_bulk_start = &GAS_proportional_bulk_start;
+      ah->s_bulk_stop = &GAS_proportional_bulk_stop;
       ah->s_done = &GAS_proportional_done;
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ATS started in %s mode\n", "SIMPLISTIC");
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ATS started in %s mode\n", "PROPORTIONAL");
       break;
+    case MODE_RIL:
+      /* Init the ril solver with default values */
+         ah->s_init = &GAS_ril_init;
+         ah->s_add = &GAS_ril_address_add;
+         ah->s_address_update_property = &GAS_ril_address_property_changed;
+         ah->s_address_update_session = &GAS_ril_address_session_changed;
+         ah->s_address_update_inuse = &GAS_ril_address_inuse_changed;
+         ah->s_address_update_network = &GAS_ril_address_change_network;
+         ah->s_get = &GAS_ril_get_preferred_address;
+         ah->s_get_stop = &GAS_ril_stop_get_preferred_address;
+         ah->s_pref = &GAS_ril_address_change_preference;
+         ah->s_feedback = &GAS_ril_address_preference_feedback;
+         ah->s_del  = &GAS_ril_address_delete;
+         ah->s_bulk_start = &GAS_ril_bulk_start;
+         ah->s_bulk_stop = &GAS_ril_bulk_stop;
+         ah->s_done = &GAS_ril_done;
+         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ATS started in %s mode\n", "RIL");
+         break;
     default:
       return NULL;
       break;
@@ -1600,20 +1859,31 @@ GAS_addresses_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
 
   GNUNET_assert (NULL != ah->s_init);
   GNUNET_assert (NULL != ah->s_add);
-  GNUNET_assert (NULL != ah->s_update);
+  GNUNET_assert (NULL != ah->s_address_update_inuse);
+  GNUNET_assert (NULL != ah->s_address_update_property);
+  GNUNET_assert (NULL != ah->s_address_update_session);
+  GNUNET_assert (NULL != ah->s_address_update_network);
   GNUNET_assert (NULL != ah->s_get);
   GNUNET_assert (NULL != ah->s_get_stop);
   GNUNET_assert (NULL != ah->s_pref);
+  GNUNET_assert (NULL != ah->s_feedback);
   GNUNET_assert (NULL != ah->s_del);
   GNUNET_assert (NULL != ah->s_done);
+  GNUNET_assert (NULL != ah->s_bulk_start);
+  GNUNET_assert (NULL != ah->s_bulk_stop);
 
-  GAS_normalization_start (&normalized_preference_changed_cb, ah);
+  GAS_normalization_start (&normalized_preference_changed_cb, ah,
+                                                                                                &normalized_property_changed_cb, ah);
   quota_count = load_quotas(cfg, quotas_in, quotas_out, GNUNET_ATS_NetworkTypeCount);
 
-  ah->solver = ah->s_init (cfg, stats, quotas, quotas_in, quotas_out, quota_count, &bandwidth_changed_cb, ah);
+  ah->solver = ah->s_init (cfg, stats, ah->addresses,
+                 quotas, quotas_in, quotas_out, quota_count,
+                 &bandwidth_changed_cb, ah,
+                 &get_preferences_cb, NULL,
+                 &get_property_cb, NULL);
   if (NULL == ah->solver)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to initialize solver!\n");
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to initialize solver!\n"));
     GNUNET_free (ah);
     return NULL;
   }
@@ -1625,7 +1895,7 @@ GAS_addresses_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
 
 
 /**
- * Free memory of address.
+ * Destroy all addresses iterator
  *
  * @param cls NULL
  * @param key peer identity (unused)
@@ -1633,12 +1903,18 @@ GAS_addresses_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
  * @return GNUNET_OK (continue to iterate)
  */
 static int
-free_address_it (void *cls, const struct GNUNET_HashCode * key, void *value)
+destroy_all_address_it (void *cls, const struct GNUNET_HashCode * key, void *value)
 {
   struct GAS_Addresses_Handle *handle = cls;
   struct ATS_Address *aa = value;
-  handle->s_del (handle->solver, handle->addresses, aa, GNUNET_NO);
-  destroy_address (handle, aa);
+
+  /* Remove */
+  GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (handle->addresses, key, value));
+  /* Notify */
+  handle->s_del (handle->solver, aa, GNUNET_NO);
+  /* Destroy */
+  free_address (aa);
+
   return GNUNET_OK;
 }
 
@@ -1654,12 +1930,12 @@ GAS_addresses_destroy_all (struct GAS_Addresses_Handle *handle)
   if (GNUNET_NO == handle->running)
     return;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Received `%s'\n",
-              "DESTROY ALL");
-
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Destroying all addresses\n");
+  handle->s_bulk_start (handle->solver);
   if (handle->addresses != NULL)
-    GNUNET_CONTAINER_multihashmap_iterate (handle->addresses, &free_address_it, handle);
+    GNUNET_CONTAINER_multihashmap_iterate (handle->addresses, &destroy_all_address_it, handle);
+  handle->s_bulk_start (handle->solver);
 }
 
 
@@ -1673,7 +1949,7 @@ GAS_addresses_done (struct GAS_Addresses_Handle *handle)
 {
   struct GAS_Addresses_Suggestion_Requests *cur;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
               "Shutting down addresses\n");
   GNUNET_assert (NULL != handle);
   GAS_addresses_destroy_all (handle);