stuff
[oweals/gnunet.git] / src / transport / gnunet-service-transport.c
index 895394c59d29c646ecb3d7351a3089ae874de751..cf02d14b26653156a92bf49dbdefacbef8671eff 100644 (file)
 #include "gnunet_service_lib.h"
 #include "gnunet_signatures.h"
 #include "gnunet_transport_plugin.h"
+#include "gnunet-service-transport_ats.h"
 #include "transport.h"
-#if HAVE_LIBGLPK
-#include <glpk.h>
-#endif
+
+
 
 #define DEBUG_BLACKLIST GNUNET_NO
 
@@ -48,9 +48,7 @@
 
 #define DEBUG_TRANSPORT_HELLO GNUNET_NO
 
-#define DEBUG_ATS GNUNET_NO
-
-#define VERBOSE_ATS GNUNET_NO
+#define DEBUG_INBOUND GNUNET_NO
 
 /**
  * Should we do some additional checks (to validate behavior
  */
 #define HELLO_REVALIDATION_START_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
 
-/**
- * Maximum frequency for re-evaluating latencies for all transport addresses.
- */
-#define LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
-
-/**
- * Maximum frequency for re-evaluating latencies for connected addresses.
- */
-#define CONNECTED_LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
-
-#define VERY_BIG_DOUBLE_VALUE 100000000000LL
-
-#define ATS_NEW 0
-#define ATS_Q_UPDATED 1
-#define ATS_C_UPDATED 2
-#define ATS_QC_UPDATED 3
-#define ATS_UNMODIFIED 4
-
 /**
  * List of addresses of other peers
  */
@@ -276,12 +256,6 @@ struct OwnAddressList
    */
   struct OwnAddressList *next;
 
-  /**
-   * How long until we actually auto-expire this address (unless it is
-   * re-confirmed by the transport)?
-   */
-  struct GNUNET_TIME_Absolute expires;
-
   /**
    * How long until the current signature expires? (ZERO if the
    * signature was never created).
@@ -306,7 +280,6 @@ struct OwnAddressList
  */
 struct TransportPlugin
 {
-
   /**
    * This is a linked list.
    */
@@ -360,7 +333,7 @@ struct TransportPlugin
   struct GNUNET_CONTAINER_MultiHashMap *blacklist;
 };
 
-struct NeighbourList;
+struct NeighbourMapEntry;
 
 /**
  * For each neighbour we keep a list of messages
@@ -461,21 +434,16 @@ struct ReadyList
   /**
    * To which neighbour does this ready list belong to?
    */
-  struct NeighbourList *neighbour;
+  struct NeighbourMapEntry *neighbour;
 };
 
 
 /**
- * Entry in linked list of all of our current neighbours.
+ * Entry in neighbours. 
  */
-struct NeighbourList
+struct NeighbourMapEntry
 {
 
-  /**
-   * This is a linked list.
-   */
-  struct NeighbourList *next;
-
   /**
    * Which of our transports is connected to this peer
    * and what is their status?
@@ -494,6 +462,18 @@ struct NeighbourList
    */
   struct MessageQueue *messages_tail;
 
+  /**
+   * Head of list of messages of messages we expected the continuation
+   * to be called to destroy the message
+   */
+  struct MessageQueue *cont_head;
+
+  /**
+   * Tail of list of messages of messages we expected the continuation
+   * to be called to destroy the message
+   */
+  struct MessageQueue *cont_tail;
+
   /**
    * Buffer for at most one payload message used when we receive
    * payload data before our PING-PONG has succeeded.  We then
@@ -582,15 +562,14 @@ struct NeighbourList
   int public_key_valid;
 
   /**
-   * Performance data for the peer.
+   * Are we already in the process of disconnecting this neighbour?
    */
-  struct GNUNET_TRANSPORT_ATS_Information *ats;
+  int in_disconnect;
 
   /**
-   * Identity of the neighbour.
+   * Performance data for the peer.
    */
-  struct GNUNET_PeerIdentity peer;
-
+  struct GNUNET_TRANSPORT_ATS_Information *ats;
 };
 
 /**
@@ -756,7 +735,7 @@ struct CheckHelloValidatedContext;
 /**
  * Entry in map of all HELLOs awaiting validation.
  */
-struct ValidationEntry
+struct ValidationEntry 
 {
 
   /**
@@ -849,296 +828,11 @@ struct CheckHelloValidatedContext
   unsigned int ve_count;
 };
 
-struct ATS_quality_metric
-{
-       int index;
-       int atis_index;
-       char * name;
-};
-
-struct ATS_mechanism
-{
-       struct ATS_mechanism * prev;
-       struct ATS_mechanism * next;
-       struct ForeignAddressList * addr;
-       struct TransportPlugin * plugin;
-       struct ATS_peer * peer;
-       int col_index;
-       int     id;
-       struct ATS_ressource_cost * rc;
-};
-
-struct ATS_peer
-{
-       int id;
-       struct GNUNET_PeerIdentity peer;
-       struct NeighbourList * n;
-       struct ATS_mechanism * m_head;
-       struct ATS_mechanism * m_tail;
-
-       /* preference value f */
-       double f;
-       int     t;
-};
-
-struct ATS_stat
-{
-       /**
-        * result of last GLPK run
-        * 5 == OPTIMAL
-        */
-       int solution;
-
-       /**
-        * Ressource costs or quality metrics changed
-        * update problem before solving
-        */
-       int modified_resources;
-
-       /**
-        * Ressource costs or quality metrics changed, update matrix
-        * update problem before solving
-        */
-       int modified_quality;
-
-       /**
-        * Peers have connected or disconnected
-        * problem has to be recreated
-        */
-       int recreate_problem;
-
-       /**
-        * Was the available basis invalid and we needed to rerun simplex?
-        */
-       int simplex_rerun_required;
-
-       /**
-        * is problem currently valid and can it be solved
-        */
-       int valid;
-
-       /**
-        * Number of transport mechanisms in the problem
-        */
-       int c_mechs;
-
-       /**
-        * Number of transport mechanisms in the problem
-        */
-       int c_peers;
-
-       /**
-        * row index where quality related rows start
-        */
-       int begin_qm;
-
-       /**
-        * row index where quality related rows end
-        */
-       int end_qm;
-
-       /**
-        * row index where ressource cost related rows start
-        */
-       int begin_cr;
-
-       /**
-        * row index where ressource cost related rows end
-        */
-       int end_cr;
-
-       /**
-        * column index for objective function value d
-        */
-       int col_d;
-       
-       /**
-        * column index for objective function value u
-        */
-       int col_u;
-       
-       /**
-        * column index for objective function value r
-        */
-       int col_r;
-       
-       /**
-        * column index for objective function value quality metrics
-        */
-       int col_qm;
-       
-       /**
-        * column index for objective function value cost ressources
-        */
-       int col_cr;
-};
-
-struct ATS_ressource_entry
-{
-       /* index in ressources array */
-       int index;
-       /* depending ATSi parameter to calculcate limits */
-       int atis_index;
-       /* lower bound */
-       double c;
-};
-
-
-struct ATS_ressource
-{
-       /* index in ressources array */
-       int index;
-       /* depending ATSi parameter to calculcate limits */
-       int atis_index;
-       /* cfg option to load limits */
-       char * cfg_param;
-       /* lower bound */
-       double c_min;
-       /* upper bound */
-       double c_max;
-
-       /* cofficients for the specific plugins */
-       double c_unix;
-       double c_tcp;
-       double c_udp;
-       double c_http;
-       double c_https;
-       double c_wlan;
-       double c_default;
-};
-
-static struct ATS_ressource ressources[] =
-{
-               /* FIXME: the coefficients for the specific plugins */
-               {1, 7, "LAN_BW_LIMIT", 0, VERY_BIG_DOUBLE_VALUE, 0, 1, 1, 2, 2, 1, 3},
-               {2, 7, "WAN_BW_LIMIT", 0, VERY_BIG_DOUBLE_VALUE, 0, 1, 1, 2, 2, 2, 3},
-               {3, 4, "WLAN_ENERGY_LIMIT", 0, VERY_BIG_DOUBLE_VALUE, 0, 0, 0, 0, 0, 2, 1}
-/*
-               {4, 4, "COST_ENERGY_CONSUMPTION", VERY_BIG_DOUBLE_VALUE},
-               {5, 5, "COST_CONNECT", VERY_BIG_DOUBLE_VALUE},
-               {6, 6, "COST_BANDWITH_AVAILABLE", VERY_BIG_DOUBLE_VALUE},
-               {7, 7, "COST_NETWORK_OVERHEAD", VERY_BIG_DOUBLE_VALUE},*/
-};
-
-static int available_ressources = 3;
-
-
-
-struct ATS_info
-{
-
-       /**
-        * Time of last execution
-        */
-       struct GNUNET_TIME_Absolute last;
-       /**
-        * Minimum intervall between two executions
-        */
-       struct GNUNET_TIME_Relative min_delta;
-       /**
-        * Regular intervall when execution is triggered
-        */
-       struct GNUNET_TIME_Relative exec_interval;
-       /**
-        * Maximum execution time per calculation
-        */
-       struct GNUNET_TIME_Relative max_exec_duration;
-
-#if HAVE_LIBGLPK
-       /**
-        * GLPK (MLP) problem object
-        */
-       glp_prob *prob;
-#endif
-
-       /**
-        * task to recalculate the bandwidth assignment
-        */
-       GNUNET_SCHEDULER_TaskIdentifier ats_task;
-
-       /**
-        * Current state of the GLPK problem
-        */
-       struct ATS_stat stat;
-
-       /**
-        * mechanisms used in current problem
-        * needed for problem modification
-        */
-       struct ATS_mechanism * mechanisms;
-
-       /**
-        * peers used in current problem
-        * needed for problem modification
-        */
-       struct ATS_peer * peers;
-
-       /**
-        * number of successful executions
-        */
-       int successful_executions;
-
-       /**
-        * number with an invalid result
-        */
-       int invalid_executions;
-
-       /**
-        * Maximum number of LP iterations per calculation
-        */
-       int max_iterations;
-
-       /**
-        * Dump problem to a file?
-        */
-       int save_mlp;
-
-       /**
-        * Dump solution to a file
-        */
-       int save_solution;
-
-       /**
-        * Dump solution when minimum peers:
-        */
-       int dump_min_peers;
-
-       /**
-        * Dump solution when minimum addresses:
-        */
-       int dump_min_addr;
-
-       /**
-        * Dump solution overwrite file:
-        */
-       int dump_overwrite;
-
-       /**
-        * Diversity weight
-        */
-       double D;
-
-       /**
-        * Utility weight
-        */
-       double U;
-
-       /**
-        * Relativity weight
-        */
-       double R;
-
-       /**
-        * Minimum bandwidth per peer
-        */
-       int v_b_min;
-
-       /**
-        * Minimum number of connections per peer
-        */
-       int v_n_min;
-};
 
+/**
+ * All zero hash for comparison.
+ */
+static GNUNET_HashCode null_hash;
 
 /**
  * Our HELLO message.
@@ -1183,7 +877,7 @@ static struct GNUNET_PEERINFO_Handle *peerinfo;
 /**
  * All known neighbours and their HELLOs.
  */
-static struct NeighbourList *neighbours;
+static struct GNUNET_CONTAINER_MultiHashMap *neighbours;
 
 /**
  * Number of neighbours we'd like to have.
@@ -1211,6 +905,16 @@ static struct GNUNET_CONTAINER_MultiHashMap *validation_map;
  */
 static struct GNUNET_STATISTICS_Handle *stats;
 
+/**
+ * Identifier of 'refresh_hello' task.
+ */
+static GNUNET_SCHEDULER_TaskIdentifier hello_task;
+
+/**
+ * Identifier of ats scheduler task.
+ */
+static GNUNET_SCHEDULER_TaskIdentifier ats_task;
+
 /**
  * Is transport service shutting down ?
  */
@@ -1219,23 +923,20 @@ static int shutdown_in_progress;
 /**
  * Handle for ats information
  */
-static struct ATS_info *ats;
-
-struct ATS_quality_entry
-{
-       int index;
-       int atsi_index;
-       uint32_t values[3];
-       int current;
-};
-
-static struct ATS_quality_metric qm[] =
-{
-               {1, 1028, "QUALITY_NET_DISTANCE"},
-               {2, 1034, "QUALITY_NET_DELAY"},
-};
-static int available_quality_metrics = 2;
+static struct ATS_Handle *ats;
 
+/**
+ * Time of last ats execution
+ */
+struct GNUNET_TIME_Absolute last_ats_execution;
+/**
+ * Minimum interval between two ATS executions
+ */
+struct GNUNET_TIME_Relative ats_minimum_interval;
+/**
+ * Regular interval when ATS execution is triggered
+ */
+struct GNUNET_TIME_Relative ats_regular_interval;
 
 /**
  * The peer specified by the given neighbour has timed-out or a plugin
@@ -1250,7 +951,7 @@ static int available_quality_metrics = 2;
  *        disconnected or must we ask all plugins to
  *        disconnect?
  */
-static void disconnect_neighbour (struct NeighbourList *n, int check);
+static void disconnect_neighbour (struct NeighbourMapEntry *n, int check);
 
 /**
  * Check the ready list for the given neighbour and if a plugin is
@@ -1258,74 +959,54 @@ static void disconnect_neighbour (struct NeighbourList *n, int check);
  *
  * @param nexi target peer for which to transmit
  */
-static void try_transmission_to_peer (struct NeighbourList *n);
+static void try_transmission_to_peer (struct NeighbourMapEntry *n);
 
-static void ats_shutdown ( );
-
-static void ats_notify_peer_connect (
-               const struct GNUNET_PeerIdentity *peer,
-               const struct GNUNET_TRANSPORT_ATS_Information *ats_data, int ats_count);
-
-static void ats_notify_peer_disconnect (
-               const struct GNUNET_PeerIdentity *peer);
-
-#if 0
-static void ats_notify_ats_data (
-               const struct GNUNET_PeerIdentity *peer,
-               const struct GNUNET_TRANSPORT_ATS_Information *ats_data);
-#endif
-
-struct ForeignAddressList * ats_get_preferred_address (
-               struct NeighbourList *n);
-
-static void
-ats_calculate_bandwidth_distribution ();
+struct ForeignAddressList * get_preferred_ats_address (
+               struct NeighbourMapEntry *n);
 
 /**
  * Find an entry in the neighbour list for a particular peer.
  *
  * @return NULL if not found.
  */
-static struct NeighbourList *
+static struct NeighbourMapEntry *
 find_neighbour (const struct GNUNET_PeerIdentity *key)
 {
-  struct NeighbourList *head = neighbours;
-
-  while ((head != NULL) &&
-        (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
-    head = head->next;
-  return head;
+  return GNUNET_CONTAINER_multihashmap_get (neighbours, &key->hashPubKey);
 }
 
 static int update_addr_value (struct ForeignAddressList *fal, uint32_t value , int ats_index)
 {
-       int c;
-       int set = GNUNET_NO;
-       for (c=0; c<available_quality_metrics; c++)
-       {
-         if (ats_index == qm[c].atis_index)
-         {
-                 fal->quality[c].values[0] = fal->quality[c].values[1];
-                 fal->quality[c].values[1] = fal->quality[c].values[2];
-                 fal->quality[c].values[2] = value;
-                 set = GNUNET_YES;
-                 ats->stat.modified_quality = GNUNET_YES;
-         }
-       }
-       if (set == GNUNET_NO)
-       {
-         for (c=0; c<available_ressources; c++)
-         {
-                 if (ats_index == ressources[c].atis_index)
-                 {
-                         fal->ressources[c].c = value;
-                         set = GNUNET_YES;
-                         ats->stat.modified_resources = GNUNET_YES;
-                 }
-         }
-       }
-
-       return set;
+  int c;
+  int set = GNUNET_NO;
+  for (c=0; c<available_quality_metrics; c++)
+  {
+    if (ats_index == qm[c].atis_index)
+    {
+      fal->quality[c].values[0] = fal->quality[c].values[1];
+      fal->quality[c].values[1] = fal->quality[c].values[2];
+      fal->quality[c].values[2] = value;
+      set = GNUNET_YES;
+#if HAVE_LIBGLPK
+      ats_modify_problem_state (ats, ATS_QUALITY_UPDATED);
+#endif
+    }
+  }
+  if (set == GNUNET_NO)
+  {
+    for (c=0; c<available_ressources; c++)
+    {
+      if (ats_index == ressources[c].atis_index)
+      {
+        fal->ressources[c].c = value;
+        set = GNUNET_YES;
+#if HAVE_LIBGLPK
+        ats_modify_problem_state (ats, ATS_COST_UPDATED);
+#endif
+      }
+    }
+  }
+  return set;
 }
 
 static int
@@ -1675,62 +1356,79 @@ a2s (const char *plugin,
   p = find_transport (plugin);
   if ((p == NULL) || (addr_len == 0) || (addr == NULL))
     return NULL;
-  return p->api->address_to_string (p->api->cls,
+  return p->api->address_to_string (NULL,
                                    addr,
                                    addr_len);
 }
 
 
+
+
 /**
- * Mark the given FAL entry as 'connected' (and hence preferred for
- * sending); also mark all others for the same peer as 'not connected'
- * (since only one can be preferred).
+ * Iterator to free entries in the validation_map.
  *
- * @param fal address to set to 'connected'
+ * @param cls closure (unused)
+ * @param key current key code
+ * @param value value in the hash map (validation to abort)
+ * @return GNUNET_YES (always)
  */
-static void
-mark_address_connected (struct ForeignAddressList *fal)
+static int
+abort_validation (void *cls,
+                 const GNUNET_HashCode * key,
+                 void *value)
 {
-  struct ForeignAddressList *pos;
-  int cnt;
+  struct ValidationEntry *va = value;
 
-  GNUNET_assert (GNUNET_YES == fal->validated);
-  if (fal->connected == GNUNET_YES)
-    return; /* nothing to do */
-  cnt = GNUNET_YES;
-  pos = fal->ready_list->addresses;
-  while (pos != NULL)
+  if (GNUNET_SCHEDULER_NO_TASK != va->timeout_task)
+    GNUNET_SCHEDULER_cancel (va->timeout_task);
+  GNUNET_free (va->transport_name);
+  if (va->chvc != NULL)
     {
-      if (GNUNET_YES == pos->connected)
+      va->chvc->ve_count--;
+      if (va->chvc->ve_count == 0)
        {
-#if DEBUG_TRANSPORT
-         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                     "Marking address `%s' as no longer connected (due to connect on other address)\n",
-                     a2s (pos->ready_list->plugin->short_name,
-                          pos->addr,
-                          pos->addrlen));
-#endif
-         GNUNET_break (cnt == GNUNET_YES);
-         cnt = GNUNET_NO;
-         pos->connected = GNUNET_NO;
-         GNUNET_STATISTICS_update (stats,
-                                   gettext_noop ("# connected addresses"),
-                                   -1,
-                                   GNUNET_NO);
+         GNUNET_CONTAINER_DLL_remove (chvc_head,
+                                      chvc_tail,
+                                      va->chvc);
+         GNUNET_free (va->chvc);
        }
-      pos = pos->next;
-    }
-  fal->connected = GNUNET_YES;
-  if (GNUNET_YES == cnt)
-    {
-      GNUNET_STATISTICS_update (stats,
-                               gettext_noop ("# connected addresses"),
-                               1,
-                               GNUNET_NO);
+      va->chvc = NULL;
     }
+  GNUNET_free (va);
+  return GNUNET_YES;
+}
+
+
+/**
+ * HELLO validation cleanup task (validation failed).
+ *
+ * @param cls the 'struct ValidationEntry' that failed
+ * @param tc scheduler context (unused)
+ */
+static void
+timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct ValidationEntry *va = cls;
+  struct GNUNET_PeerIdentity pid;
+
+  va->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+  GNUNET_STATISTICS_update (stats,
+                           gettext_noop ("# address validation timeouts"),
+                           1,
+                           GNUNET_NO);
+  GNUNET_CRYPTO_hash (&va->publicKey,
+                     sizeof (struct
+                             GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
+                     &pid.hashPubKey);
+  GNUNET_break (GNUNET_OK ==
+                GNUNET_CONTAINER_multihashmap_remove (validation_map,
+                                                     &pid.hashPubKey,
+                                                     va));
+  abort_validation (NULL, NULL, va);
 }
 
 
+
 /**
  * Send the specified message to the specified client.  Since multiple
  * messages may be pending for the same client at a time, this code
@@ -1748,6 +1446,15 @@ transmit_to_client (struct TransportClient *client,
   struct ClientMessageQueueEntry *q;
   uint16_t msize;
 
+  /* Client==NULL when GNUNET_SERVER_Client disconnected and was
+   * freed in client_disconnect_notification
+   */
+  if (client->client == NULL)
+    {
+      GNUNET_break (0);
+      return;
+    }
+
   if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
     {
       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
@@ -1767,10 +1474,9 @@ transmit_to_client (struct TransportClient *client,
   GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
   q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
   memcpy (&q[1], msg, msize);
-  GNUNET_CONTAINER_DLL_insert_after (client->message_queue_head,
-                                    client->message_queue_tail,
-                                    client->message_queue_tail,
-                                    q);
+  GNUNET_CONTAINER_DLL_insert_tail (client->message_queue_head,
+                                   client->message_queue_tail,
+                                   q);
   client->message_count++;
   if (client->th == NULL)
     {
@@ -1795,7 +1501,7 @@ transmit_to_client (struct TransportClient *client,
  */
 static void
 transmit_send_ok (struct TransportClient *client,
-                 struct NeighbourList *n,
+                 struct NeighbourMapEntry *n,
                  const struct GNUNET_PeerIdentity *target,
                  int result)
 {
@@ -1813,6 +1519,33 @@ transmit_send_ok (struct TransportClient *client,
 }
 
 
+/**
+ * Mark the given FAL entry as 'connected' (and hence preferred for
+ * sending); also mark all others for the same peer as 'not connected'
+ * (since only one can be preferred).
+ *
+ * @param fal address to set to 'connected'
+ */
+static void
+mark_address_connected (struct ForeignAddressList *fal);
+
+
+
+/**
+ * We should re-try transmitting to the given peer,
+ * hopefully we've learned something in the meantime.
+ */
+static void
+retry_transmission_task (void *cls,
+                        const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct NeighbourMapEntry *n = cls;
+
+  n->retry_task = GNUNET_SCHEDULER_NO_TASK;
+  try_transmission_to_peer (n);
+}
+
+
 /**
  * Function called by the GNUNET_TRANSPORT_TransmitFunction
  * upon "completion" of a send request.  This tells the API
@@ -1833,7 +1566,7 @@ transmit_send_continuation (void *cls,
                             int result)
 {
   struct MessageQueue *mq = cls;
-  struct NeighbourList *n;
+  struct NeighbourMapEntry *n;
 
   GNUNET_STATISTICS_update (stats,
                            gettext_noop ("# bytes pending with plugins"),
@@ -1865,7 +1598,7 @@ transmit_send_continuation (void *cls,
        }
       else
        {
-         if (mq->specific_address->connected != GNUNET_NO)
+         if (mq->specific_address->connected == GNUNET_YES)
            {
 #if DEBUG_TRANSPORT
              GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -1884,160 +1617,36 @@ transmit_send_continuation (void *cls,
       if (! mq->internal_msg)
        mq->specific_address->in_transmit = GNUNET_NO;
     }
-  n = find_neighbour(&mq->neighbour_id);
+  n = find_neighbour (&mq->neighbour_id);
   if (mq->client != NULL)
     transmit_send_ok (mq->client, n, target, result);
+  GNUNET_assert (n != NULL);
+  GNUNET_CONTAINER_DLL_remove (n->cont_head,
+                              n->cont_tail,
+                              mq);
   GNUNET_free (mq);
-  if (n != NULL)
+  if (result == GNUNET_OK) 
     try_transmission_to_peer (n);
+  else if (GNUNET_SCHEDULER_NO_TASK == n->retry_task)
+    n->retry_task = GNUNET_SCHEDULER_add_now (&retry_transmission_task,
+                                             n);
 }
 
 
 /**
- * Find an address in any of the available transports for
- * the given neighbour that would be good for message
- * transmission.  This is essentially the transport selection
- * routine.
+ * Check the ready list for the given neighbour and if a plugin is
+ * ready for transmission (and if we have a message), do so!
  *
- * @param neighbour for whom to select an address
- * @return selected address, NULL if we have none
+ * @param neighbour target peer for which to transmit
  */
-struct ForeignAddressList *
-find_ready_address(struct NeighbourList *neighbour)
+static void
+try_transmission_to_peer (struct NeighbourMapEntry *n)
 {
-  struct ReadyList *head = neighbour->plugins;
-  struct ForeignAddressList *addresses;
-  struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
-  struct ForeignAddressList *best_address;
-
-  /* Hack to prefer unix domain sockets */
-  struct ForeignAddressList *unix_address = NULL;
-
-  best_address = NULL;
-  while (head != NULL)
-    {
-      addresses = head->addresses;
-      while (addresses != NULL)
-        {
-          if ( (addresses->timeout.abs_value < now.abs_value) &&
-              (addresses->connected == GNUNET_YES) )
-            {
-#if DEBUG_TRANSPORT
-              GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                          "Marking long-time inactive connection to `%4s' as down.\n",
-                          GNUNET_i2s (&neighbour->id));
-#endif
-             GNUNET_STATISTICS_update (stats,
-                                       gettext_noop ("# connected addresses"),
-                                       -1,
-                                       GNUNET_NO);
-              addresses->connected = GNUNET_NO;
-            }
-          addresses = addresses->next;
-        }
-
-      addresses = head->addresses;
-      while (addresses != NULL)
-        {
-#if DEBUG_TRANSPORT > 1
-         if (addresses->addr != NULL)
-           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                       "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
-                       a2s (head->plugin->short_name,
-                            addresses->addr,
-                            addresses->addrlen),
-                       GNUNET_i2s (&neighbour->id),
-                       addresses->connected,
-                       addresses->in_transmit,
-                       addresses->validated,
-                       addresses->connect_attempts,
-                       (unsigned long long) addresses->timeout.abs_value,
-                       (unsigned int) addresses->distance);
-#endif
-                if (0==strcmp(head->plugin->short_name,"unix"))
-                {
-                        if ((unix_address == NULL) || ((unix_address != NULL) &&
-                                (addresses->latency.rel_value < unix_address->latency.rel_value)))
-                               unix_address = addresses;
-                }
-          if ( ( (best_address == NULL) ||
-                (addresses->connected == GNUNET_YES) ||
-                (best_address->connected == GNUNET_NO) ) &&
-              (addresses->in_transmit == GNUNET_NO) &&
-              ( (best_address == NULL) ||
-                (addresses->latency.rel_value < best_address->latency.rel_value)) )
-           best_address = addresses;
-         /* FIXME: also give lower-latency addresses that are not
-            connected a chance some times... */
-          addresses = addresses->next;
-        }
-      if (unix_address != NULL)
-         break;
-      head = head->next;
-    }
-  if (unix_address != NULL)
-    {
-      best_address = unix_address;
-#if DEBUG_TRANSPORT
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
-                 "Found UNIX address, forced this address\n");
-#endif
-    }
-  if (best_address != NULL)
-    {
-#if DEBUG_TRANSPORT
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "Best address found (`%s') has latency of %llu ms.\n",
-                 (best_address->addrlen > 0)
-                 ? a2s (best_address->ready_list->plugin->short_name,
-                        best_address->addr,
-                      best_address->addrlen)
-                 : "<inbound>",
-                  best_address->latency.rel_value);
-#endif
-    }
-  else
-    {
-      GNUNET_STATISTICS_update (stats,
-                               gettext_noop ("# transmission attempts failed (no address)"),
-                               1,
-                               GNUNET_NO);
-    }
-
-  return best_address;
-
-}
-
-
-/**
- * We should re-try transmitting to the given peer,
- * hopefully we've learned something in the meantime.
- */
-static void
-retry_transmission_task (void *cls,
-                        const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
-  struct NeighbourList *n = cls;
-
-  n->retry_task = GNUNET_SCHEDULER_NO_TASK;
-  try_transmission_to_peer (n);
-}
-
-
-/**
- * Check the ready list for the given neighbour and if a plugin is
- * ready for transmission (and if we have a message), do so!
- *
- * @param neighbour target peer for which to transmit
- */
-static void
-try_transmission_to_peer (struct NeighbourList *n)
-{
-  struct ReadyList *rl;
-  struct MessageQueue *mq;
-  struct GNUNET_TIME_Relative timeout;
-  ssize_t ret;
-  int force_address;
+  struct ReadyList *rl;
+  struct MessageQueue *mq;
+  struct GNUNET_TIME_Relative timeout;
+  ssize_t ret;
+  int force_address;
 
   if (n->messages_head == NULL)
     {
@@ -2053,8 +1662,8 @@ try_transmission_to_peer (struct NeighbourList *n)
   force_address = GNUNET_YES;
   if (mq->specific_address == NULL)
     {
-         /* TODO: ADD ATS */
-      mq->specific_address = ats_get_preferred_address(n);
+      /* TODO: ADD ATS */
+      mq->specific_address = get_preferred_ats_address(n);
       GNUNET_STATISTICS_update (stats,
                                gettext_noop ("# transport selected peer address freely"),
                                1,
@@ -2099,8 +1708,8 @@ try_transmission_to_peer (struct NeighbourList *n)
       if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
        GNUNET_SCHEDULER_cancel (n->retry_task);
       n->retry_task = GNUNET_SCHEDULER_add_delayed (timeout,
-                                                           &retry_transmission_task,
-                                                           n);
+                                                   &retry_transmission_task,
+                                                   n);
 #if DEBUG_TRANSPORT
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                  "No validated destination address available to transmit message of size %u to peer `%4s', will wait %llums to find an address.\n",
@@ -2141,6 +1750,11 @@ try_transmission_to_peer (struct NeighbourList *n)
                            gettext_noop ("# bytes pending with plugins"),
                            mq->message_buf_size,
                            GNUNET_NO);
+
+  GNUNET_CONTAINER_DLL_insert (n->cont_head,
+                               n->cont_tail,
+                               mq);
+
   ret = rl->plugin->api->send (rl->plugin->api->cls,
                               &mq->neighbour_id,
                               mq->message_buf,
@@ -2183,7 +1797,7 @@ transmit_to_peer (struct TransportClient *client,
                  struct GNUNET_TIME_Relative timeout,
                   const char *message_buf,
                   size_t message_buf_size,
-                  int is_internal, struct NeighbourList *neighbour)
+                  int is_internal, struct NeighbourMapEntry *neighbour)
 {
   struct MessageQueue *mq;
 
@@ -2234,193 +1848,432 @@ transmit_to_peer (struct TransportClient *client,
 
 
 /**
- * FIXME: document.
- */
-struct GeneratorContext
-{
-  struct TransportPlugin *plug_pos;
-  struct OwnAddressList *addr_pos;
-  struct GNUNET_TIME_Absolute expiration;
-};
-
-
-/**
- * FIXME: document.
+ * Send a plain PING (without address or our HELLO) to the given
+ * foreign address to try to establish a connection (and validate
+ * that the other peer is really who he claimed he is).
+ *
+ * @param n neighbour to PING
  */
-static size_t
-address_generator (void *cls, size_t max, void *buf)
+static void
+transmit_plain_ping (struct NeighbourMapEntry *n)
 {
-  struct GeneratorContext *gc = cls;
-  size_t ret;
+  struct ValidationEntry *ve;
+  struct TransportPingMessage ping;
+  struct ReadyList *rl;
+  struct TransportPlugin *plugin;
+  struct ForeignAddressList *fal;
 
-  while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
+  if (! n->public_key_valid)
     {
-      gc->plug_pos = gc->plug_pos->next;
-      gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
+      /* This should not happen since the other peer
+        should send us a HELLO prior to sending his
+        PING */
+      GNUNET_break_op (0);
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                 "Could not transmit plain PING to `%s': public key not known\n",
+                 GNUNET_i2s (&n->id));
+      return;
     }
-  if (NULL == gc->plug_pos)
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Looking for addresses to transmit plain PING to `%s'\n",
+             GNUNET_i2s (&n->id));
+  for (rl = n->plugins; rl != NULL; rl = rl->next)
     {
-
-      return 0;
+      plugin = rl->plugin;
+      for (fal = rl->addresses; fal != NULL; fal = fal->next)
+       {
+         if (! fal->connected)
+           continue;      
+         ve = GNUNET_malloc (sizeof (struct ValidationEntry));
+         ve->transport_name = GNUNET_strdup (plugin->short_name);
+         ve->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
+                                                   UINT_MAX);
+         ve->send_time = GNUNET_TIME_absolute_get();
+         ve->session = fal->session;
+         memcpy(&ve->publicKey,
+                &n->publicKey,
+                sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
+         ve->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
+                                                          &timeout_hello_validation,
+                                                          ve);
+         GNUNET_CONTAINER_multihashmap_put (validation_map,
+                                            &n->id.hashPubKey,
+                                            ve,
+                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
+         ping.header.size = htons(sizeof(struct TransportPingMessage));
+         ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
+         ping.challenge = htonl(ve->challenge);
+         memcpy(&ping.target, &n->id, sizeof(struct GNUNET_PeerIdentity));
+         GNUNET_STATISTICS_update (stats,
+                                   gettext_noop ("# PING without HELLO messages sent"),
+                                   1,
+                                   GNUNET_NO);
+         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                     "Transmitting plain PING to `%s'\n",
+                     GNUNET_i2s (&n->id));
+         transmit_to_peer (NULL, 
+                           fal,
+                           GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+                           HELLO_VERIFICATION_TIMEOUT,
+                           (const char*) &ping, sizeof (ping),
+                           GNUNET_YES, n);
+       }
     }
-  ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
-                                  gc->expiration,
-                                  &gc->addr_pos[1],
-                                  gc->addr_pos->addrlen, buf, max);
-  gc->addr_pos = gc->addr_pos->next;
-  return ret;
 }
 
 
 /**
- * Construct our HELLO message from all of the addresses of
- * all of the transports.
+ * Mark the given FAL entry as 'connected' (and hence preferred for
+ * sending); also mark all others for the same peer as 'not connected'
+ * (since only one can be preferred).
+ *
+ * @param fal address to set to 'connected'
  */
 static void
-refresh_hello ()
+mark_address_connected(struct ForeignAddressList *fal)
 {
-  struct GNUNET_HELLO_Message *hello;
-  struct TransportClient *cpos;
-  struct NeighbourList *npos;
-  struct GeneratorContext gc;
+  struct ForeignAddressList *pos;
+  struct ForeignAddressList *inbound;
+  struct ForeignAddressList *outbound;
 
-  gc.plug_pos = plugins;
-  gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
-  gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
-  hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
-#if DEBUG_TRANSPORT
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
-              "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
+  GNUNET_assert (GNUNET_YES == fal->validated);
+  if (fal->connected == GNUNET_YES)
+    return; /* nothing to do */
+  inbound = NULL;
+  outbound = NULL;
+
+  pos = fal->ready_list->addresses;
+  while (pos != NULL)
+    {
+      /* Already have inbound address, and this is also an inbound address, don't switch!! */
+      if ( (GNUNET_YES == pos->connected) && 
+          (0 == pos->addrlen) && 
+          (0 == fal->addrlen) )
+        return;
+      if ( (0 == pos->addrlen) && 
+          (GNUNET_YES == pos->connected) )
+        inbound = pos;
+      pos = pos->next;
+    }
+
+  pos = fal->ready_list->addresses;
+  while (pos != NULL)
+    {
+      /* Already have outbound address, and this is also an outbound address, don't switch!! */
+      if ( (GNUNET_YES == pos->connected) && 
+          (0 < pos->addrlen) && 
+          (0 < fal->addrlen) )
+        return;
+      if ( (0 < pos->addrlen) && (GNUNET_YES == pos->connected) )
+        outbound = pos;
+      pos = pos->next;
+    }
+
+#if DEBUG_INBOUND
+  if (inbound != NULL)
+    fprintf(stderr, "Peer: %s, have inbound connection.\n", GNUNET_i2s(&my_identity));
+  if (outbound != NULL)
+    fprintf(stderr, "Peer: %s, have outbound connection.\n", GNUNET_i2s(&my_identity));
 #endif
-  GNUNET_STATISTICS_update (stats,
-                           gettext_noop ("# refreshed my HELLO"),
-                           1,
-                           GNUNET_NO);
-  cpos = clients;
-  while (cpos != NULL)
+
+  /* Have an inbound connection to this peer which is valid; our id is lower, ignore outbound connection! */
+  if ((inbound != NULL) && (0 != fal->addrlen) && (1
+      == GNUNET_CRYPTO_hash_xorcmp (&inbound->ready_list->neighbour->id.hashPubKey,
+                                    &my_identity.hashPubKey, &null_hash)))
     {
-      transmit_to_client (cpos,
-                          (const struct GNUNET_MessageHeader *) hello,
-                          GNUNET_NO);
-      cpos = cpos->next;
+#if DEBUG_INBOUND
+      fprintf(stderr, "Peer: %s, had inbound connection, ignoring outbound!\n", GNUNET_i2s(&my_identity));
+#endif
+      return;
+    }
+  else if ((outbound != NULL) && (0 == fal->addrlen) && ((-1
+      == GNUNET_CRYPTO_hash_xorcmp (&outbound->ready_list->neighbour->id.hashPubKey,
+                                    &my_identity.hashPubKey, &null_hash))))
+    {
+#if DEBUG_INBOUND
+      fprintf(stderr, "Peer: %s, have outbound connection, ignoring inbound!\n", GNUNET_i2s(&my_identity));
+#endif
+      return;
     }
 
-  GNUNET_free_non_null (our_hello);
-  our_hello = hello;
-  GNUNET_PEERINFO_add_peer (peerinfo, our_hello);
-  npos = neighbours;
-  while (npos != NULL)
+  pos = fal->ready_list->addresses;
+  while (pos != NULL)
     {
+      if ((GNUNET_YES == pos->connected) && (0 < pos->addrlen))
+        {
 #if DEBUG_TRANSPORT
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
-                  "Transmitting updated `%s' to neighbour `%4s'\n",
-                  "HELLO", GNUNET_i2s (&npos->id));
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                      "Marking address `%s' as no longer connected (due to connect on other address)\n",
+                      a2s (pos->ready_list->plugin->short_name, pos->addr,
+                           pos->addrlen));
 #endif
-      GNUNET_STATISTICS_update (stats,
-                               gettext_noop ("# transmitted my HELLO to other peers"),
-                               1,
-                               GNUNET_NO);
-      transmit_to_peer (NULL, NULL, 0,
-                       HELLO_ADDRESS_EXPIRATION,
-                        (const char *) our_hello,
-                       GNUNET_HELLO_size(our_hello),
-                        GNUNET_NO, npos);
-      npos = npos->next;
+#if DEBUG_INBOUND
+          fprintf(stderr, 
+                 "Peer: %s, setting %s connection to disconnected.\n", 
+                 GNUNET_i2s(&my_identity),
+                 (0 == pos->addrlen) ? "INBOUND" : "OUTBOUND");
+#endif
+          pos->connected = GNUNET_NO;
+          GNUNET_STATISTICS_update (stats,
+                                    gettext_noop ("# connected addresses"), -1,
+                                    GNUNET_NO);
+        }
+      pos = pos->next;
     }
+  GNUNET_assert (GNUNET_NO == fal->connected);
+  fal->connected = GNUNET_YES;
+  GNUNET_STATISTICS_update (stats, gettext_noop ("# connected addresses"),
+                           1, GNUNET_NO);
 }
 
 
 /**
- * Task used to clean up expired addresses for a plugin.
+ * Find an address in any of the available transports for
+ * the given neighbour that would be good for message
+ * transmission.  This is essentially the transport selection
+ * routine.
  *
- * @param cls closure
- * @param tc context
+ * @param neighbour for whom to select an address
+ * @return selected address, NULL if we have none
  */
-static void
-expire_address_task (void *cls,
-                     const struct GNUNET_SCHEDULER_TaskContext *tc);
+struct ForeignAddressList *
+find_ready_address(struct NeighbourMapEntry *neighbour)
+{
+  struct ReadyList *head = neighbour->plugins;
+  struct ForeignAddressList *addresses;
+  struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
+  struct ForeignAddressList *best_address;
 
+  /* Hack to prefer unix domain sockets */
+  struct ForeignAddressList *unix_address = NULL;
 
-/**
- * Update the list of addresses for this plugin,
- * expiring those that are past their expiration date.
- *
- * @param plugin addresses of which plugin should be recomputed?
- * @param fresh set to GNUNET_YES if a new address was added
- *        and we need to regenerate the HELLO even if nobody
- *        expired
- */
-static void
-update_addresses (struct TransportPlugin *plugin,
-                 int fresh)
-{
-  static struct GNUNET_TIME_Absolute last_update;
-  struct GNUNET_TIME_Relative min_remaining;
-  struct GNUNET_TIME_Relative remaining;
-  struct GNUNET_TIME_Absolute now;
-  struct OwnAddressList *pos;
-  struct OwnAddressList *prev;
-  struct OwnAddressList *next;
-  int expired;
-
-  if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
-    GNUNET_SCHEDULER_cancel (plugin->address_update_task);
-  plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
-  now = GNUNET_TIME_absolute_get ();
-  min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
-  expired = (GNUNET_TIME_absolute_get_duration (last_update).rel_value > (HELLO_ADDRESS_EXPIRATION.rel_value / 4));
-  prev = NULL;
-  pos = plugin->addresses;
-  while (pos != NULL)
+  best_address = NULL;
+  while (head != NULL)
     {
-      next = pos->next;
-      if (pos->expires.abs_value < now.abs_value)
+      addresses = head->addresses;
+      while (addresses != NULL)
         {
-          expired = GNUNET_YES;
-          if (prev == NULL)
-            plugin->addresses = pos->next;
-          else
-            prev->next = pos->next;
-          GNUNET_free (pos);
+          if ( (addresses->timeout.abs_value < now.abs_value) &&
+              (addresses->connected == GNUNET_YES) )
+            {
+#if DEBUG_TRANSPORT
+              GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                          "Marking long-time inactive connection to `%4s' as down.\n",
+                          GNUNET_i2s (&neighbour->id));
+#endif
+             GNUNET_STATISTICS_update (stats,
+                                       gettext_noop ("# connected addresses"),
+                                       -1,
+                                       GNUNET_NO);
+              addresses->connected = GNUNET_NO;
+            }
+          addresses = addresses->next;
         }
-      else
+
+      addresses = head->addresses;
+      while (addresses != NULL)
         {
-          remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
-          if (remaining.rel_value < min_remaining.rel_value)
-            min_remaining = remaining;
-          prev = pos;
+#if DEBUG_TRANSPORT
+         if (addresses->addr != NULL)
+           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                       "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
+                       a2s (head->plugin->short_name,
+                            addresses->addr,
+                            addresses->addrlen),
+                       GNUNET_i2s (&neighbour->id),
+                       addresses->connected,
+                       addresses->in_transmit,
+                       addresses->validated,
+                       addresses->connect_attempts,
+                       (unsigned long long) addresses->timeout.abs_value,
+                       (unsigned int) addresses->distance);
+#endif
+         if (0==strcmp(head->plugin->short_name,"unix"))
+           {
+             if ( (unix_address == NULL) || 
+                  ( (unix_address != NULL) &&
+                    (addresses->latency.rel_value < unix_address->latency.rel_value) ) )
+               unix_address = addresses;
+           }
+          if ( ( (best_address == NULL) ||
+                (addresses->connected == GNUNET_YES) ||
+                (best_address->connected == GNUNET_NO) ) &&
+              (addresses->in_transmit == GNUNET_NO) &&
+              ( (best_address == NULL) ||
+                (addresses->latency.rel_value < best_address->latency.rel_value)) )
+           best_address = addresses;
+         /* FIXME: also give lower-latency addresses that are not
+            connected a chance some times... */
+          addresses = addresses->next;
         }
-      pos = next;
+      if (unix_address != NULL)
+         break;
+      head = head->next;
+    }
+  if (unix_address != NULL)
+    {
+      best_address = unix_address;
+#if DEBUG_TRANSPORT
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
+                 "Found UNIX address, forced this address\n");
+#endif
+    }
+  if (best_address != NULL)
+    {
+#if DEBUG_TRANSPORT
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "Best address found (`%s') has latency of %llu ms.\n",
+                 (best_address->addrlen > 0)
+                 ? a2s (best_address->ready_list->plugin->short_name,
+                        best_address->addr,
+                      best_address->addrlen)
+                 : "<inbound>",
+                  best_address->latency.rel_value);
+#endif
+    }
+  else
+    {
+      GNUNET_STATISTICS_update (stats,
+                               gettext_noop ("# transmission attempts failed (no address)"),
+                               1,
+                               GNUNET_NO);
     }
 
-  if (expired || fresh)
+  return best_address;
+}
+
+
+/**
+ * FIXME: document.
+ */
+struct GeneratorContext
+{
+  struct TransportPlugin *plug_pos;
+  struct OwnAddressList *addr_pos;
+  struct GNUNET_TIME_Absolute expiration;
+};
+
+
+/**
+ * FIXME: document.
+ */
+static size_t
+address_generator (void *cls, size_t max, void *buf)
+{
+  struct GeneratorContext *gc = cls;
+  size_t ret;
+
+  while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
     {
-      last_update = now;
-      refresh_hello ();
+      gc->plug_pos = gc->plug_pos->next;
+      gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
+    }
+  if (NULL == gc->plug_pos)
+    {
+
+      return 0;
     }
-  min_remaining = GNUNET_TIME_relative_min (min_remaining,
-                                           GNUNET_TIME_relative_divide (HELLO_ADDRESS_EXPIRATION,
-                                                                        2));
-  plugin->address_update_task
-    = GNUNET_SCHEDULER_add_delayed (min_remaining,
-                                   &expire_address_task, plugin);
+  ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
+                                  gc->expiration,
+                                  &gc->addr_pos[1],
+                                  gc->addr_pos->addrlen, buf, max);
+  gc->addr_pos = gc->addr_pos->next;
+  return ret;
+}
+
+
+
+static int
+transmit_our_hello_if_pong (void *cls,
+                           const GNUNET_HashCode *key,
+                           void *value)
+{
+  struct NeighbourMapEntry *npos = value;
+
+  if (GNUNET_YES != npos->received_pong)
+    return GNUNET_OK;
+#if DEBUG_TRANSPORT
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
+             "Transmitting updated `%s' to neighbour `%4s'\n",
+             "HELLO", GNUNET_i2s (&npos->id));
+#endif
+  GNUNET_STATISTICS_update (stats,
+                           gettext_noop ("# transmitted my HELLO to other peers"),
+                           1,
+                           GNUNET_NO);
+  transmit_to_peer (NULL, NULL, 0,
+                   HELLO_ADDRESS_EXPIRATION,
+                   (const char *) our_hello,
+                   GNUNET_HELLO_size(our_hello),
+                   GNUNET_NO, npos);
+  return GNUNET_OK;
 }
 
 
 /**
- * Task used to clean up expired addresses for a plugin.
+ * Construct our HELLO message from all of the addresses of
+ * all of the transports.
  *
- * @param cls closure
- * @param tc context
+ * @param cls unused
+ * @param tc scheduler context
  */
 static void
-expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+refresh_hello_task (void *cls,
+                   const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
-  struct TransportPlugin *plugin = cls;
+  struct GNUNET_HELLO_Message *hello;
+  struct TransportClient *cpos;
+  struct GeneratorContext gc;
+
+  hello_task = GNUNET_SCHEDULER_NO_TASK;
+  gc.plug_pos = plugins;
+  gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
+  gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
+  hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
+#if DEBUG_TRANSPORT
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
+              "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
+#endif
+  GNUNET_STATISTICS_update (stats,
+                           gettext_noop ("# refreshed my HELLO"),
+                           1,
+                           GNUNET_NO);
+  cpos = clients;
+  while (cpos != NULL)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                 "Transmitting my HELLO to client!\n");
+      transmit_to_client (cpos,
+                          (const struct GNUNET_MessageHeader *) hello,
+                          GNUNET_NO);
+      cpos = cpos->next;
+    }
+
+  GNUNET_free_non_null (our_hello);
+  our_hello = hello;
+  GNUNET_PEERINFO_add_peer (peerinfo, our_hello);
+  GNUNET_CONTAINER_multihashmap_iterate (neighbours,
+                                        &transmit_our_hello_if_pong,
+                                        NULL);
+}
 
-  plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
-  if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
-    update_addresses (plugin, GNUNET_NO);
+
+/**
+ * Schedule task to refresh hello (unless such a
+ * task exists already).
+ */
+static void
+refresh_hello ()
+{
+#if DEBUG_TRANSPORT_HELLO
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "refresh_hello() called!\n");
+#endif
+  if (hello_task != GNUNET_SCHEDULER_NO_TASK)
+    return;
+  hello_task
+    = GNUNET_SCHEDULER_add_now (&refresh_hello_task,
+                               NULL);
 }
 
 
@@ -2461,7 +2314,7 @@ remove_session_validations (void *cls,
  */
 static void
 try_fast_reconnect (struct TransportPlugin *p,
-                   struct NeighbourList *nl)
+                   struct NeighbourMapEntry *nl)
 {
   /* FIXME-MW: fast reconnect / transport switching not implemented... */
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
@@ -2493,18 +2346,25 @@ try_fast_reconnect (struct TransportPlugin *p,
    * GNUNET_NO in the call below makes transport disconnect the peer,
    * even if only a single address (out of say, six) went away.  This
    * function must be careful to ONLY disconnect if the peer is gone,
-   * not just a specifi address.
+   * not just a specific address.
    *
    * More specifically, half the places it was used had it WRONG.
    */
 
   /* No reconnect, signal disconnect instead! */
 #if DEBUG_TRANSPORT
+#endif
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
             "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
             "try_fast_reconnect");
-#endif
+
+  GNUNET_STATISTICS_update (stats,
+                            gettext_noop ("# disconnects due to try_fast_reconnect"),
+                            1,
+                            GNUNET_NO);
+#if DISCONNECT || 1
   disconnect_neighbour (nl, GNUNET_YES);
+#endif
 }
 
 
@@ -2525,7 +2385,7 @@ plugin_env_session_end  (void *cls,
                         struct Session *session)
 {
   struct TransportPlugin *p = cls;
-  struct NeighbourList *nl;
+  struct NeighbourMapEntry *nl;
   struct ReadyList *rl;
   struct ForeignAddressList *pos;
   struct ForeignAddressList *prev;
@@ -2563,6 +2423,10 @@ plugin_env_session_end  (void *cls,
                  "Plugin was associated with peer `%4s'\n", 
                  GNUNET_i2s(peer));
 #endif
+      GNUNET_STATISTICS_update (stats,
+                                gettext_noop ("# disconnects due to session end"),
+                                1,
+                                GNUNET_NO);
       disconnect_neighbour (nl, GNUNET_YES);
       return;
     }
@@ -2581,19 +2445,67 @@ plugin_env_session_end  (void *cls,
                  "Session was never marked as ready for peer `%4s'\n", 
                  GNUNET_i2s(peer));
 #endif
+
+      int validations_pending = GNUNET_CONTAINER_multihashmap_contains (validation_map, &peer->hashPubKey);
+
+      /* No session was marked as ready, but we have pending validations so do not disconnect from neighbour */
+      if (validations_pending ==GNUNET_YES)
+        {
+#if DEBUG_TRANSPORT
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "Not disconnecting from peer `%4s due to pending address validations\n", GNUNET_i2s(peer));
+#endif
+        return;
+        }
+
       //FIXME: This conflicts with inbound tcp connections and tcp nat ... debugging in progress
+      GNUNET_STATISTICS_update (stats,
+                                gettext_noop ("# disconnects due to unready session"),
+                                1,
+                                GNUNET_NO);
+
       disconnect_neighbour (nl, GNUNET_YES);
       return; /* was never marked as connected */
     }
   pos->session = NULL;
+  if (GNUNET_YES == pos->connected)
+    {
+      pos->connected = GNUNET_NO;      
+      GNUNET_STATISTICS_update (stats,
+                               gettext_noop ("# connected addresses"),
+                               -1,
+                               GNUNET_NO);
+    }
+  if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
+    {
+      GNUNET_SCHEDULER_cancel (pos->revalidate_task);
+      pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
+    }
+
   if (pos->addrlen != 0)
     {
       if (nl->received_pong != GNUNET_NO)
-       try_fast_reconnect (p, nl);
+        {
+          GNUNET_STATISTICS_update (stats,
+                                    gettext_noop ("# try_fast_reconnect thanks to plugin_env_session_end"),
+                                    1,
+                                    GNUNET_NO);
+         if (GNUNET_YES == pos->connected)                  
+             try_fast_reconnect (p, nl);           
+        }
       else
-       disconnect_neighbour (nl, GNUNET_YES);
+        {
+          GNUNET_STATISTICS_update (stats,
+                                    gettext_noop ("# disconnects due to missing pong"),
+                                    1,
+                                    GNUNET_NO);
+          /* FIXME this is never true?! See: line 2416*/
+         if (GNUNET_YES == pos->connected)
+           disconnect_neighbour (nl, GNUNET_YES);
+        }
       return;
     }
+
   /* was inbound connection, free 'pos' */
   if (prev == NULL)
     rl->addresses = pos->next;
@@ -2604,12 +2516,30 @@ plugin_env_session_end  (void *cls,
       GNUNET_SCHEDULER_cancel (pos->revalidate_task);
       pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
     }
-  GNUNET_free_non_null(pos->ressources);
-  GNUNET_free_non_null(pos->quality);
+  GNUNET_free_non_null (pos->ressources);
+  GNUNET_free_non_null (pos->quality);
+#if HAVE_LIBGLPK
+  ats_modify_problem_state (ats, ATS_MODIFIED);
+#endif
+  if (GNUNET_YES != pos->connected)
+    {
+      /* nothing else to do, connection was never up... */
+      GNUNET_free (pos);
+      return; 
+    }
+  pos->connected = GNUNET_NO;
+  GNUNET_STATISTICS_update (stats,
+                           gettext_noop ("# connected addresses"),
+                           -1,
+                           GNUNET_NO);
   GNUNET_free (pos);
-  ats->stat.recreate_problem = GNUNET_YES;
+
   if (nl->received_pong == GNUNET_NO)
     {
+      GNUNET_STATISTICS_update (stats,
+                                gettext_noop ("# disconnects due to NO pong"),
+                                1,
+                                GNUNET_NO);
       disconnect_neighbour (nl, GNUNET_YES);
       return; /* nothing to do, never connected... */
     }
@@ -2617,8 +2547,12 @@ plugin_env_session_end  (void *cls,
   pos = rl->addresses;
   while (pos != NULL)
     {
-      if (pos->validated)
+      if (GNUNET_YES == pos->validated)
        {
+          GNUNET_STATISTICS_update (stats,
+                                    gettext_noop ("# try_fast_reconnect thanks to validated_address"),
+                                    1,
+                                    GNUNET_NO);
          try_fast_reconnect (p, nl);
          return;
        }
@@ -2639,6 +2573,10 @@ plugin_env_session_end  (void *cls,
    * if there are any addresses that work first, so as not to overdo it.
    * --NE
    */
+  GNUNET_STATISTICS_update (stats,
+                            gettext_noop ("# disconnects due to plugin_env_session_end"),
+                            1,
+                            GNUNET_NO);
   disconnect_neighbour (nl, GNUNET_YES);
 }
 
@@ -2649,45 +2587,61 @@ plugin_env_session_end  (void *cls,
  * provided by the plugin can be reached.
  *
  * @param cls closure
- * @param name name of the transport that generated the address
+ * @param add_remove GNUNET_YES to add, GNUNET_NO to remove the address
  * @param addr one of the addresses of the host, NULL for the last address
  *        the specific address format depends on the transport
  * @param addrlen length of the address
- * @param expires when should this address automatically expire?
  */
 static void
 plugin_env_notify_address (void *cls,
-                           const char *name,
+                          int add_remove,
                            const void *addr,
-                           uint16_t addrlen,
-                           struct GNUNET_TIME_Relative expires)
+                           size_t addrlen)
 {
   struct TransportPlugin *p = cls;
   struct OwnAddressList *al;
-  struct GNUNET_TIME_Absolute abex;
+  struct OwnAddressList *prev;
 
+  GNUNET_assert (p->api != NULL);
+#if DEBUG_TRANSPORT
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             (add_remove == GNUNET_YES)
+             ? "Adding `%s':%s to the set of our addresses\n"
+             : "Removing `%s':%s from the set of our addresses\n",
+             a2s (p->short_name,
+                  addr, addrlen),
+             p->short_name);
+#endif
   GNUNET_assert (addr != NULL);
-  abex = GNUNET_TIME_relative_to_absolute (expires);
-  GNUNET_assert (p == find_transport (name));
-  al = p->addresses;
-  while (al != NULL)
+  if (GNUNET_NO == add_remove)
     {
-      if ( (addrlen == al->addrlen) &&
-          (0 == memcmp (addr, &al[1], addrlen)) )
-        {
-         al->expires = abex;
-         update_addresses (p, GNUNET_NO);
-          return;
-        }
-      al = al->next;
-    }
-  al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
-  al->next = p->addresses;
+      prev = NULL;
+      al = p->addresses;
+      while (al != NULL)
+       {
+         if ( (addrlen == al->addrlen) &&
+              (0 == memcmp (addr, &al[1], addrlen)) )
+           {
+             if (prev == NULL)
+               p->addresses = al->next;
+             else
+               prev->next = al->next;
+             GNUNET_free (al);
+             refresh_hello ();
+             return;
+           }
+         prev = al;
+         al = al->next;
+       }
+      GNUNET_break (0);
+      return;
+    }
+  al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
+  al->next = p->addresses;
   p->addresses = al;
-  al->expires = abex;
   al->addrlen = addrlen;
   memcpy (&al[1], addr, addrlen);
-  update_addresses (p, GNUNET_YES);
+  refresh_hello ();
 }
 
 
@@ -2704,9 +2658,16 @@ notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
   uint32_t ats_count;
   size_t size;
 
+  if (0 == memcmp (peer,
+                  &my_identity,
+                  sizeof (struct GNUNET_PeerIdentity)))
+    {
+      GNUNET_break (0);
+      return;
+    }
 #if DEBUG_TRANSPORT
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Notifying clients about connection from `%s'\n",
+             "Notifying clients about connection with `%s'\n",
              GNUNET_i2s (peer));
 #endif
   GNUNET_STATISTICS_update (stats,
@@ -2716,34 +2677,33 @@ notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
 
   ats_count = 2;
   size  = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
-  if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
-  {
-         GNUNET_break(0);
-  }
+  GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
   cim = GNUNET_malloc (size);
-
   cim->header.size = htons (size);
   cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
   cim->ats_count = htonl(2);
-  (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
-  (&(cim->ats))[0].value = htonl (distance);
-  (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
-  (&(cim->ats))[1].value = htonl ((uint32_t) latency.rel_value);
-  (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
-  (&(cim->ats))[2].value = htonl (0);
+  (&cim->ats)[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
+  (&cim->ats)[0].value = htonl (distance);
+  (&cim->ats)[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
+  (&cim->ats)[1].value = htonl ((uint32_t) latency.rel_value);
+  (&cim->ats)[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
+  (&cim->ats)[2].value = htonl (0);
   memcpy (&cim->id, peer, sizeof (struct GNUNET_PeerIdentity));
 
   /* notify ats about connecting peer */
-  if (shutdown_in_progress == GNUNET_NO)
-       ats_notify_peer_connect (peer, &(cim->ats), 2);
-
+  if ((ats != NULL) && (shutdown_in_progress == GNUNET_NO))
+    {
+#if HAVE_LIBGLPK
+      ats_modify_problem_state(ats, ATS_MODIFIED);
+      ats_calculate_bandwidth_distribution (ats);
+#endif
+    }
   cpos = clients;
   while (cpos != NULL)
     {
-      transmit_to_client (cpos, &(cim->header), GNUNET_NO);
+      transmit_to_client (cpos, &cim->header, GNUNET_NO);
       cpos = cpos->next;
     }
-
   GNUNET_free (cim);
 }
 
@@ -2757,6 +2717,13 @@ notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
   struct DisconnectInfoMessage dim;
   struct TransportClient *cpos;
 
+  if (0 == memcmp (peer,
+                  &my_identity,
+                  sizeof (struct GNUNET_PeerIdentity)))
+    {
+      GNUNET_break (0);
+      return;
+    }
 #if DEBUG_TRANSPORT
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Notifying clients about lost connection to `%s'\n",
@@ -2772,8 +2739,13 @@ notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
   memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
 
   /* notify ats about connecting peer */
-  if (shutdown_in_progress == GNUNET_NO)
-         ats_notify_peer_disconnect (peer);
+  if ((ats != NULL) && (shutdown_in_progress == GNUNET_NO))
+  {
+#if HAVE_LIBGLPK
+    ats_modify_problem_state(ats, ATS_MODIFIED);
+    ats_calculate_bandwidth_distribution (ats);
+#endif
+  }
 
   cpos = clients;
   while (cpos != NULL)
@@ -2798,7 +2770,7 @@ notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
  * @return NULL if no such entry exists
  */
 static struct ForeignAddressList *
-find_peer_address(struct NeighbourList *neighbour,
+find_peer_address(struct NeighbourMapEntry *neighbour,
                  const char *tname,
                  struct Session *session,
                  const char *addr,
@@ -2844,7 +2816,7 @@ find_peer_address(struct NeighbourList *neighbour,
  * @return NULL if we do not have a transport plugin for 'tname'
  */
 static struct ForeignAddressList *
-add_peer_address (struct NeighbourList *neighbour,
+add_peer_address (struct NeighbourMapEntry *neighbour,
                  const char *tname,
                  struct Session *session,
                  const char *addr,
@@ -2914,7 +2886,7 @@ add_peer_address (struct NeighbourList *neighbour,
          r[c].c = ressources[c].c_default;
          GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                      "Assigning default cost to peer `%s' addr plugin `%s'! This should not happen!\n",
-                     GNUNET_i2s(&neighbour->peer), 
+                     GNUNET_i2s(&neighbour->id),
                      neighbour->plugins->plugin->short_name);
        }
     }
@@ -3055,76 +3027,11 @@ check_address_exists (void *cls,
 }
 
 
-
-/**
- * Iterator to free entries in the validation_map.
- *
- * @param cls closure (unused)
- * @param key current key code
- * @param value value in the hash map (validation to abort)
- * @return GNUNET_YES (always)
- */
-static int
-abort_validation (void *cls,
-                 const GNUNET_HashCode * key,
-                 void *value)
-{
-  struct ValidationEntry *va = value;
-
-  if (GNUNET_SCHEDULER_NO_TASK != va->timeout_task)
-    GNUNET_SCHEDULER_cancel (va->timeout_task);
-  GNUNET_free (va->transport_name);
-  if (va->chvc != NULL)
-    {
-      va->chvc->ve_count--;
-      if (va->chvc->ve_count == 0)
-       {
-         GNUNET_CONTAINER_DLL_remove (chvc_head,
-                                      chvc_tail,
-                                      va->chvc);
-         GNUNET_free (va->chvc);
-       }
-      va->chvc = NULL;
-    }
-  GNUNET_free (va);
-  return GNUNET_YES;
-}
-
-
-/**
- * HELLO validation cleanup task (validation failed).
- *
- * @param cls the 'struct ValidationEntry' that failed
- * @param tc scheduler context (unused)
- */
-static void
-timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
-  struct ValidationEntry *va = cls;
-  struct GNUNET_PeerIdentity pid;
-
-  va->timeout_task = GNUNET_SCHEDULER_NO_TASK;
-  GNUNET_STATISTICS_update (stats,
-                           gettext_noop ("# address validation timeouts"),
-                           1,
-                           GNUNET_NO);
-  GNUNET_CRYPTO_hash (&va->publicKey,
-                     sizeof (struct
-                             GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
-                     &pid.hashPubKey);
-  GNUNET_break (GNUNET_OK ==
-                GNUNET_CONTAINER_multihashmap_remove (validation_map,
-                                                     &pid.hashPubKey,
-                                                     va));
-  abort_validation (NULL, NULL, va);
-}
-
-
 static void
 neighbour_timeout_task (void *cls,
                       const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
-  struct NeighbourList *n = cls;
+  struct NeighbourMapEntry *n = cls;
 
 #if DEBUG_TRANSPORT
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
@@ -3153,7 +3060,7 @@ schedule_next_ping (struct ForeignAddressList *fal);
  * Add the given address to the list of foreign addresses
  * available for the given peer (check for duplicates).
  *
- * @param cls the respective 'struct NeighbourList' to update
+ * @param cls the respective 'struct NeighbourMapEntry' to update
  * @param tname name of the transport
  * @param expiration expiration time
  * @param addr the address
@@ -3167,7 +3074,7 @@ add_to_foreign_address_list (void *cls,
                             const void *addr,
                             uint16_t addrlen)
 {
-  struct NeighbourList *n = cls;
+  struct NeighbourMapEntry *n = cls;
   struct ForeignAddressList *fal;
   int try;
 
@@ -3241,7 +3148,7 @@ add_to_foreign_address_list (void *cls,
  * Add addresses in validated HELLO "h" to the set of addresses
  * we have for this peer.
  *
- * @param cls closure ('struct NeighbourList*')
+ * @param cls closure ('struct NeighbourMapEntry*')
  * @param peer id of the peer, NULL for last call
  * @param h hello message for the peer (can be NULL)
  * @param err_msg NULL if successful, otherwise contains error message
@@ -3252,7 +3159,7 @@ add_hello_for_peer (void *cls,
                    const struct GNUNET_HELLO_Message *h,
                    const char *err_msg)
 {
-  struct NeighbourList *n = cls;
+  struct NeighbourMapEntry *n = cls;
 
   if (err_msg != NULL)
     {
@@ -3301,14 +3208,17 @@ add_hello_for_peer (void *cls,
  * @param do_hello should we schedule transmitting a HELLO
  * @return the new neighbour list entry
  */
-static struct NeighbourList *
+static struct NeighbourMapEntry *
 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer,
                     int do_hello)
 {
-  struct NeighbourList *n;
+  struct NeighbourMapEntry *n;
   struct TransportPlugin *tp;
   struct ReadyList *rl;
 
+  GNUNET_assert (0 != memcmp (peer,
+                             &my_identity,
+                             sizeof (struct GNUNET_PeerIdentity)));
 #if DEBUG_TRANSPORT
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Setting up state for neighbour `%4s'\n",
@@ -3318,9 +3228,7 @@ setup_new_neighbour (const struct GNUNET_PeerIdentity *peer,
                            gettext_noop ("# active neighbours"),
                            1,
                            GNUNET_NO);
-  n = GNUNET_malloc (sizeof (struct NeighbourList));
-  n->next = neighbours;
-  neighbours = n;
+  n = GNUNET_malloc (sizeof (struct NeighbourMapEntry));
   n->id = *peer;
   n->peer_timeout =
     GNUNET_TIME_relative_to_absolute
@@ -3346,6 +3254,10 @@ setup_new_neighbour (const struct GNUNET_PeerIdentity *peer,
   n->distance = -1;
   n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
                                                   &neighbour_timeout_task, n);
+  GNUNET_CONTAINER_multihashmap_put (neighbours,
+                                    &n->id.hashPubKey,
+                                    n,
+                                    GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
   if (do_hello)
     {
       GNUNET_STATISTICS_update (stats,
@@ -3382,7 +3294,7 @@ setup_new_neighbour (const struct GNUNET_PeerIdentity *peer,
  * @param n NULL if communication is not acceptable
  */
 typedef void (*SetupContinuation)(void *cls,
-                                 struct NeighbourList *n);
+                                 struct NeighbourMapEntry *n);
 
 
 /**
@@ -3584,12 +3496,12 @@ do_blacklist_check (void *cls,
 
 
 /**
- * Obtain a 'struct NeighbourList' for the given peer.  If such an entry
+ * Obtain a 'struct NeighbourMapEntry' for the given peer.  If such an entry
  * does not yet exist, check the blacklist.  If the blacklist says creating
  * one is acceptable, create one and call the continuation; otherwise
  * call the continuation with NULL.
  *
- * @param peer peer to setup or look up a struct NeighbourList for
+ * @param peer peer to setup or look up a struct NeighbourMapEntry for
  * @param do_hello should we also schedule sending our HELLO to the peer
  *        if this is a new record
  * @param cont function to call with the 'struct NeigbhbourList*'
@@ -3601,7 +3513,7 @@ setup_peer_check_blacklist (const struct GNUNET_PeerIdentity *peer,
                            SetupContinuation cont,
                            void *cont_cls)
 {
-  struct NeighbourList *n;
+  struct NeighbourMapEntry *n;
   struct BlacklistCheck *bc;
 
   n = find_neighbour(peer);
@@ -3640,14 +3552,14 @@ setup_peer_check_blacklist (const struct GNUNET_PeerIdentity *peer,
  * Function called with the result of querying a new blacklister about
  * it being allowed (or not) to continue to talk to an existing neighbour.
  *
- * @param cls the original 'struct NeighbourList'
+ * @param cls the original 'struct NeighbourMapEntry'
  * @param n NULL if we need to disconnect
  */
 static void
 confirm_or_drop_neighbour (void *cls,
-                          struct NeighbourList *n)
+                          struct NeighbourMapEntry *n)
 {
-  struct NeighbourList * orig = cls;
+  struct NeighbourMapEntry * orig = cls;
 
   if (n == NULL)
     {
@@ -3656,11 +3568,52 @@ confirm_or_drop_neighbour (void *cls,
               "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&orig->id),
               "confirm_or_drop_neighboUr");
 #endif
+      GNUNET_STATISTICS_update (stats,
+                                gettext_noop ("# disconnects due to blacklist"),
+                                1,
+                                GNUNET_NO);
       disconnect_neighbour (orig, GNUNET_NO);
     }
 }
 
 
+struct TestConnectionContext
+{
+  int first;
+
+  struct Blacklisters *bl;
+};
+
+
+static int
+test_connection_ok (void *cls,
+                   const GNUNET_HashCode *key,
+                   void *value)
+{
+  struct TestConnectionContext *tcc = cls;
+  struct NeighbourMapEntry *n = value;
+  struct BlacklistCheck *bc;
+
+  
+  bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
+  GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
+  bc->peer = n->id;
+  bc->do_hello = GNUNET_NO;
+  bc->cont = &confirm_or_drop_neighbour;
+  bc->cont_cls = n;
+  bc->bl_pos = tcc->bl;
+  if (GNUNET_YES == tcc->first)
+    { 
+      /* all would wait for the same client, no need to
+        create more than just the first task right now */
+      bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
+                                          bc);
+      tcc->first = GNUNET_NO;
+    }
+  return GNUNET_OK;
+}
+
+
 /**
  * Handle a request to start a blacklist.
  *
@@ -3674,8 +3627,7 @@ handle_blacklist_init (void *cls,
                       const struct GNUNET_MessageHeader *message)
 {
   struct Blacklisters *bl;
-  struct BlacklistCheck *bc;
-  struct NeighbourList *n;
+  struct TestConnectionContext tcc;
 
   bl = bl_head;
   while (bl != NULL)
@@ -3693,22 +3645,11 @@ handle_blacklist_init (void *cls,
   GNUNET_SERVER_client_keep (client);
   GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
   /* confirm that all existing connections are OK! */
-  n = neighbours;
-  while (NULL != n)
-    {
-      bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
-      GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
-      bc->peer = n->id;
-      bc->do_hello = GNUNET_NO;
-      bc->cont = &confirm_or_drop_neighbour;
-      bc->cont_cls = n;
-      bc->bl_pos = bl;
-      if (n == neighbours) /* all would wait for the same client, no need to
-                             create more than just the first task right now */
-       bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
-                                            bc);
-      n = n->next;
-    }
+  tcc.bl = bl;
+  tcc.first = GNUNET_YES;
+  GNUNET_CONTAINER_multihashmap_iterate (neighbours,
+                                        &test_connection_ok,
+                                        &tcc);
 }
 
 
@@ -3790,7 +3731,7 @@ send_periodic_ping (void *cls,
   struct ForeignAddressList *peer_address = cls;
   struct TransportPlugin *tp;
   struct ValidationEntry *va;
-  struct NeighbourList *neighbour;
+  struct NeighbourMapEntry *neighbour;
   struct TransportPingMessage ping;
   struct CheckAddressExistsClosure caec;
   char * message_buf;
@@ -3801,6 +3742,7 @@ send_periodic_ping (void *cls,
   peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
   if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
     return;
+  GNUNET_assert (peer_address != NULL);
   tp = peer_address->ready_list->plugin;
   neighbour = peer_address->ready_list->neighbour;
   if (GNUNET_YES != neighbour->public_key_valid)
@@ -3814,6 +3756,7 @@ send_periodic_ping (void *cls,
   caec.tname = tp->short_name;
   caec.session = peer_address->session;
   caec.exists = GNUNET_NO;
+
   GNUNET_CONTAINER_multihashmap_iterate (validation_map,
                                          &check_address_exists,
                                          &caec);
@@ -3939,7 +3882,7 @@ send_periodic_ping (void *cls,
                     HELLO_VERIFICATION_TIMEOUT,
                     message_buf, tsize,
                     GNUNET_YES, neighbour);
-  GNUNET_free(message_buf);
+  GNUNET_free (message_buf);
   schedule_next_ping (peer_address);
 }
 
@@ -3956,7 +3899,10 @@ schedule_next_ping (struct ForeignAddressList *fal)
   struct GNUNET_TIME_Relative delay;
 
   if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
-    return;
+    {
+      GNUNET_SCHEDULER_cancel(fal->revalidate_task);
+      fal->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
+    }
   delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
   delay.rel_value /= 2; /* do before expiration */
   delay = GNUNET_TIME_relative_min (delay,
@@ -3966,6 +3912,7 @@ schedule_next_ping (struct ForeignAddressList *fal)
       delay = GNUNET_TIME_UNIT_ZERO;
       fal->estimated = GNUNET_YES;
     }
+
   if (GNUNET_YES == fal->connected)
     {
       delay = GNUNET_TIME_relative_min (delay,
@@ -3978,6 +3925,8 @@ schedule_next_ping (struct ForeignAddressList *fal)
                                    GNUNET_TIME_UNIT_SECONDS);
   /* randomize a bit (to avoid doing all at the same time) */
   delay.rel_value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
+
+  GNUNET_assert (fal->revalidate_task == GNUNET_SCHEDULER_NO_TASK);
   fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(delay,
                                                      &send_periodic_ping,
                                                      fal);
@@ -3995,7 +3944,7 @@ schedule_next_ping (struct ForeignAddressList *fal)
  */
 static void
 handle_payload_message (const struct GNUNET_MessageHeader *message,
-                       struct NeighbourList *n)
+                       struct NeighbourMapEntry *n)
 {
   struct InboundMessage *im;
   struct TransportClient *cpos;
@@ -4103,7 +4052,7 @@ check_pending_validation (void *cls,
   unsigned int challenge = ntohl(pong->challenge);
   struct GNUNET_HELLO_Message *hello;
   struct GNUNET_PeerIdentity target;
-  struct NeighbourList *n;
+  struct NeighbourMapEntry *n;
   struct ForeignAddressList *fal;
   struct OwnAddressList *oal;
   struct TransportPlugin *tp;
@@ -4177,7 +4126,8 @@ check_pending_validation (void *cls,
                         &my_identity,
                         sizeof (struct GNUNET_PeerIdentity)))
        {
-      char * peer;
+         char * peer;
+
          GNUNET_asprintf(&peer, "%s",GNUNET_i2s (&pong->pid));
 #if DEBUG_TRANSPORT
          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -4212,11 +4162,17 @@ check_pending_validation (void *cls,
       if (oal == NULL)
        {
          GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                     _("Not accepting PONG with address `%s' since I cannot confirm having this address.\n"),
+                     _("Not accepting PONG from `%s' with address `%s' since I cannot confirm using this address.\n"),
+                     GNUNET_i2s (&pong->pid),
                      a2s (ve->transport_name,
                           &addr[slen],
                           alen));
+         /* FIXME: since the sender of the PONG currently uses the
+            wrong address (see FIMXE there!), we cannot run a 
+            proper check here... */
+#if FIXME_URGENT
          return GNUNET_NO;
+#endif
        }
       if (GNUNET_OK !=
          GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING,
@@ -4298,7 +4254,6 @@ check_pending_validation (void *cls,
       if (GNUNET_NO == n->received_pong)
        {
          n->received_pong = GNUNET_YES;
-
          notify_clients_connect (&target, n->latency, n->distance);
          if (NULL != (prem = n->pre_connect_message_buffer))
            {
@@ -4346,6 +4301,16 @@ handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
              const char *sender_address,
              size_t sender_address_len)
 {
+  if (0 == memcmp (peer,
+                  &my_identity,
+                  sizeof (struct GNUNET_PeerIdentity)))
+    {
+      /* PONG send to self, ignore */
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                 "Receiving `%s' message from myself\n", 
+                 "PONG");
+      return;
+    }
 #if DEBUG_TRANSPORT > 1
   /* we get tons of these that just get discarded, only log
      if we are quite verbose */
@@ -4390,7 +4355,7 @@ handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
  */
 static void
 transmit_hello_and_ping (void *cls,
-                        struct NeighbourList *neighbour)
+                        struct NeighbourMapEntry *neighbour)
 {
   struct ValidationEntry *va = cls;
   struct ForeignAddressList *peer_address;
@@ -4433,6 +4398,8 @@ transmit_hello_and_ping (void *cls,
       abort_validation (NULL, NULL, va);
       return;
     }
+  if (NULL == our_hello)
+    refresh_hello_task (NULL, NULL);
   hello_size = GNUNET_HELLO_size(our_hello);
   slen = strlen(va->transport_name) + 1;
   tsize = sizeof(struct TransportPingMessage) + hello_size + va->addrlen + slen;
@@ -4473,7 +4440,7 @@ transmit_hello_and_ping (void *cls,
                    HELLO_VERIFICATION_TIMEOUT,
                    message_buf, tsize,
                    GNUNET_YES, neighbour);
-  GNUNET_free(message_buf);
+  GNUNET_free (message_buf);
 }
 
 
@@ -4631,7 +4598,7 @@ check_hello_validated (void *cls,
   struct GNUNET_HELLO_Message *plain_hello;
   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
   struct GNUNET_PeerIdentity target;
-  struct NeighbourList *n;
+  struct NeighbourMapEntry *n;
 
   if (err_msg != NULL)
     {
@@ -4758,9 +4725,11 @@ process_hello (struct TransportPlugin *plugin,
   const struct GNUNET_HELLO_Message *hello;
   struct CheckHelloValidatedContext *chvc;
   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
+  struct NeighbourMapEntry *n;
 #if DEBUG_TRANSPORT_HELLO > 2
   char *my_id;
 #endif
+
   hsize = ntohs (message->size);
   if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
       (hsize < sizeof (struct GNUNET_MessageHeader)))
@@ -4773,21 +4742,6 @@ process_hello (struct TransportPlugin *plugin,
                            1,
                            GNUNET_NO);
 
-  /* first, check if load is too high */
-  if (GNUNET_SCHEDULER_get_load (GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
-    {
-      GNUNET_STATISTICS_update (stats,
-                               gettext_noop ("# HELLOs ignored due to high load"),
-                               1,
-                               GNUNET_NO);
-#if DEBUG_TRANSPORT_HELLO
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "Ignoring `%s' for `%4s', load too high.\n",
-                  "HELLO",
-                  GNUNET_i2s (&target));
-#endif
-      return GNUNET_OK;
-    }
   hello = (const struct GNUNET_HELLO_Message *) message;
   if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
     {
@@ -4800,7 +4754,6 @@ process_hello (struct TransportPlugin *plugin,
       GNUNET_break_op (0);
       return GNUNET_SYSERR;
     }
-
   GNUNET_CRYPTO_hash (&publicKey,
                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
                       &target.hashPubKey);
@@ -4811,7 +4764,6 @@ process_hello (struct TransportPlugin *plugin,
               "HELLO",
               GNUNET_i2s (&target));
 #endif
-
   if (0 == memcmp (&my_identity,
                   &target,
                   sizeof (struct GNUNET_PeerIdentity)))
@@ -4822,6 +4774,31 @@ process_hello (struct TransportPlugin *plugin,
                                GNUNET_NO);
       return GNUNET_OK;
     }
+  n = find_neighbour (&target);
+  if ( (NULL != n) &&
+       (! n->public_key_valid) )
+    {
+      GNUNET_HELLO_get_key (hello, &n->publicKey);
+      n->public_key_valid = GNUNET_YES;
+    }
+
+  /* check if load is too high before doing expensive stuff */
+  if (GNUNET_SCHEDULER_get_load (GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
+    {
+      GNUNET_STATISTICS_update (stats,
+                               gettext_noop ("# HELLOs ignored due to high load"),
+                               1,
+                               GNUNET_NO);
+#if DEBUG_TRANSPORT_HELLO
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "Ignoring `%s' for `%4s', load too high.\n",
+                  "HELLO",
+                  GNUNET_i2s (&target));
+#endif
+      return GNUNET_OK;
+    }
+
+
   chvc = chvc_head;
   while (NULL != chvc)
     {
@@ -4837,14 +4814,14 @@ process_hello (struct TransportPlugin *plugin,
 #endif
          return GNUNET_OK; /* validation already pending */
        }
-      if (GNUNET_HELLO_size(hello) == GNUNET_HELLO_size (chvc->hello))
+      if (GNUNET_HELLO_size (hello) == GNUNET_HELLO_size (chvc->hello))
        GNUNET_break (0 != memcmp (hello, chvc->hello,
                                   GNUNET_HELLO_size(hello)));
       chvc = chvc->next;
     }
 
 #if BREAK_TESTS
-  struct NeighbourList *temp_neighbor = find_neighbour(&target);
+  struct NeighbourMapEntry *temp_neighbor = find_neighbour(&target);
   if ((NULL != temp_neighbor))
     {
       fprintf(stderr, "Already know peer, ignoring hello\n");
@@ -4855,8 +4832,8 @@ process_hello (struct TransportPlugin *plugin,
 #if DEBUG_TRANSPORT_HELLO > 2
   if (plugin != NULL)
     {
-      my_id = GNUNET_strdup(GNUNET_i2s(plugin->env.my_identity));
 #if DEBUG_TRANSPORT
+      my_id = GNUNET_strdup(GNUNET_i2s(plugin->env.my_identity));
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                   "%s: Starting validation of `%s' message for `%4s' via '%s' of size %u\n",
                   my_id,
@@ -4864,8 +4841,8 @@ process_hello (struct TransportPlugin *plugin,
                   GNUNET_i2s (&target),
                   plugin->short_name,
                   GNUNET_HELLO_size(hello));
+      GNUNET_free (my_id);
 #endif
-      GNUNET_free(my_id);
     }
 #endif
   chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
@@ -4907,15 +4884,15 @@ process_hello (struct TransportPlugin *plugin,
  *              regardless of whether other addresses exist.
  */
 static void
-disconnect_neighbour (struct NeighbourList *n, int check)
+disconnect_neighbour (struct NeighbourMapEntry *n, int check)
 {
   struct ReadyList *rpos;
-  struct NeighbourList *npos;
-  struct NeighbourList *nprev;
   struct MessageQueue *mq;
   struct ForeignAddressList *peer_addresses;
   struct ForeignAddressList *peer_pos;
 
+  if (GNUNET_YES == n->in_disconnect)
+    return;
   if (GNUNET_YES == check)
     {
       rpos = n->plugins;
@@ -4924,13 +4901,16 @@ disconnect_neighbour (struct NeighbourList *n, int check)
           peer_addresses = rpos->addresses;
           while (peer_addresses != NULL)
             {
-                 // Do not disconnect if: an address is connected or an inbound address exists
+              /* Do not disconnect if: an address is connected or an inbound address exists */
               if ((GNUNET_YES == peer_addresses->connected) || (peer_addresses->addrlen == 0))
                 {
 #if DEBUG_TRANSPORT
                   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                             "NOT Disconnecting from `%4s', still have live addresses!\n",
-                             GNUNET_i2s (&n->id));
+                             "NOT Disconnecting from `%4s', still have live address `%s'!\n",
+                             GNUNET_i2s (&n->id),
+                             a2s (peer_addresses->ready_list->plugin->short_name,
+                                  peer_addresses->addr,
+                                  peer_addresses->addrlen));
 #endif
                   return;             /* still connected */
                 }
@@ -4944,24 +4924,17 @@ disconnect_neighbour (struct NeighbourList *n, int check)
               "Disconnecting from `%4s'\n",
              GNUNET_i2s (&n->id));
 #endif
-  /* remove n from neighbours list */
-  nprev = NULL;
-  npos = neighbours;
-  while ((npos != NULL) && (npos != n))
-    {
-      nprev = npos;
-      npos = npos->next;
-    }
-  GNUNET_assert (npos != NULL);
-  if (nprev == NULL)
-    neighbours = n->next;
-  else
-    nprev->next = n->next;
+  n->in_disconnect = GNUNET_YES; /* prevent recursive entry */
 
   /* notify all clients about disconnect */
   if (GNUNET_YES == n->received_pong)
-    notify_clients_disconnect (&n->id);
-
+    {
+      n->received_pong = GNUNET_NO;
+      notify_clients_disconnect (&n->id);
+    }
+#if HAVE_LIBGLPK
+  ats_modify_problem_state(ats, ATS_MODIFIED);
+#endif
   /* clean up all plugins, cancel connections and pending transmissions */
   while (NULL != (rpos = n->plugins))
     {
@@ -4972,10 +4945,13 @@ disconnect_neighbour (struct NeighbourList *n, int check)
           peer_pos = rpos->addresses;
           rpos->addresses = peer_pos->next;
          if (peer_pos->connected == GNUNET_YES)
-           GNUNET_STATISTICS_update (stats,
-                                     gettext_noop ("# connected addresses"),
-                                     -1,
-                                     GNUNET_NO);
+           {
+             GNUNET_STATISTICS_update (stats,
+                                       gettext_noop ("# connected addresses"),
+                                       -1,
+                                       GNUNET_NO);
+             peer_pos->connected = GNUNET_NO;
+           }
          if (GNUNET_YES == peer_pos->validated)
            GNUNET_STATISTICS_update (stats,
                                      gettext_noop ("# peer addresses considered valid"),
@@ -4986,12 +4962,11 @@ disconnect_neighbour (struct NeighbourList *n, int check)
              GNUNET_SCHEDULER_cancel (peer_pos->revalidate_task);
              peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
            }
-         GNUNET_free(peer_pos->ressources);
+         GNUNET_free (peer_pos->ressources);
          peer_pos->ressources = NULL;
-         GNUNET_free(peer_pos->quality);
+         GNUNET_free (peer_pos->quality);
          peer_pos->ressources = NULL;
-         GNUNET_free(peer_pos);
-         ats->stat.recreate_problem = GNUNET_YES;
+         GNUNET_free (peer_pos);
         }
       GNUNET_free (rpos);
     }
@@ -5015,6 +4990,19 @@ disconnect_neighbour (struct NeighbourList *n, int check)
                                 sizeof(struct GNUNET_PeerIdentity)));
       GNUNET_free (mq);
     }
+
+  while (NULL != (mq = n->cont_head))
+    {
+
+      GNUNET_CONTAINER_DLL_remove (n->cont_head,
+                                   n->cont_tail,
+                                   mq);
+      GNUNET_assert (0 == memcmp(&mq->neighbour_id,
+                                 &n->id,
+                                 sizeof(struct GNUNET_PeerIdentity)));
+      GNUNET_free (mq);
+    }
+
   if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
     {
       GNUNET_SCHEDULER_cancel (n->timeout_task);
@@ -5034,6 +5022,11 @@ disconnect_neighbour (struct NeighbourList *n, int check)
                                 GNUNET_NO);
       n->piter = NULL;
     }
+
+  GNUNET_assert (GNUNET_OK ==
+                GNUNET_CONTAINER_multihashmap_remove (neighbours,
+                                                      &n->id.hashPubKey,
+                                                      n));
   /* finally, free n itself */
   GNUNET_STATISTICS_update (stats,
                            gettext_noop ("# active neighbours"),
@@ -5049,23 +5042,24 @@ disconnect_neighbour (struct NeighbourList *n, int check)
  * in response to the peer by any means necessary.
  */
 static int
-handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
-           const struct GNUNET_PeerIdentity *peer,
-           struct Session *session,
-           const char *sender_address,
-           uint16_t sender_address_len)
+handle_ping (void *cls, const struct GNUNET_MessageHeader *message,
+            const struct GNUNET_PeerIdentity *peer,
+            struct Session *session,
+            const char *sender_address,
+            uint16_t sender_address_len)
 {
   struct TransportPlugin *plugin = cls;
   struct SessionHeader *session_header = (struct SessionHeader*) session;
   struct TransportPingMessage *ping;
   struct TransportPongMessage *pong;
-  struct NeighbourList *n;
+  struct NeighbourMapEntry *n;
   struct ReadyList *rl;
   struct ForeignAddressList *fal;
   struct OwnAddressList *oal;
   const char *addr;
   size_t alen;
   size_t slen;
+  int did_pong;
 
   if (ntohs (message->size) < sizeof (struct TransportPingMessage))
     {
@@ -5118,6 +5112,19 @@ handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
                      GNUNET_i2s (peer));
          return GNUNET_SYSERR;
        }
+      /* FIXME-urg: the use of 'sender_address' in the code below is doubly-wrong:
+        1) it is NULL when we need to have a real value
+       2) it is documented to be the address of the sender (source-IP), where
+       what we actually want is our LISTEN IP (what we 'bound' to); which we don't even
+       have...
+      */
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                 "Creating PONG indicating that we received a connection at our address `%s' from `%s'.\n",
+                 a2s (plugin->short_name,
+                      sender_address,
+                      sender_address_len),                    
+                 GNUNET_i2s (peer));
+
       pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len + slen);
       pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len + slen);
       pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
@@ -5214,8 +5221,7 @@ handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                      "Creating PONG signature to indicate ownership.\n");
 #endif
-         oal->pong_sig_expires = GNUNET_TIME_absolute_min (oal->expires,
-                                                           GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
+         oal->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
          pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
          GNUNET_assert (GNUNET_OK ==
                         GNUNET_CRYPTO_rsa_sign (my_private_key,
@@ -5245,6 +5251,7 @@ handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
     }
   n = find_neighbour(peer);
   GNUNET_assert (n != NULL);
+  did_pong = GNUNET_NO;
   /* first try reliable response transmission */
   rl = n->plugins;
   while (rl != NULL)
@@ -5264,6 +5271,9 @@ handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
                                           GNUNET_SYSERR,
                                           NULL, NULL))
            {
+             GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                         "Transmitted PONG to `%s' via reliable mechanism\n",
+                         GNUNET_i2s (peer));
              /* done! */
              GNUNET_STATISTICS_update (stats,
                                        gettext_noop ("# PONGs unicast via reliable transport"),
@@ -5272,6 +5282,7 @@ handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
              GNUNET_free (pong);
              return GNUNET_OK;
            }
+         did_pong = GNUNET_YES;
          fal = fal->next;
        }
       rl = rl->next;
@@ -5287,6 +5298,13 @@ handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
       fal = rl->addresses;
       while (fal != NULL)
        {
+         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                     "Transmitting PONG to `%s' via unreliable mechanism `%s':%s\n",
+                     GNUNET_i2s (peer),
+                     a2s (rl->plugin->short_name,
+                          fal->addr,
+                          fal->addrlen),
+                     rl->plugin->short_name);
          transmit_to_peer(NULL, fal,
                           TRANSPORT_PONG_PRIORITY,
                           HELLO_VERIFICATION_TIMEOUT,
@@ -5294,23 +5312,25 @@ handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
                           ntohs(pong->header.size),
                           GNUNET_YES,
                           n);
+         did_pong = GNUNET_YES;
          fal = fal->next;
        }
       rl = rl->next;
     }
   GNUNET_free(pong);
+  if (GNUNET_YES != did_pong)
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+               _("Could not send PONG to `%s': no address available\n"),
+               GNUNET_i2s (peer));
   return GNUNET_OK;
 }
 
 
-
-
-
 /**
- * Function called by the plugin for each received message.
- * Update data volumes, possibly notify plugins about
- * reducing the rate at which they read from the socket
- * and generally forward to our receive callback.
+ * Function called by the plugin for each received message.  Update
+ * data volumes, possibly notify plugins about reducing the rate at
+ * which they read from the socket and generally forward to our
+ * receive callback.
  *
  * @param cls the "struct TransportPlugin *" we gave to the plugin
  * @param peer (claimed) identity of the other peer
@@ -5337,11 +5357,19 @@ plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
   struct ReadyList *service_context;
   struct ForeignAddressList *peer_address;
   uint16_t msize;
-  struct NeighbourList *n;
+  struct NeighbourMapEntry *n;
   struct GNUNET_TIME_Relative ret;
   uint32_t distance;
   int c;
 
+  if (0 == memcmp (peer,
+                  &my_identity,
+                  sizeof (struct GNUNET_PeerIdentity)))
+    {
+      /* refuse to receive from myself */
+      GNUNET_break (0); 
+      return GNUNET_TIME_UNIT_FOREVER_REL;
+    }
   if (is_blacklisted (peer, plugin))
     return GNUNET_TIME_UNIT_FOREVER_REL;
   n = find_neighbour (peer);
@@ -5357,9 +5385,7 @@ plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
   for (c=0; c<ats_count; c++)
     if (ntohl(ats_data[c].type) == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
       distance = ntohl(ats_data[c].value);
-  
-  /* notify ATS about incoming data */
-  //ats_notify_ats_data(peer, ats_data);
+
 
   if (message != NULL)
     {
@@ -5377,10 +5403,26 @@ plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
          
          peer_address->distance = distance;
          if (GNUNET_YES == peer_address->validated)
+         {
            mark_address_connected (peer_address);
+           schedule_next_ping (peer_address);
+         }
+         else
+         {
+#if DEBUG_TRANSPORT
+           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                       "New address is unvalidated, trying to validate it now\n");
+#endif
+            if (peer_address->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
+            {
+              GNUNET_SCHEDULER_cancel (peer_address->revalidate_task);
+              peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
+            }
+            peer_address->revalidate_task = GNUNET_SCHEDULER_add_now (&send_periodic_ping, peer_address);
+
+         }
          peer_address->timeout
            = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
-         schedule_next_ping (peer_address);
        }
       /* update traffic received amount ... */
       msize = ntohs (message->size);
@@ -5415,23 +5457,22 @@ plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
     if ((ntohs(message->type) == GNUNET_MESSAGE_TYPE_TRANSPORT_ATS) &&
        (ntohs(message->size) == (sizeof (struct GNUNET_MessageHeader) + sizeof (uint32_t))))
       {
+#if HAVE_LIBGLPK
        uint32_t value =  ntohl(*((uint32_t *) &message[1]));
        //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "GNUNET_MESSAGE_TYPE_TRANSPORT_ATS: %i \n", value);
        /* Force ressource and quality update */
-       if (value == 4)
-         {
-           ats->stat.modified_resources = GNUNET_YES;
-           ats->stat.modified_quality = GNUNET_YES;
-         }
+       if ((value == 4) && (ats != NULL))
+            ats_modify_problem_state(ats, ATS_QUALITY_COST_UPDATED);
        /* Force cost update */
-       if (value == 3)
-         ats->stat.modified_resources = GNUNET_YES;
+       if ((value == 3) && (ats != NULL))
+          ats_modify_problem_state(ats, ATS_COST_UPDATED);
        /* Force quality update */
-       if (value == 2)
-         ats->stat.modified_quality = GNUNET_YES;
+       if ((value == 2) && (ats != NULL))
+          ats_modify_problem_state(ats, ATS_QUALITY_UPDATED);
        /* Force full rebuild */
-       if (value == 1)
-         ats->stat.recreate_problem = GNUNET_YES;
+       if ((value == 1) && (ats != NULL))
+          ats_modify_problem_state(ats, ATS_MODIFIED);
+#endif
       }
     
 #if DEBUG_PING_PONG
@@ -5452,6 +5493,8 @@ plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
          break;
        case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
          handle_ping (plugin, message, peer, session, sender_address, sender_address_len);
+         if (GNUNET_YES != n->received_pong)
+           transmit_plain_ping (n);
          break;
        case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
          handle_pong (plugin, message, peer, sender_address, sender_address_len);
@@ -5481,6 +5524,44 @@ plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
   return ret;
 }
 
+
+static int
+notify_client_about_neighbour (void *cls,
+                              const GNUNET_HashCode *key,
+                              void *value)
+{
+  struct TransportClient *c = cls;
+  struct NeighbourMapEntry *n = value;
+  struct ConnectInfoMessage * cim;
+  uint32_t ats_count;
+  size_t size;
+
+  if (GNUNET_YES != n->received_pong)
+    return GNUNET_OK;
+
+  ats_count = 2;
+  size  = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
+  GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
+  cim = GNUNET_malloc (size);
+  cim->header.size = htons (size);
+  cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
+  cim->ats_count = htonl(ats_count);
+  (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
+  (&(cim->ats))[2].value = htonl (0); 
+  if (GNUNET_YES == n->received_pong)
+    {
+      (&cim->ats)[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
+      (&cim->ats)[0].value = htonl (n->distance);
+      (&cim->ats)[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
+      (&cim->ats)[1].value = htonl ((uint32_t) n->latency.rel_value);
+      cim->id = n->id;
+      transmit_to_client (c, &cim->header, GNUNET_NO);
+    }
+  GNUNET_free (cim);
+  return GNUNET_OK;
+}
+
+
 /**
  * Handle START-message.  This is the first message sent to us
  * by any client which causes us to add it to our list.
@@ -5496,10 +5577,6 @@ handle_start (void *cls,
 {
   const struct StartMessage *start;
   struct TransportClient *c;
-  struct ConnectInfoMessage * cim;
-  struct NeighbourList *n;
-  uint32_t ats_count;
-  size_t size;
 
   start = (const struct StartMessage*) message;
 #if DEBUG_TRANSPORT
@@ -5534,7 +5611,7 @@ handle_start (void *cls,
   clients = c;
   c->client = client;
   if (our_hello != NULL)
-  {
+    {
 #if DEBUG_TRANSPORT
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                   "Sending our own `%s' to new client\n", "HELLO");
@@ -5543,34 +5620,18 @@ handle_start (void *cls,
                           (const struct GNUNET_MessageHeader *) our_hello,
                           GNUNET_NO);
       /* tell new client about all existing connections */
-      ats_count = 2;
-      size  = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
-      if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
-      {
-         GNUNET_break(0);
-      }
-      cim = GNUNET_malloc (size);
-      cim->header.size = htons (size);
-      cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
-      cim->ats_count = htonl(ats_count);
-      (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
-      (&(cim->ats))[2].value = htonl (0);
-      n = neighbours;
-      while (n != NULL)
-         {
-                 if (GNUNET_YES == n->received_pong)
-                 {
-                         (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
-                         (&(cim->ats))[0].value = htonl (n->distance);
-                         (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
-                         (&(cim->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
-                         cim->id = n->id;
-                         transmit_to_client (c, &cim->header, GNUNET_NO);
-                 }
-           n = n->next;
-      }
-      GNUNET_free (cim);
-  }
+      GNUNET_CONTAINER_multihashmap_iterate (neighbours,
+                                            &notify_client_about_neighbour,
+                                            c);
+    }
+  else
+    {
+#if DEBUG_TRANSPORT_HELLO
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                 "No HELLO created yet, will transmit HELLO to client later!\n");
+#endif
+      refresh_hello ();
+    }
   GNUNET_SERVER_receive_done (client, GNUNET_OK);
 }
 
@@ -5634,7 +5695,7 @@ struct TransmitClientMessageContext
  */
 static void
 transmit_client_message (void *cls,
-                        struct NeighbourList *n)
+                        struct NeighbourMapEntry *n)
 {
   struct TransmitClientMessageContext *tcmc = cls;
   struct TransportClient *tc;
@@ -5754,7 +5815,7 @@ handle_set_quota (void *cls,
 {
   const struct QuotaSetMessage *qsm =
     (const struct QuotaSetMessage *) message;
-  struct NeighbourList *n;
+  struct NeighbourMapEntry *n;
 
   GNUNET_STATISTICS_update (stats,
                            gettext_noop ("# SET QUOTA messages received"),
@@ -5770,8 +5831,8 @@ handle_set_quota (void *cls,
                                GNUNET_NO);
       return;
     }
-#if DEBUG_TRANSPORT || 1
-  GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+#if DEBUG_TRANSPORT 
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
               "SET_QUOTA",
              (unsigned int) ntohl (qsm->quota.value__),
@@ -5787,6 +5848,10 @@ handle_set_quota (void *cls,
                 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&n->id),
                 "SET_QUOTA");
 #endif
+      GNUNET_STATISTICS_update (stats,
+                                gettext_noop ("# disconnects due to quota of 0"),
+                                1,
+                                GNUNET_NO);
       disconnect_neighbour (n, GNUNET_NO);
     }
   GNUNET_SERVER_receive_done (client, GNUNET_OK);
@@ -5806,15 +5871,18 @@ transmit_address_to_client (void *cls, const char *address)
   struct GNUNET_SERVER_TransmitContext *tc = cls;
   size_t slen;
 
-  if (NULL == address)
-    slen = 0;
+  if (NULL != address)
+    {
+      slen = strlen (address) + 1;
+      GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
+                                                 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
+    }
   else
-    slen = strlen (address) + 1;
-
-  GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
-                                             GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
-  if (NULL == address)
-    GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
+    {
+      GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
+                                                 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
+      GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
+    }
 }
 
 
@@ -5836,7 +5904,6 @@ handle_address_lookup (void *cls,
   const char *address;
   uint16_t size;
   struct GNUNET_SERVER_TransmitContext *tc;
-  struct GNUNET_TIME_Absolute timeout;
   struct GNUNET_TIME_Relative rtimeout;
   int32_t numeric;
 
@@ -5864,8 +5931,7 @@ handle_address_lookup (void *cls,
       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
       return;
     }
-  timeout = GNUNET_TIME_absolute_ntoh (alum->timeout);
-  rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
+  rtimeout = GNUNET_TIME_relative_ntoh (alum->timeout);
   numeric = ntohl (alum->numeric_only);
   lsPlugin = find_transport (nameTransport);
   if (NULL == lsPlugin)
@@ -5876,6 +5942,7 @@ handle_address_lookup (void *cls,
       GNUNET_SERVER_transmit_context_run (tc, rtimeout);
       return;
     }
+  GNUNET_SERVER_disable_receive_done_warning (client);
   tc = GNUNET_SERVER_transmit_context_create (client);
   lsPlugin->api->address_pretty_printer (lsPlugin->api->cls,
                                         nameTransport,
@@ -5885,6 +5952,198 @@ handle_address_lookup (void *cls,
                                          &transmit_address_to_client, tc);
 }
 
+/**
+ * Handle PeerAddressLookupMessage.
+ *
+ * @param cls closure (always NULL)
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_peer_address_lookup (void *cls,
+                       struct GNUNET_SERVER_Client *client,
+                       const struct GNUNET_MessageHeader *message)
+{
+  const struct PeerAddressLookupMessage *peer_address_lookup;
+  struct NeighbourMapEntry *neighbor_iterator;
+  struct ReadyList *ready_iterator;
+  struct ForeignAddressList *foreign_address_iterator;
+  struct TransportPlugin *transport_plugin;
+
+  uint16_t size;
+  struct GNUNET_SERVER_TransmitContext *tc;
+  struct GNUNET_TIME_Relative rtimeout;
+  char *addr_buf;
+
+  size = ntohs (message->size);
+  if (size < sizeof (struct PeerAddressLookupMessage))
+    {
+      GNUNET_break_op (0);
+      GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+      return;
+    }
+  peer_address_lookup = (const struct PeerAddressLookupMessage *) message;
+
+  rtimeout = GNUNET_TIME_relative_ntoh (peer_address_lookup->timeout);
+
+  neighbor_iterator = find_neighbour (&peer_address_lookup->peer);
+
+  /* Found no neighbor matching this peer id (shouldn't be possible, but...) */
+  if (neighbor_iterator == NULL)
+    {
+      GNUNET_break(0);
+      tc = GNUNET_SERVER_transmit_context_create (client);
+      GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
+                                                  GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
+      GNUNET_SERVER_transmit_context_run (tc, rtimeout);
+      return;
+    }
+
+  ready_iterator = neighbor_iterator->plugins;
+  GNUNET_SERVER_disable_receive_done_warning (client);
+  tc = GNUNET_SERVER_transmit_context_create (client);
+  while(ready_iterator != NULL)
+    {
+      foreign_address_iterator = ready_iterator->addresses;
+      while (foreign_address_iterator != NULL)
+        {
+          transport_plugin = foreign_address_iterator->ready_list->plugin;
+          if (foreign_address_iterator->addr != NULL)
+            {
+              GNUNET_asprintf (&addr_buf, "%s --- %s, %s",
+                               a2s (transport_plugin->short_name,
+                                    foreign_address_iterator->addr,
+                                    foreign_address_iterator->addrlen),
+                               (foreign_address_iterator->connected
+                                   == GNUNET_YES) ? "CONNECTED"
+                                   : "DISCONNECTED",
+                               (foreign_address_iterator->validated
+                                   == GNUNET_YES) ? "VALIDATED"
+                                   : "UNVALIDATED");
+              transmit_address_to_client(tc, addr_buf);
+              GNUNET_free (addr_buf);
+            }
+          else if (foreign_address_iterator->addrlen == 0)
+            {
+              GNUNET_asprintf (&addr_buf, "%s --- %s, %s", "<inbound>",
+                               (foreign_address_iterator->connected
+                                   == GNUNET_YES) ? "CONNECTED"
+                                   : "DISCONNECTED",
+                               (foreign_address_iterator->validated
+                                   == GNUNET_YES) ? "VALIDATED"
+                                   : "UNVALIDATED");
+              transmit_address_to_client (tc, addr_buf);
+              GNUNET_free (addr_buf);
+            }
+
+          foreign_address_iterator = foreign_address_iterator->next;
+        }
+      ready_iterator = ready_iterator->next;
+    }
+  GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
+                                              GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
+  GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
+}
+
+
+
+static int
+output_addresses (void *cls,
+                 const GNUNET_HashCode *key,
+                 void *value)
+{
+  struct GNUNET_SERVER_TransmitContext *tc = cls;
+  struct NeighbourMapEntry *neighbor_iterator = value;
+  struct ForeignAddressList *foreign_address_iterator;
+  struct TransportPlugin *transport_plugin;
+  struct ReadyList *ready_iterator;
+  char *addr_buf;
+
+  ready_iterator = neighbor_iterator->plugins;
+  while (ready_iterator != NULL)
+    {
+      foreign_address_iterator = ready_iterator->addresses;
+      while (foreign_address_iterator != NULL)
+       {
+         transport_plugin = foreign_address_iterator->ready_list->plugin;
+         if (foreign_address_iterator->addr != NULL)
+           {
+             GNUNET_asprintf (&addr_buf, "%s:%s --- %s, %s",
+                              GNUNET_i2s(&neighbor_iterator->id),
+                              a2s (transport_plugin->short_name,
+                                   foreign_address_iterator->addr,
+                                   foreign_address_iterator->addrlen),
+                              (foreign_address_iterator->connected
+                               == GNUNET_YES) ? "CONNECTED"
+                              : "DISCONNECTED",
+                              (foreign_address_iterator->validated
+                               == GNUNET_YES) ? "VALIDATED"
+                              : "UNVALIDATED");
+             transmit_address_to_client (tc, addr_buf);
+             GNUNET_free (addr_buf);
+           }
+         else if (foreign_address_iterator->addrlen == 0)
+           {
+             GNUNET_asprintf (&addr_buf, "%s:%s --- %s, %s",
+                              GNUNET_i2s (&neighbor_iterator->id),
+                              "<inbound>",
+                              (foreign_address_iterator->connected
+                               == GNUNET_YES) ? "CONNECTED"
+                              : "DISCONNECTED",
+                              (foreign_address_iterator->validated
+                               == GNUNET_YES) ? "VALIDATED"
+                              : "UNVALIDATED");
+             transmit_address_to_client (tc, addr_buf);
+             GNUNET_free (addr_buf);
+           }
+         
+         foreign_address_iterator = foreign_address_iterator->next;
+       }
+      ready_iterator = ready_iterator->next;
+    }
+  return GNUNET_OK;
+}
+
+
+/**
+ * Handle AddressIterateMessage
+ *
+ * @param cls closure (always NULL)
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_address_iterate (void *cls,
+                        struct GNUNET_SERVER_Client *client,
+                        const struct GNUNET_MessageHeader *message)
+{
+  struct GNUNET_SERVER_TransmitContext *tc;
+  uint16_t size;
+
+  size = ntohs (message->size);
+  if (size < sizeof (struct AddressIterateMessage))
+    {
+      GNUNET_break_op (0);
+      GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+      return;
+    }
+  GNUNET_SERVER_disable_receive_done_warning (client);
+  tc = GNUNET_SERVER_transmit_context_create (client);
+  GNUNET_CONTAINER_multihashmap_iterate (neighbours,
+                                        &output_addresses,
+                                        tc);
+  GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
+                                              GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
+  GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
+}
+
+
+static const struct GNUNET_MessageHeader *
+do_get_our_hello ()
+{
+  return (const struct GNUNET_MessageHeader*) our_hello;
+}
+
 
 /**
  * Setup the environment for this plugin.
@@ -5894,7 +6153,7 @@ create_environment (struct TransportPlugin *plug)
 {
   plug->env.cfg = cfg;
   plug->env.my_identity = &my_identity;
-  plug->env.our_hello = &our_hello;
+  plug->env.get_our_hello = &do_get_our_hello;
   plug->env.cls = plug;
   plug->env.receive = &plugin_env_receive;
   plug->env.notify_address = &plugin_env_notify_address;
@@ -5936,6 +6195,24 @@ start_transport (struct GNUNET_SERVER_Handle *server,
 }
 
 
+static int
+null_mq_client_pointers (void *cls,
+                        const GNUNET_HashCode *key,
+                        void *value)
+{
+  struct TransportClient *pos = cls;
+  struct NeighbourMapEntry *n = value;
+  struct MessageQueue *mq;
+
+  for (mq = n->messages_head; mq != NULL; mq = mq->next)
+    {
+      if (mq->client == pos)
+       mq->client = NULL; /* do not use anymore! */
+    }
+  return GNUNET_OK;
+}
+
+
 /**
  * Called whenever a client is disconnected.  Frees our
  * resources associated with that client.
@@ -6010,6 +6287,10 @@ client_disconnect_notification (void *cls,
       pos->message_count--;
       GNUNET_free (mqe);
     }
+  if (NULL != neighbours)
+    GNUNET_CONTAINER_multihashmap_iterate (neighbours,
+                                          &null_mq_client_pointers,
+                                          pos);
   if (prev == NULL)
     clients = pos->next;
   else
@@ -6029,6 +6310,24 @@ client_disconnect_notification (void *cls,
 }
 
 
+static int
+disconnect_all_neighbours (void *cls,
+                          const GNUNET_HashCode *key,
+                          void *value)
+{
+  struct NeighbourMapEntry *n = value;
+
+#if DEBUG_TRANSPORT
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Disconnecting peer `%4s', %s\n",
+             GNUNET_i2s(&n->id),
+             "SHUTDOWN_TASK");
+#endif
+  disconnect_neighbour (n, GNUNET_NO);
+  return GNUNET_OK;
+}
+
+
 /**
  * Function called when the service shuts down.  Unloads our plugins
  * and cancels pending validations.
@@ -6044,22 +6343,15 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
   struct CheckHelloValidatedContext *chvc;
 
   shutdown_in_progress = GNUNET_YES;
-  while (neighbours != NULL)
-    {
-#if DEBUG_TRANSPORT
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&neighbours->id),
-                 "SHUTDOWN_TASK");
-#endif
-      disconnect_neighbour (neighbours, GNUNET_NO);
-    }
+  GNUNET_CONTAINER_multihashmap_iterate (neighbours,
+                                        &disconnect_all_neighbours,
+                                        NULL);
 #if DEBUG_TRANSPORT
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Transport service is unloading plugins...\n");
 #endif
   while (NULL != (plug = plugins))
     {
-      plugins = plug->next;
       if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
        {
          GNUNET_SCHEDULER_cancel (plug->address_update_task);
@@ -6073,6 +6365,7 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
           plug->addresses = al->next;
           GNUNET_free (al);
         }
+      plugins = plug->next;
       GNUNET_free (plug);
     }
   if (my_private_key != NULL)
@@ -6085,7 +6378,16 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
   GNUNET_CONTAINER_multihashmap_destroy (validation_map);
   validation_map = NULL;
 
-  ats_shutdown(ats);
+
+  if (ats_task != GNUNET_SCHEDULER_NO_TASK)
+  {
+    GNUNET_SCHEDULER_cancel(ats_task);
+    ats_task = GNUNET_SCHEDULER_NO_TASK;
+  }
+#if HAVE_LIBGLPK
+  if (ats != NULL)
+    ats_shutdown (ats);
+#endif
 
   /* free 'chvc' data structure */
   while (NULL != (chvc = chvc_head))
@@ -6117,1312 +6419,201 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
       GNUNET_PEERINFO_disconnect (peerinfo);
       peerinfo = NULL;
     }
+  if (GNUNET_SCHEDULER_NO_TASK != hello_task)
+    {
+      GNUNET_SCHEDULER_cancel (hello_task);
+      hello_task = GNUNET_SCHEDULER_NO_TASK;
+    }
   /* Can we assume those are gone by now, or do we need to clean up
      explicitly!? */
   GNUNET_break (bl_head == NULL);
   GNUNET_break (bc_head == NULL);
+  GNUNET_CONTAINER_multihashmap_destroy (neighbours);
+  neighbours = NULL;
+}
+
+
+void ats_result_cb ()
+{
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+      "ATS Result callback\n");
 }
 
+
 #if HAVE_LIBGLPK
-static int ats_evaluate_results (int result, int solution, char * problem)
+struct AtsBuildContext
 {
-       int cont = GNUNET_NO;
-#if DEBUG_ATS || VERBOSE_ATS
-       int error_kind = GNUNET_ERROR_TYPE_DEBUG;
-#endif
-#if VERBOSE_ATS
-       error_kind = GNUNET_ERROR_TYPE_ERROR;
-#endif
+  struct ATS_mechanism * mechanisms;
+  struct ATS_peer *peers;
+  int c_peers;
+  int c_mechs;
+};
 
-       switch (result) {
-       case GNUNET_SYSERR : /* GNUNET problem, not GLPK related */
-#if DEBUG_ATS || VERBOSE_ATS
-               GNUNET_log (error_kind, "%s , GLPK solving not executed\n", problem);
-#endif
-               break;
-       case GLP_ESTOP  :    /* search terminated by application */
-#if DEBUG_ATS || VERBOSE_ATS
-               GNUNET_log (error_kind, "%s , Search terminated by application\n", problem);
-#endif
-               break;
-       case GLP_EITLIM :    /* iteration limit exceeded */
-#if DEBUG_ATS || VERBOSE_ATS
-               GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "%s Iteration limit exceeded\n", problem);
-#endif
-               break;
-       case GLP_ETMLIM :    /* time limit exceeded */
-#if DEBUG_ATS || VERBOSE_ATS
-               GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "%s Time limit exceeded\n", problem);
-#endif
-       break;
-       case GLP_ENOPFS :    /* no primal feasible solution */
-       case GLP_ENODFS :    /* no dual feasible solution */
-#if DEBUG_ATS || VERBOSE_ATS
-               GNUNET_log (error_kind, "%s No feasible solution\n", problem);
-#endif
-       break;
 
-       case GLP_EBADB  :    /* invalid basis */
-       case GLP_ESING  :    /* singular matrix */
-       case GLP_ECOND  :    /* ill-conditioned matrix */
-       case GLP_EBOUND :    /* invalid bounds */
-       case GLP_EFAIL  :    /* solver failed */
-       case GLP_EOBJLL :    /* objective lower limit reached */
-       case GLP_EOBJUL :    /* objective upper limit reached */
-       case GLP_EROOT  :    /* root LP optimum not provided */
-#if DEBUG_ATS || VERBOSE_ATS
-               GNUNET_log (error_kind, "%s Invalid Input data: %i\n", problem, result);
-#endif
-       break;
+static int
+find_and_count_addresses (void *cls,
+                         const GNUNET_HashCode *key,
+                         void *value)
+{
+  struct AtsBuildContext *abc = cls;
+  struct NeighbourMapEntry *next = value;  
+  int found_addresses = GNUNET_NO;
+  
+  struct ReadyList *r_next = next->plugins;
+  while (r_next != NULL)
+    {
+      struct ForeignAddressList * a_next = r_next->addresses;
+      while (a_next != NULL)
+        {
+         abc->c_mechs++;
+         found_addresses = GNUNET_YES;
+         a_next = a_next->next;
+        }
+      r_next = r_next->next;
+    }
+  if (found_addresses) 
+    abc->c_peers++;
+  return GNUNET_OK;
+}
 
-       case 0:
-#if DEBUG_ATS || VERBOSE_ATS
-                       GNUNET_log (error_kind, "%s Problem has been solved\n", problem);
-#endif
-       break;
-       }
 
-       switch (solution) {
-               case GLP_UNDEF:
-#if DEBUG_ATS || VERBOSE_ATS
-                       GNUNET_log (error_kind, "%s solution is undefined\n", problem);
-#endif
-                       break;
-               case GLP_OPT:
-#if DEBUG_ATS || VERBOSE_ATS
-                       GNUNET_log (error_kind, "%s solution is optimal\n", problem);
-#endif
-                       cont=GNUNET_YES;
-                       break;
-               case GLP_FEAS:
-#if DEBUG_ATS || VERBOSE_ATS
-                       GNUNET_log (error_kind, "%s solution is %s feasible, however, its optimality (or non-optimality) has not been proven, \n", problem, (0==strcmp(problem,"LP")?"":"integer"));
-#endif
-                       cont=GNUNET_YES;
-                       break;
-               case GLP_NOFEAS:
-#if DEBUG_ATS || VERBOSE_ATS
-                       GNUNET_log (error_kind, "%s problem has no %sfeasible solution\n", problem,  (0==strcmp(problem,"LP")?"":"integer "));
-#endif
-                       break;
-               case GLP_INFEAS:
-#if DEBUG_ATS || VERBOSE_ATS
-                       GNUNET_log (error_kind, "%s problem is infeasible \n", problem);
-#endif
-                       break;
-               case GLP_UNBND:
-#if DEBUG_ATS || VERBOSE_ATS
-                       GNUNET_log (error_kind, "%s problem is unbounded \n", problem);
-#endif
-               default:
-                       break;
+static int
+setup_ats_problem (void *cls,
+                  const GNUNET_HashCode *key,
+                  void *value)
+{
+  struct AtsBuildContext *abc = cls;
+  struct NeighbourMapEntry *next = value;  
+
+  int found_addresses = GNUNET_NO;
+  struct ReadyList *r_next = next->plugins;
+  while (r_next != NULL)
+    {
+      struct ForeignAddressList * a_next = r_next->addresses;
+      while (a_next != NULL)
+       {
+         if (found_addresses == GNUNET_NO)
+           {
+             abc->peers[abc->c_peers].peer = next->id;
+             abc->peers[abc->c_peers].m_head = NULL;
+             abc->peers[abc->c_peers].m_tail = NULL;
+             abc->peers[abc->c_peers].f = 1.0 / abc->c_mechs;
+           }
+         abc->mechanisms[abc->c_mechs].addr = a_next;
+         abc->mechanisms[abc->c_mechs].col_index = abc->c_mechs;
+         abc->mechanisms[abc->c_mechs].peer = &abc->peers[abc->c_peers];
+         abc->mechanisms[abc->c_mechs].next = NULL;
+         abc->mechanisms[abc->c_mechs].plugin = r_next->plugin;
+         abc->mechanisms[abc->c_mechs].ressources = a_next->ressources;
+         abc->mechanisms[abc->c_mechs].quality = a_next->quality;
+         GNUNET_CONTAINER_DLL_insert_tail(abc->peers[abc->c_peers].m_head,
+                                          abc->peers[abc->c_peers].m_tail,
+                                          &abc->mechanisms[abc->c_mechs]);
+         found_addresses = GNUNET_YES;
+         abc->c_mechs++;             
+         a_next = a_next->next;
        }
-return cont;
+      r_next = r_next->next;
+    }
+  if (found_addresses == GNUNET_YES)
+    abc->c_peers++;
+  return GNUNET_OK;
 }
 
-static void ats_solve_problem (unsigned int max_it, unsigned int  max_dur, unsigned int c_peers, unsigned int  c_mechs, struct ATS_stat *stat)
+
+static void
+create_ats_information ( struct ATS_peer **p,
+                        int * c_p,
+                        struct ATS_mechanism ** m,
+                        int * c_m )
 {
-       int result = GNUNET_SYSERR;
-       int lp_solution = GNUNET_SYSERR;
-       int mlp_solution = GNUNET_SYSERR;
+  struct AtsBuildContext abc;
 
-       // Solving simplex
-       glp_smcp opt_lp;
-       glp_init_smcp(&opt_lp);
 #if VERBOSE_ATS
-       opt_lp.msg_lev = GLP_MSG_ALL;
-#else
-       opt_lp.msg_lev = GLP_MSG_OFF;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+      "ATS requires clean address information\n");
+#endif
+  abc.c_peers = 0;
+  abc.c_mechs = 0;
+  GNUNET_CONTAINER_multihashmap_iterate (neighbours,
+                                        &find_and_count_addresses,
+                                        &abc);
+#if VERBOSE_ATS
+  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+      "Found %u peers with % u transport mechanisms\n", c_peers, c_mechs);
 #endif
 
-       // setting iteration limit
-       opt_lp.it_lim = max_it;
-       // maximum duration
-       opt_lp.tm_lim = max_dur;
+  if ( (abc.c_peers == 0) && (abc.c_mechs == 0) )
+    {
+      *p = NULL;
+      (*c_p) = 0;
+      *m = NULL;
+      (*c_m) = 0;
+      return;
+    }
 
-       if (ats->stat.recreate_problem == GNUNET_YES)
-               opt_lp.presolve = GLP_ON;
-       result = glp_simplex(ats->prob, &opt_lp);
-       lp_solution =  glp_get_status (ats->prob);
+  abc.mechanisms = GNUNET_malloc((1+abc.c_mechs) * sizeof (struct ATS_mechanism));
+  abc.peers =  GNUNET_malloc((1+abc.c_peers) * sizeof (struct ATS_peer));
+  abc.c_mechs = 1;
+  abc.c_peers = 1;
+  GNUNET_CONTAINER_multihashmap_iterate (neighbours,
+                                        &setup_ats_problem,
+                                        &abc);
+  abc.c_mechs--;
+  abc.c_peers--;
+  (*c_m) = abc.c_mechs;
+  (*c_p) = abc.c_peers;
+  (*p) = abc.peers;
+  (*m) = abc.mechanisms;
+}
 
-       if ((result == GLP_ETMLIM) || (result == GLP_EITLIM))
-       {
-               ats->stat.valid = GNUNET_NO;
-               GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ATS exceeded time or iteration limit!\n");
-               return;
-       }
 
-       if (ats_evaluate_results(result, lp_solution, "LP") == GNUNET_YES)
-       {
-                       stat->valid = GNUNET_YES;
-       }
-       else
-       {
-               ats->stat.simplex_rerun_required = GNUNET_YES;
-               opt_lp.presolve = GLP_ON;
-               result = glp_simplex(ats->prob, &opt_lp);
-               lp_solution =  glp_get_status (ats->prob);
+static void
+schedule_ats (void *cls,
+              const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct ATS_Handle *ats = (struct ATS_Handle *) cls;
+  if (ats==NULL)
+    return;
 
-               // TODO: Remove if this does not appear until release
-               GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "EXECUTED SIMPLEX WITH PRESOLVER! %i \n", lp_solution);
+  ats_task = GNUNET_SCHEDULER_NO_TASK;
+  if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
+      return;
 
-               if (ats_evaluate_results(result, lp_solution, "LP") != GNUNET_YES)
-               {
-                       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "After execution simplex with presolver: STILL INVALID!\n");
-                       char * filename;
-                       GNUNET_asprintf (&filename, "ats_mlp_p%i_m%i_%llu.mlp",ats->stat.c_peers, ats->stat.c_mechs, GNUNET_TIME_absolute_get().abs_value);
-                       glp_write_lp (ats->prob, NULL, filename);
-                       GNUNET_free (filename);
-                       stat->valid = GNUNET_NO;
-                       ats->stat.recreate_problem = GNUNET_YES;
-                       return;
-               }
-               stat->valid = GNUNET_YES;
-       }
+  if (shutdown_in_progress == GNUNET_YES)
+          return;
 
-       // Solving mlp
-       glp_iocp opt_mlp;
-       glp_init_iocp(&opt_mlp);
-       // maximum duration
-       opt_mlp.tm_lim = max_dur;
-       // output level
-#if VERBOSE_ATS
-       opt_mlp.msg_lev = GLP_MSG_ALL;
-#else
-       opt_mlp.msg_lev = GLP_MSG_OFF;
+  struct GNUNET_TIME_Relative delta =
+      GNUNET_TIME_absolute_get_difference (last_ats_execution, GNUNET_TIME_absolute_get());
+  if (delta.rel_value < ats_minimum_interval.rel_value)
+  {
+#if DEBUG_ATS
+    GNUNET_log (GNUNET_ERROR_TYPE_BULK,
+        "Minimum time between cycles not reached\n");
 #endif
+    return;
+  }
 
-       result = glp_intopt (ats->prob, &opt_mlp);
-       mlp_solution =  glp_mip_status (ats->prob);
-       stat->solution = mlp_solution;
-
-       if (ats_evaluate_results(result, mlp_solution, "MLP") == GNUNET_YES)
-       {
-               stat->valid = GNUNET_YES;
-       }
-       else
-       {
-               // TODO: Remove if this does not appear until release
-               GNUNET_log (GNUNET_ERROR_TYPE_ERROR,  "MLP solution for %i peers, %i mechs is invalid: %i\n", ats->stat.c_peers, ats->stat.c_mechs, mlp_solution);
-               stat->valid = GNUNET_NO;
-       }
-
-/*
-       int check;
-       int error = GNUNET_NO;
-       double bw;
-       struct ATS_mechanism *t = NULL;
-       for (c=1; c<= (c_peers); c++ )
-       {
-               check = GNUNET_NO;
-               t = peers[c].m_head;
-               while (t!=NULL)
-               {
-                       bw = glp_get_col_prim(prob, t->col_index);
-                       if (bw > 1.0)
-                       {
-#if VERBOSE_ATS
-                               GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[%i][%i] `%s' %s %s %f\n", c, t->col_index, GNUNET_h2s(&peers[c].peer.hashPubKey), t->plugin->short_name, glp_get_col_name(prob,t->col_index), bw);
+#if DEBUG_ATS
+  GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Running scheduled calculation\n");
 #endif
-                               if (check ==GNUNET_YES)
-                               {
-                                       glp_write_sol(prob, "invalid_solution.mlp");
-                                       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid solution, check invalid_solution.mlp");
-                                       GNUNET_STATISTICS_update (stats, "ATS invalid solutions", 1, GNUNET_NO);
-                                       error = GNUNET_YES;
-                               }
-                               if (check ==GNUNET_NO)
-                                       check = GNUNET_YES;
-                       }
-                       t = t->next;
-               }
-       }*/
-
-#if VERBOSE_ATS
-       if (glp_get_col_prim(ats->prob,2*c_mechs+1) != 1)
-       {
-       int c;
-       for (c=1; c<= available_quality_metrics; c++ )
-       {
-               GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s %f\n", glp_get_col_name(ats->prob,2*c_mechs+3+c), glp_get_col_prim(ats->prob,2*c_mechs+3+c));
-       }
-       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s %f\n", glp_get_col_name(ats->prob,2*c_mechs+1), glp_get_col_prim(ats->prob,2*c_mechs+1));
-       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s %f\n", glp_get_col_name(ats->prob,2*c_mechs+2), glp_get_col_prim(ats->prob,2*c_mechs+2));
-       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s %f\n", glp_get_col_name(ats->prob,2*c_mechs+3), glp_get_col_prim(ats->prob,2*c_mechs+3));
-       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "objective value:  %f\n", glp_mip_obj_val(ats->prob));
-       }
+#if HAVE_LIBGLPK
+  ats_calculate_bandwidth_distribution (ats);
 #endif
-}
+  last_ats_execution = GNUNET_TIME_absolute_get();
 
-static void ats_delete_problem ()
-{
-#if DEBUG_ATS
-       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Deleting problem\n");
+  ats_task = GNUNET_SCHEDULER_add_delayed (ats_regular_interval,
+                                  &schedule_ats, ats);
+}
 #endif
-       int c;
 
-       for (c=0; c< (ats->stat).c_mechs; c++)
-               GNUNET_free_non_null (ats->mechanisms[c].rc);
 
-
-       if (ats->mechanisms!=NULL)
-       {
-               GNUNET_free(ats->mechanisms);
-               ats->mechanisms = NULL;
-       }
-
-       if (ats->peers!=NULL)
-       {
-               GNUNET_free(ats->peers);
-               ats->peers = NULL;
-       }
-
-       if (ats->prob != NULL)
-       {
-               glp_delete_prob(ats->prob);
-               ats->prob = NULL;
-       }
-
-       ats->stat.begin_cr = GNUNET_SYSERR;
-       ats->stat.begin_qm = GNUNET_SYSERR;
-       ats->stat.c_mechs = 0;
-       ats->stat.c_peers = 0;
-       ats->stat.end_cr = GNUNET_SYSERR;
-       ats->stat.end_qm = GNUNET_SYSERR;
-       ats->stat.solution = GNUNET_SYSERR;
-       ats->stat.valid = GNUNET_SYSERR;
-}
-
-
-static void ats_update_problem_qm ()
-{
-       int array_index;
-       int row_index;
-       int c, c2;
-       int c_q_metrics = available_quality_metrics;
-
-       int *ja    = GNUNET_malloc ((1 + ats->stat.c_mechs*2 + 3 + available_quality_metrics) * sizeof (int));
-       double *ar = GNUNET_malloc ((1 + ats->stat.c_mechs*2 + 3 + available_quality_metrics) * sizeof (double));
-#if DEBUG_ATS
-               GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Updating problem quality metrics\n");
-#endif
-       row_index = ats->stat.begin_qm;
-
-       for (c=1; c <= c_q_metrics; c++)
-       {
-               array_index = 1;
-               double value = 1;
-#if VERBOSE_ATS
-               GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
-#endif
-
-               glp_set_row_bnds(ats->prob, row_index, GLP_FX, 0.0, 0.0);
-               for (c2=1; c2<=ats->stat.c_mechs; c2++)
-               {
-                       ja[array_index] = c2;
-
-                       GNUNET_assert (ats->mechanisms[c2].addr != NULL);
-                       GNUNET_assert (ats->mechanisms[c2].peer != NULL);
-
-                       if (qm[c-1].atis_index  == GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY)
-                       {
-                               double v0 = 0, v1 = 0, v2 = 0;
-
-                               v0 = ats->mechanisms[c2].addr->quality[c-1].values[0];
-                               if (v1 < 1) v0 = 0.1;
-                               v1 = ats->mechanisms[c2].addr->quality[c-1].values[1];
-                               if (v1 < 1) v0 = 0.1;
-                               v2 = ats->mechanisms[c2].addr->quality[c-1].values[2];
-                               if (v1 < 1) v0 = 0.1;
-                               value = 100.0 / ((v0 + 2 * v1 + 3 * v2) / 6.0);
-                               //value = 1;
-                       }
-                       if (qm[c-1].atis_index  == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
-                       {
-                               double v0 = 0, v1 = 0, v2 = 0;
-                               v0 = ats->mechanisms[c2].addr->quality[c-1].values[0];
-                               if (v0 < 1) v0 = 1;
-                               v1 = ats->mechanisms[c2].addr->quality[c-1].values[1];
-                               if (v1 < 1) v1 = 1;
-                               v2 = ats->mechanisms[c2].addr->quality[c-1].values[2];
-                               if (v2 < 1) v2 = 1;
-                               value =  (v0 + 2 * v1 + 3 * v2) / 6.0;
-                               if (value >= 1)
-                                       value =  (double) 10 / value;
-                               else
-                                       value = 10;
-                       }
-                       ar[array_index] = (ats->mechanisms[c2].peer->f) * value;
-#if VERBOSE_ATS
-                       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: %s [%i,%i]=%f \n",array_index, qm[c-1].name, row_index, ja[array_index], ar[array_index]);
-#endif
-                       array_index++;
-               }
-               ja[array_index] = ats->stat.col_qm + c - 1;
-               ar[array_index] = -1;
-
-#if VERBOSE_ATS
-               GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, row_index, ja[array_index], ar[array_index]);
-#endif
-               glp_set_mat_row (ats->prob, row_index, array_index, ja, ar);
-
-               array_index = 1;
-               row_index++;
-       }
-
-       GNUNET_free_non_null (ja);
-       GNUNET_free_non_null (ar);
-}
-
-
-static void ats_update_problem_cr ()
-{
-
-       int array_index;
-       int row_index;
-       int c, c2;
-       double ct_max, ct_min;
-
-       int *ja    = GNUNET_malloc ((1 + ats->stat.c_mechs*2 + 3 + available_quality_metrics) * sizeof (int));
-       double *ar = GNUNET_malloc ((1 + ats->stat.c_mechs*2 + 3 + available_quality_metrics) * sizeof (double));
-
-       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Updating problem quality metrics\n");
-       row_index = ats->stat.begin_cr;
-       array_index = 1;
-
-       for (c=0; c<available_ressources; c++)
-       {
-               ct_max = ressources[c].c_max;
-               ct_min = ressources[c].c_min;
-#if VERBOSE_ATS
-               GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] %f..%f\n",row_index, ct_min, ct_max);
-#endif
-               glp_set_row_bnds(ats->prob, row_index, GLP_DB, ct_min, ct_max);
-
-               for (c2=1; c2<=ats->stat.c_mechs; c2++)
-               {
-                       double value = 0;
-
-                       GNUNET_assert (ats->mechanisms[c2].addr != NULL);
-                       GNUNET_assert (ats->mechanisms[c2].peer != NULL);
-
-                       ja[array_index] = c2;
-                       value = ats->mechanisms[c2].addr->ressources[c].c;
-                       ar[array_index] = value;
-#if VERBOSE_ATS
-                       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, row_index, ja[array_index], ar[array_index]);
-#endif
-                       array_index++;
-               }
-               glp_set_mat_row (ats->prob, row_index, array_index, ja, ar);
-
-               row_index ++;
-       }
-
-
-       GNUNET_free_non_null (ja);
-       GNUNET_free_non_null (ar);
-}
-
-
-#if 0
-static void ats_update_problem_qm_TEST ()
-{
-       int row_index;
-       int c, c2;
-
-       int old_ja[ats->stat.c_mechs + 2];
-       double old_ar[ats->stat.c_mechs + 2];
-       int c_old;
-       int changed = 0;
-
-       int *ja    = GNUNET_malloc ((1 + ats->stat.c_mechs*2 + 3 + available_quality_metrics) * sizeof (int));
-       double *ar = GNUNET_malloc ((1 + ats->stat.c_mechs*2 + 3 + available_quality_metrics) * sizeof (double));
-#if DEBUG_ATS
-       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Updating problem quality metrics TEST\n");
-#endif
-       if (ats->stat.begin_qm >0)
-               row_index = ats->stat.begin_qm;
-       else
-               return;
-
-
-       for (c=0; c<available_quality_metrics; c++)
-       {
-
-               c_old = glp_get_mat_row (ats->prob, row_index, old_ja, old_ar);
-
-               glp_set_row_bnds(ats->prob, row_index, GLP_FX, 0.0, 0.0);
-
-               for (c2=1; c2<=c_old; c2++)
-               {
-                       ja[c2] = old_ja[c2];
-                       if ((changed < 3) && (c2>2) && (old_ar[c2] != -1))
-                       {
-                               ar[c2] = old_ar[c2] + 5 - changed;
-                               changed ++;
-                       }
-                       else
-                               ar[c2] = old_ar[c2];
-#if VERBOSE_ATS
-                       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: old [%i,%i]=%f  new [%i,%i]=%f\n",c2, row_index, old_ja[c2], old_ar[c2], row_index, ja[c2], ar[c2]);
-#endif
-               }
-               glp_set_mat_row (ats->prob, row_index, c_old, ja, ar);
-
-               row_index ++;
-       }
-
-       GNUNET_free_non_null (ja);
-       GNUNET_free_non_null (ar);
-}
-#endif //END: HAVE_LIBGLPK
-
-/** solve the bandwidth distribution problem
- * @param max_it maximum iterations
- * @param max_dur maximum duration in ms
- * @param D    weight for diversity
- * @param U weight for utility
- * @param R weight for relativity
- * @param v_b_min minimal bandwidth per peer
- * @param v_n_min minimum number of connections
- * @param stat result struct
- * @return GNUNET_SYSERR if glpk is not available, number of mechanisms used
- */
-static int ats_create_problem (double D, double U, double R, int v_b_min, int v_n_min, struct ATS_stat *stat)
-{
-       ats->prob = glp_create_prob();
-
-       int c;
-       int c_peers = 0;
-       int c_mechs = 0;
-
-       int c_c_ressources = available_ressources;
-       int c_q_metrics = available_quality_metrics;
-
-       double M = VERY_BIG_DOUBLE_VALUE;
-       double Q[c_q_metrics+1];
-       for (c=1; c<=c_q_metrics; c++)
-       {
-               Q[c] = 1;
-       }
-
-       struct NeighbourList *next = neighbours;
-       while (next!=NULL)
-       {
-               int found_addresses = GNUNET_NO;
-               struct ReadyList *r_next = next->plugins;
-               while (r_next != NULL)
-               {
-                       struct ForeignAddressList * a_next = r_next->addresses;
-                       while (a_next != NULL)
-                       {
-                               c_mechs++;
-                               found_addresses = GNUNET_YES;
-                               a_next = a_next->next;
-                       }
-                       r_next = r_next->next;
-               }
-               if (found_addresses) c_peers++;
-               next = next->next;
-       }
-
-       if (c_mechs==0)
-       {
-#if DEBUG_ATS
-               GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No addresses for bw distribution available\n", c_peers);
-#endif
-               stat->valid = GNUNET_NO;
-               stat->c_peers = 0;
-               stat->c_mechs = 0;
-               return GNUNET_SYSERR;
-       }
-
-       GNUNET_assert (ats->mechanisms == NULL);
-       ats->mechanisms = GNUNET_malloc((1+c_mechs) * sizeof (struct ATS_mechanism));
-       GNUNET_assert (ats->peers == NULL);
-       ats->peers =  GNUNET_malloc((1+c_peers) * sizeof (struct ATS_peer));
-
-       struct ATS_mechanism * mechanisms = ats->mechanisms;
-       struct ATS_peer * peers = ats->peers;
-
-       c_mechs = 1;
-       c_peers = 1;
-
-       next = neighbours;
-       while (next!=NULL)
-       {
-               int found_addresses = GNUNET_NO;
-               struct ReadyList *r_next = next->plugins;
-               while (r_next != NULL)
-               {
-                       struct ForeignAddressList * a_next = r_next->addresses;
-                       while (a_next != NULL)
-                       {
-                               if (found_addresses == GNUNET_NO)
-                               {
-                                       peers[c_peers].peer = next->id;
-                                       peers[c_peers].m_head = NULL;
-                                       peers[c_peers].m_tail = NULL;
-                                       peers[c_peers].f = 1.0 / c_mechs;
-                               }
-
-                               mechanisms[c_mechs].addr = a_next;
-                               mechanisms[c_mechs].col_index = c_mechs;
-                               mechanisms[c_mechs].peer = &peers[c_peers];
-                               mechanisms[c_mechs].next = NULL;
-                               mechanisms[c_mechs].plugin = r_next->plugin;
-
-                               GNUNET_CONTAINER_DLL_insert_tail(peers[c_peers].m_head, peers[c_peers].m_tail, &mechanisms[c_mechs]);
-                               found_addresses = GNUNET_YES;
-                               c_mechs++;
-
-                               a_next = a_next->next;
-                       }
-                       r_next = r_next->next;
-               }
-               if (found_addresses == GNUNET_YES)
-                       c_peers++;
-               next = next->next;
-       }
-       c_mechs--;
-       c_peers--;
-
-       if (v_n_min > c_peers)
-               v_n_min = c_peers;
-
-#if VERBOSE_ATS
-       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Creating problem with: %i peers, %i mechanisms, %i resource entries, %i quality metrics \n", c_peers, c_mechs, c_c_ressources, c_q_metrics);
-#endif
-
-       int size =  1 + 3 + 10 *c_mechs + c_peers + (c_q_metrics*c_mechs)+ c_q_metrics + c_c_ressources * c_mechs ;
-       int row_index;
-       int array_index=1;
-       int * ia = GNUNET_malloc (size * sizeof (int));
-       int * ja = GNUNET_malloc (size * sizeof (int));
-       double * ar = GNUNET_malloc(size* sizeof (double));
-
-       glp_set_prob_name(ats->prob, "gnunet ats bandwidth distribution");
-       glp_set_obj_dir(ats->prob, GLP_MAX);
-
-       /* adding columns */
-       char * name;
-       glp_add_cols(ats->prob, 2 * c_mechs);
-       /* adding b_t cols */
-       for (c=1; c <= c_mechs; c++)
-       {
-
-               GNUNET_asprintf(&name, "p_%s_b%i",GNUNET_i2s(&(mechanisms[c].peer->peer)), c);
-               glp_set_col_name(ats->prob, c, name);
-               GNUNET_free (name);
-               glp_set_col_bnds(ats->prob, c, GLP_LO, 0.0, 0.0);
-               glp_set_col_kind(ats->prob, c, GLP_CV);
-               glp_set_obj_coef(ats->prob, c, 0);
-
-       }
-       /* adding n_t cols */
-       for (c=c_mechs+1; c <= 2*c_mechs; c++)
-       {
-               GNUNET_asprintf(&name, "p_%s_n%i",GNUNET_i2s(&(mechanisms[c-c_mechs].peer->peer)),(c-c_mechs));
-               glp_set_col_name(ats->prob, c, name);
-               GNUNET_free (name);
-               glp_set_col_bnds(ats->prob, c, GLP_DB, 0.0, 1.0);
-               glp_set_col_kind(ats->prob, c, GLP_IV);
-               glp_set_obj_coef(ats->prob, c, 0);
-       }
-
-       /* feasibility constraints */
-       /* Constraint 1: one address per peer*/
-       row_index = 1;
-       glp_add_rows(ats->prob, c_peers);
-       for (c=1; c<=c_peers; c++)
-       {
-#if VERBOSE_ATS
-               GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
-#endif
-               glp_set_row_bnds(ats->prob, row_index, GLP_FX, 1.0, 1.0);
-
-               struct ATS_mechanism *m = peers[c].m_head;
-               while (m!=NULL)
-               {
-                       ia[array_index] = row_index;
-                       ja[array_index] = (c_mechs + m->col_index);
-                       ar[array_index] = 1;
-#if VERBOSE_ATS
-                       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
-#endif
-                       array_index++;
-                       m = m->next;
-               }
-               row_index++;
-       }
-
-       /* Constraint 2: only active mechanism gets bandwidth assigned */
-       glp_add_rows(ats->prob, c_mechs);
-       for (c=1; c<=c_mechs; c++)
-       {
-               /* b_t - n_t * M <= 0 */
-#if VERBOSE_ATS
-               GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
-#endif
-               glp_set_row_bnds(ats->prob, row_index, GLP_UP, 0.0, 0.0);
-
-               ia[array_index] = row_index;
-               ja[array_index] = mechanisms[c].col_index;
-               ar[array_index] = 1;
-#if VERBOSE_ATS
-               GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
-#endif
-               array_index++;
-               ia[array_index] = row_index;
-               ja[array_index] = c_mechs + mechanisms[c].col_index;
-               ar[array_index] = -M;
-#if VERBOSE_ATS
-               GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
-#endif
-               array_index++;
-               row_index ++;
-       }
-
-       /* Constraint 3: minimum bandwidth*/
-       glp_add_rows(ats->prob, c_mechs);
-       for (c=1; c<=c_mechs; c++)
-       {
-               /* b_t - n_t * b_min <= 0 */
-#if VERBOSE_ATS
-               GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
-#endif
-               glp_set_row_bnds(ats->prob, row_index, GLP_LO, 0.0, 0.0);
-
-               ia[array_index] = row_index;
-               ja[array_index] = mechanisms[c].col_index;
-               ar[array_index] = 1;
-#if VERBOSE_ATS
-               GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
-#endif
-               array_index++;
-               ia[array_index] = row_index;
-               ja[array_index] = c_mechs + mechanisms[c].col_index;
-               ar[array_index] = -v_b_min;
-#if VERBOSE_ATS
-               GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
-#endif
-               array_index++;
-               row_index ++;
-       }
-       int c2;
-       /* Constraint 4: max ressource capacity */
-       /* V cr: bt * ct_r <= cr_max
-        * */
-       glp_add_rows(ats->prob, available_ressources);
-       double ct_max = VERY_BIG_DOUBLE_VALUE;
-       double ct_min = 0.0;
-
-       stat->begin_cr = array_index;
-
-       for (c=0; c<available_ressources; c++)
-       {
-               ct_max = ressources[c].c_max;
-               ct_min = ressources[c].c_min;
-#if VERBOSE_ATS
-               GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] %f..%f\n",row_index, ct_min, ct_max);
-#endif
-               glp_set_row_bnds(ats->prob, row_index, GLP_DB, ct_min, ct_max);
-
-               for (c2=1; c2<=c_mechs; c2++)
-               {
-                       double value = 0;
-                       ia[array_index] = row_index;
-                       ja[array_index] = c2;
-                       value = mechanisms[c2].addr->ressources[c].c;
-                       ar[array_index] = value;
-#if VERBOSE_ATS
-                       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
-#endif
-                       array_index++;
-               }
-               row_index ++;
-       }
-       stat->end_cr = array_index--;
-
-       /* Constraint 5: min number of connections*/
-       glp_add_rows(ats->prob, 1);
-       for (c=1; c<=c_mechs; c++)
-       {
-               // b_t - n_t * b_min >= 0
-#if VERBOSE_ATS
-               GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
-#endif
-               glp_set_row_bnds(ats->prob, row_index, GLP_LO, v_n_min, 0.0);
-
-               ia[array_index] = row_index;
-               ja[array_index] = c_mechs + mechanisms[c].col_index;
-               ar[array_index] = 1;
-#if VERBOSE_ATS
-               GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
-#endif
-               array_index++;
-       }
-       row_index ++;
-
-       // optimisation constraints
-
-       // adding columns
-
-       // Constraint 6: optimize for diversity
-       int col_d;
-       col_d = glp_add_cols(ats->prob, 1);
-       stat->col_d = col_d;
-       //GNUNET_assert (col_d == (2*c_mechs) + 1);
-       glp_set_col_name(ats->prob, col_d, "d");
-       glp_set_obj_coef(ats->prob, col_d, D);
-       glp_set_col_bnds(ats->prob, col_d, GLP_LO, 0.0, 0.0);
-       glp_add_rows(ats->prob, 1);
-#if VERBOSE_ATS
-       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
-#endif
-       glp_set_row_bnds(ats->prob, row_index, GLP_FX, 0.0, 0.0);
-       for (c=1; c<=c_mechs; c++)
-       {
-               ia[array_index] = row_index;
-               ja[array_index] = c_mechs + mechanisms[c].col_index;
-               ar[array_index] = 1;
-#if VERBOSE_ATS
-               GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
-#endif
-               array_index++;
-       }
-       ia[array_index] = row_index;
-       ja[array_index] = col_d;
-       ar[array_index] = -1;
-#if VERBOSE_ATS
-       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
-#endif
-       array_index++;
-       row_index ++;
-
-
-       // Constraint 7: optimize for quality
-       int col_qm;
-       col_qm = glp_add_cols(ats->prob, c_q_metrics);
-       stat->col_qm = col_qm;
-       //GNUNET_assert (col_qm == (2*c_mechs) + 3 + 1);
-       for (c=0; c< c_q_metrics; c++)
-       {
-               GNUNET_asprintf(&name, "Q_%s",qm[c].name);
-               glp_set_col_name(ats->prob, col_qm + c, name);
-               glp_set_col_bnds(ats->prob, col_qm + c, GLP_LO, 0.0, 0.0);
-               GNUNET_free (name);
-               glp_set_obj_coef(ats->prob, col_qm + c, Q[c]);
-       }
-    glp_add_rows(ats->prob, available_quality_metrics);
-       stat->begin_qm = row_index;
-       for (c=1; c <= c_q_metrics; c++)
-       {
-#if VERBOSE_ATS
-               GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
-#endif
-               double value = 1;
-               glp_set_row_bnds(ats->prob, row_index, GLP_FX, 0.0, 0.0);
-               for (c2=1; c2<=c_mechs; c2++)
-               {
-
-                       ia[array_index] = row_index;
-                       ja[array_index] = c2;
-                       if (qm[c-1].atis_index  == GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY)
-                       {
-                               double v0 = 0, v1 = 0, v2 = 0;
-                               v0 = mechanisms[c2].addr->quality[c-1].values[0];
-                               if (v1 < 1) v0 = 0.1;
-                               v1 = mechanisms[c2].addr->quality[c-1].values[1];
-                               if (v1 < 1) v0 = 0.1;
-                               v2 = mechanisms[c2].addr->quality[c-1].values[2];
-                               if (v1 < 1) v0 = 0.1;
-                               value = 100.0 / ((v0 + 2 * v1 + 3 * v2) / 6.0);
-                               value = 1;
-                       }
-                       if (qm[c-1].atis_index  == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
-                       {
-                               double v0 = 0, v1 = 0, v2 = 0;
-                               v0 = mechanisms[c2].addr->quality[c-1].values[0];
-                               if (v0 < 1) v0 = 1;
-                               v1 = mechanisms[c2].addr->quality[c-1].values[1];
-                               if (v1 < 1) v1 = 1;
-                               v2 = mechanisms[c2].addr->quality[c-1].values[2];
-                               if (v2 < 1) v2 = 1;
-                               value =  (v0 + 2 * v1 + 3 * v2) / 6.0;
-                               if (value >= 1)
-                                       value =  (double) 10 / value;
-                               else
-                                       value = 10;
-                       }
-                       ar[array_index] = (mechanisms[c2].peer->f) * value ;
-#if VERBOSE_ATS
-                       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: %s [%i,%i]=%f \n",array_index, qm[c-1].name, ia[array_index], ja[array_index], ar[array_index]);
-#endif
-                       array_index++;
-               }
-
-               ia[array_index] = row_index;
-               ja[array_index] = col_qm + c - 1;
-               ar[array_index] = -1;
-#if VERBOSE_ATS
-               GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
-#endif
-               array_index++;
-               row_index++;
-       }
-       stat->end_qm = row_index-1;
-
-       // Constraint 8: optimize bandwidth utility
-       int col_u;
-       col_u = glp_add_cols(ats->prob, 1);
-       stat->col_u = col_u;
-       //GNUNET_assert (col_u == (2*c_mechs) + 2);
-       glp_set_col_name(ats->prob, col_u, "u");
-       glp_set_obj_coef(ats->prob, col_u, U);
-       glp_set_col_bnds(ats->prob, col_u, GLP_LO, 0.0, 0.0);
-       glp_add_rows(ats->prob, 1);
-#if VERBOSE_ATS
-       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
-#endif
-       glp_set_row_bnds(ats->prob, row_index, GLP_FX, 0.0, 0.0);
-       for (c=1; c<=c_mechs; c++)
-       {
-               ia[array_index] = row_index;
-               ja[array_index] = c;
-               ar[array_index] = mechanisms[c].peer->f;
-#if VERBOSE_ATS
-               GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
-#endif
-               array_index++;
-       }
-       ia[array_index] = row_index;
-       ja[array_index] = col_u;
-       ar[array_index] = -1;
-#if VERBOSE_ATS
-       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
-#endif
-
-       array_index++;
-       row_index ++;
-
-       // Constraint 9: optimize relativity
-       int col_r;
-       col_r = glp_add_cols(ats->prob, 1);
-       stat->col_r = col_r;
-       //GNUNET_assert (col_r == (2*c_mechs) + 3);
-       glp_set_col_name(ats->prob, col_r, "r");
-       glp_set_obj_coef(ats->prob, col_r, R);
-       glp_set_col_bnds(ats->prob, col_r, GLP_LO, 0.0, 0.0);
-       glp_add_rows(ats->prob, c_peers);
-       for (c=1; c<=c_peers; c++)
-       {
-               glp_set_row_bnds(ats->prob, row_index, GLP_LO, 0.0, 0.0);
-
-               struct ATS_mechanism *m = peers[c].m_head;
-               while (m!=NULL)
-               {
-                       ia[array_index] = row_index;
-                       ja[array_index] = m->col_index;
-                       ar[array_index] = 1 / mechanisms[c].peer->f;
-#if VERBOSE_ATS
-                       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
-#endif
-                       array_index++;
-                       m = m->next;
-               }
-               ia[array_index] = row_index;
-               ja[array_index] = col_r;
-               ar[array_index] = -1;
-#if VERBOSE_ATS
-               GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
-#endif
-               array_index++;
-
-               row_index++;
-       }
-
-       /* Loading the matrix */
-       glp_load_matrix(ats->prob, array_index-1, ia, ja, ar);
-
-       stat->c_mechs = c_mechs;
-       stat->c_peers = c_peers;
-       stat->solution = 0;
-       stat->valid = GNUNET_YES;
-
-       /* clean up */
-
-       GNUNET_free (ja);
-       GNUNET_free (ia);
-       GNUNET_free (ar);
-
-       return GNUNET_OK;
-
-}
-
-void ats_notify_ats_data (
-               const struct GNUNET_PeerIdentity *peer,
-               const struct GNUNET_TRANSPORT_ATS_Information *ats_data)
-{
-#if DEBUG_ATS
-       GNUNET_log (GNUNET_ERROR_TYPE_BULK, "ATS_notify_ats_data: %s\n",GNUNET_i2s(peer));
-#endif
-       if (shutdown_in_progress == GNUNET_NO)
-               ats_calculate_bandwidth_distribution();
-}
-#endif //END: HAVE_LIBGLPK
-
-static void
-ats_calculate_bandwidth_distribution ()
-{
-#if HAVE_LIBGLPK
-
-       struct GNUNET_TIME_Absolute start;
-       struct GNUNET_TIME_Relative creation;
-       struct GNUNET_TIME_Relative solving;
-       char *text = "unmodified";
-
-       struct GNUNET_TIME_Relative delta = GNUNET_TIME_absolute_get_difference (ats->last, GNUNET_TIME_absolute_get());
-       if (delta.rel_value < ats->min_delta.rel_value)
-       {
-#if DEBUG_ATS
-               GNUNET_log (GNUNET_ERROR_TYPE_BULK, "Minimum time between cycles not reached\n");
-#endif
-               return;
-       }
-
-       if (shutdown_in_progress == GNUNET_YES)
-       {
-#if DEBUG_ATS
-               GNUNET_log (GNUNET_ERROR_TYPE_BULK, "Transport service is shutting down\n");
-#endif
-               return;
-       }
-
-       int dur = 500;
-       if (INT_MAX < ats->max_exec_duration.rel_value)
-               dur = INT_MAX;
-       else
-               dur = (int) ats->max_exec_duration.rel_value;
-
-       ats->stat.simplex_rerun_required = GNUNET_NO;
-       start = GNUNET_TIME_absolute_get();
-       if ((ats->stat.recreate_problem == GNUNET_YES) || (ats->prob==NULL) || (ats->stat.valid == GNUNET_NO))
-       {
-               text = "new";
-               ats->stat.recreate_problem = GNUNET_YES;
-               ats_delete_problem ();
-               ats_create_problem (ats->D, ats->U, ats->R, ats->v_b_min, ats->v_n_min, &ats->stat);
-#if DEBUG_ATS
-               GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peers/Addresses were modified... new problem: %i peer, %i mechs\n", ats->stat.c_peers, ats->stat.c_mechs);
-#endif
-       }
-
-       else if ((ats->stat.recreate_problem == GNUNET_NO) && (ats->stat.modified_resources == GNUNET_YES) && (ats->stat.valid == GNUNET_YES))
-       {
-               text = "modified resources";
-               ats_update_problem_cr();
-       }
-       else if ((ats->stat.recreate_problem == GNUNET_NO) && (ats->stat.modified_quality == GNUNET_YES) && (ats->stat.valid == GNUNET_YES))
-       {
-               text = "modified quality";
-               ats_update_problem_qm();
-               //ats_update_problem_qm_TEST ();
-
-       }
-#if DEBUG_ATS
-       else GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Problem is unmodified\n");
-#endif
-
-       creation = GNUNET_TIME_absolute_get_difference(start,GNUNET_TIME_absolute_get());
-       start = GNUNET_TIME_absolute_get();
-
-       ats->stat.solution = GLP_UNDEF;
-       if (ats->stat.valid == GNUNET_YES)
-       {
-               ats_solve_problem(ats->max_iterations, ats->max_exec_duration.rel_value, ats->stat.c_peers, ats->stat.c_mechs, &ats->stat);
-       }
-       solving = GNUNET_TIME_absolute_get_difference(start,GNUNET_TIME_absolute_get());
-
-       if (ats->stat.valid == GNUNET_YES)
-       {
-               int msg_type = GNUNET_ERROR_TYPE_DEBUG;
-#if DEBUG_ATS
-               msg_type = GNUNET_ERROR_TYPE_ERROR;
-#endif
-               GNUNET_log (msg_type, "MLP %s: creation time: %llu, execution time: %llu, %i mechanisms, simplex rerun: %s, solution %s\n",
-                               text, creation.rel_value, solving.rel_value,
-                               ats->stat.c_mechs,
-                               (ats->stat.simplex_rerun_required == GNUNET_NO) ? "NO" : "YES", (ats->stat.solution == 5) ? "OPTIMAL" : "INVALID");
-               ats->successful_executions ++;
-               GNUNET_STATISTICS_set (stats, "# ATS successful executions", ats->successful_executions, GNUNET_NO);
-
-               if ((ats->stat.recreate_problem == GNUNET_YES) || (ats->prob==NULL))
-                       GNUNET_STATISTICS_set (stats, "ATS state",ATS_NEW, GNUNET_NO);
-               else if ((ats->stat.modified_resources == GNUNET_YES) &&
-                               (ats->stat.modified_quality == GNUNET_NO))
-                       GNUNET_STATISTICS_set (stats, "ATS state", ATS_C_UPDATED, GNUNET_NO);
-               else if ((ats->stat.modified_resources == GNUNET_NO) &&
-                               (ats->stat.modified_quality == GNUNET_YES) &&
-                               (ats->stat.simplex_rerun_required == GNUNET_NO))
-                       GNUNET_STATISTICS_set (stats, "ATS state", ATS_Q_UPDATED, GNUNET_NO);
-               else if ((ats->stat.modified_resources == GNUNET_YES) &&
-                               (ats->stat.modified_quality == GNUNET_YES) &&
-                               (ats->stat.simplex_rerun_required == GNUNET_NO))
-                       GNUNET_STATISTICS_set (stats, "ATS state", ATS_QC_UPDATED, GNUNET_NO);
-               else if (ats->stat.simplex_rerun_required == GNUNET_NO)
-                       GNUNET_STATISTICS_set (stats, "ATS state", ATS_UNMODIFIED, GNUNET_NO);
-       }
-       else
-       {
-               if (ats->stat.c_peers != 0)
-               {
-                       ats->invalid_executions ++;
-                       GNUNET_STATISTICS_set (stats, "# ATS invalid executions", ats->invalid_executions, GNUNET_NO);
-               }
-               else
-               {
-                       GNUNET_STATISTICS_set (stats, "# ATS successful executions", ats->successful_executions, GNUNET_NO);
-               }
-       }
-
-       GNUNET_STATISTICS_set (stats, "ATS duration", solving.rel_value + creation.rel_value, GNUNET_NO);
-       GNUNET_STATISTICS_set (stats, "ATS mechanisms", ats->stat.c_mechs, GNUNET_NO);
-       GNUNET_STATISTICS_set (stats, "ATS peers", ats->stat.c_peers, GNUNET_NO);
-       GNUNET_STATISTICS_set (stats, "ATS solution", ats->stat.solution, GNUNET_NO);
-       GNUNET_STATISTICS_set (stats, "ATS timestamp", start.abs_value, GNUNET_NO);
-
-       if ((ats->save_mlp == GNUNET_YES) && (ats->stat.c_mechs >= ats->dump_min_peers) && (ats->stat.c_mechs >= ats->dump_min_addr))
-       {
-               char * filename;
-               if (ats->dump_overwrite == GNUNET_NO)
-               {
-                       GNUNET_asprintf (&filename, "ats_mlp_p%i_m%i_%s_%llu.mlp",
-                       ats->stat.c_peers, ats->stat.c_mechs, text, GNUNET_TIME_absolute_get().abs_value);
-                       glp_write_lp (ats->prob, NULL, filename);
-               }
-               else
-               {
-                       GNUNET_asprintf (&filename, "ats_mlp_p%i_m%i.mlp",
-                       ats->stat.c_peers, ats->stat.c_mechs );
-                       glp_write_lp (ats->prob, NULL, filename);
-               }
-               GNUNET_free (filename);
-       }
-       if ((ats->save_solution == GNUNET_YES) && (ats->stat.c_mechs >= ats->dump_min_peers) && (ats->stat.c_mechs >= ats->dump_min_addr))
-       {
-               char * filename;
-               if (ats->dump_overwrite == GNUNET_NO)
-               {
-                       GNUNET_asprintf (&filename, "ats_mlp_p%i_m%i_%s_%llu.sol",
-                       ats->stat.c_peers, ats->stat.c_mechs, text, GNUNET_TIME_absolute_get().abs_value);
-                       glp_print_sol (ats->prob, filename);
-               }
-               else
-               {
-                       GNUNET_asprintf (&filename, "ats_mlp_p%i_m%i.sol",
-                       ats->stat.c_peers, ats->stat.c_mechs);
-                       glp_print_sol (ats->prob, filename);
-               }
-               GNUNET_free (filename);
-       }
-
-       ats->last = GNUNET_TIME_absolute_get();
-       ats->stat.recreate_problem = GNUNET_NO;
-       ats->stat.modified_resources = GNUNET_NO;
-       ats->stat.modified_quality = GNUNET_NO;
-#endif
-}
-
-static void
-ats_schedule_calculation (void *cls,
-                         const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
-       struct ATS_info *ats = (struct ATS_info *) cls;
-       if (ats==NULL) return;
-
-       ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
-       if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
-           return;
-
-       if (shutdown_in_progress == GNUNET_YES)
-               return;
-
-#if DEBUG_ATS
-       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Running scheduled calculation\n");
-#endif
-
-       ats_calculate_bandwidth_distribution (ats);
-
-       ats->ats_task = GNUNET_SCHEDULER_add_delayed (ats->exec_interval,
-                                       &ats_schedule_calculation, ats);
-}
-
-void ats_init ()
-{
-       int c = 0;
-       unsigned long long  value;
-       char * section;
-
-       ats = GNUNET_malloc(sizeof (struct ATS_info));
-
-       ats->min_delta = ATS_MIN_INTERVAL;
-       ats->exec_interval = ATS_EXEC_INTERVAL;
-       ats->max_exec_duration = ATS_MAX_EXEC_DURATION;
-       ats->max_iterations = ATS_MAX_ITERATIONS;
-       ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
-
-#if !HAVE_LIBGLPK
-       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "GLPK not installed, ATS not active\n");
-       return;
-#endif
-
-       ats->D = 1.0;
-       ats->U = 1.0;
-       ats->R = 1.0;
-       ats->v_b_min = 64000;
-       ats->v_n_min = 10;
-       ats->dump_min_peers = 1;
-       ats->dump_min_addr = 1;
-       ats->dump_overwrite = GNUNET_NO;
-       ats->mechanisms = NULL;
-       ats->peers = NULL;
-       ats->successful_executions = 0;
-       ats->invalid_executions = 0;
-
-#if HAVE_LIBGLPK
-       ats->prob = NULL;
-#endif
-
-       /* loading cost ressources */
-       for (c=0; c<available_ressources; c++)
-       {
-               GNUNET_asprintf(&section,"%s_UP",ressources[c].cfg_param);
-               if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
-               {
-                       if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg, "transport",section, &value))
-                       {
-#if DEBUG_ATS
-                               GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found ressource cost: [%s] = %llu\n", section, value);
-#endif
-                               ressources[c].c_max = value;
-                       }
-               }
-               GNUNET_free (section);
-               GNUNET_asprintf(&section,"%s_DOWN",ressources[c].cfg_param);
-               if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
-               {
-                       if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg, "transport",section, &value))
-                       {
-#if DEBUG_ATS
-                               GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found ressource cost: [%s] = %llu\n", section, value);
-#endif
-                               ressources[c].c_min = value;
-                       }
-               }
-               GNUNET_free (section);
-       }
-
-       if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_MLP"))
-               ats->save_mlp = GNUNET_CONFIGURATION_get_value_yesno (cfg, "transport","DUMP_MLP");
-
-       if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_SOLUTION"))
-               ats->save_solution = GNUNET_CONFIGURATION_get_value_yesno (cfg, "transport","DUMP_SOLUTION");
-       if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_OVERWRITE"))
-               ats->dump_overwrite = GNUNET_CONFIGURATION_get_value_yesno (cfg, "transport","DUMP_OVERWRITE");
-       if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_MIN_PEERS"))
-       {
-               GNUNET_CONFIGURATION_get_value_number(cfg, "transport","DUMP_MIN_PEERS", &value);
-               ats->dump_min_peers= value;
-       }
-       if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_MIN_ADDRS"))
-       {
-               GNUNET_CONFIGURATION_get_value_number(cfg, "transport","DUMP_MIN_ADDRS", &value);
-               ats->dump_min_addr= value;
-       }
-       if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_OVERWRITE"))
-       {
-               GNUNET_CONFIGURATION_get_value_number(cfg, "transport","DUMP_OVERWRITE", &value);
-               ats->min_delta.rel_value = value;
-       }
-
-       if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "ATS_MIN_INTERVAL"))
-       {
-               GNUNET_CONFIGURATION_get_value_number(cfg, "transport","ATS_MIN_INTERVAL", &value);
-               ats->min_delta.rel_value = value;
-       }
-
-       if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "ATS_EXEC_INTERVAL"))
-       {
-               GNUNET_CONFIGURATION_get_value_number(cfg, "transport","ATS_EXEC_INTERVAL", &value);
-               ats->exec_interval.rel_value = value;
-       }
-       if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "ATS_MIN_INTERVAL"))
-       {
-               GNUNET_CONFIGURATION_get_value_number(cfg, "transport","ATS_MIN_INTERVAL", &value);
-               ats->min_delta.rel_value = value;
-       }
-
-       ats->ats_task = GNUNET_SCHEDULER_add_now(&ats_schedule_calculation, ats);
-}
-
-
-static void ats_shutdown ()
-{
-#if DEBUG_ATS
-       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_destroy\n");
-#endif
-       if (ats->ats_task != GNUNET_SCHEDULER_NO_TASK)
-               GNUNET_SCHEDULER_cancel(ats->ats_task);
-       ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
-
-#if HAVE_LIBGLPK
-       ats_delete_problem ();
-       glp_free_env();
-#endif
-       GNUNET_free (ats);
-}
-
-
-void ats_notify_peer_connect (
-               const struct GNUNET_PeerIdentity *peer,
-               const struct GNUNET_TRANSPORT_ATS_Information *ats_data, int ats_count)
-{
-#if DEBUG_ATS
-       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_notify_peer_connect: %s\n",GNUNET_i2s(peer));
-#endif
-       //update_addr_ats();
-       ats->stat.recreate_problem = GNUNET_YES;
-       ats_calculate_bandwidth_distribution(ats);
-}
-
-void ats_notify_peer_disconnect (
-               const struct GNUNET_PeerIdentity *peer)
-{
-#if DEBUG_ATS
-       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_notify_peer_disconnect: %s\n",GNUNET_i2s(peer));
-#endif
-       ats->stat.recreate_problem = GNUNET_YES;
-       ats_calculate_bandwidth_distribution (ats);
-}
-
-struct ForeignAddressList * ats_get_preferred_address (
-               struct NeighbourList *n)
-{
-#if DEBUG_ATS
-       //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "ats_get_prefered_transport for peer: %s\n",GNUNET_i2s(&n->id));
-#endif
-       struct ReadyList *next = n->plugins;
-       while (next != NULL)
-       {
-#if DEBUG_ATS
-               //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "plugin: %s %i\n",next->plugin->short_name,strcmp(next->plugin->short_name,"unix"));
-#endif
-               next = next->next;
-       }
-       return find_ready_address(n);
-}
+struct ForeignAddressList * get_preferred_ats_address (
+               struct NeighbourMapEntry *n)
+{
+  // TODO get ATS prefered address
+  return find_ready_address(n);
+}
 
 /**
  * Initiate transport service.
@@ -7450,6 +6641,12 @@ run (void *cls,
     {&handle_address_lookup, NULL,
      GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
      0},
+    {&handle_peer_address_lookup, NULL,
+     GNUNET_MESSAGE_TYPE_TRANSPORT_PEER_ADDRESS_LOOKUP,
+     0},
+    {&handle_address_iterate, NULL,
+     GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE,
+     0},
     {&handle_blacklist_init, NULL,
      GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT, sizeof (struct GNUNET_MessageHeader)},
     {&handle_blacklist_reply, NULL,
@@ -7466,6 +6663,7 @@ run (void *cls,
   cfg = c;
   stats = GNUNET_STATISTICS_create ("transport", cfg);
   validation_map = GNUNET_CONTAINER_multihashmap_create (64);
+  neighbours = GNUNET_CONTAINER_multihashmap_create (256);
   /* parse configuration */
   if ((GNUNET_OK !=
        GNUNET_CONFIGURATION_get_value_number (c,
@@ -7488,6 +6686,8 @@ run (void *cls,
        }
       GNUNET_CONTAINER_multihashmap_destroy (validation_map);
       validation_map = NULL;
+      GNUNET_CONTAINER_multihashmap_destroy (neighbours);
+      neighbours = NULL;
       return;
     }
 
@@ -7505,6 +6705,8 @@ run (void *cls,
        }
       GNUNET_CONTAINER_multihashmap_destroy (validation_map);
       validation_map = NULL;
+      GNUNET_CONTAINER_multihashmap_destroy (neighbours);
+      neighbours = NULL;
       GNUNET_free (keyfile);
       return;
     }
@@ -7523,6 +6725,8 @@ run (void *cls,
        }
       GNUNET_CONTAINER_multihashmap_destroy (validation_map);
       validation_map = NULL;
+      GNUNET_CONTAINER_multihashmap_destroy (neighbours);
+      neighbours = NULL;
       return;
     }
   GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
@@ -7553,10 +6757,85 @@ run (void *cls,
   if (no_transports)
     refresh_hello ();
 
-  ats_init();
+  /* Initializing ATS */
+  int co;
+  char * section;
+  unsigned long long  value;
+#if HAVE_LIBGLPK
+  double D = 1.0;
+  double U = 1.0;
+  double R = 1.0;
+  int v_b_min = 64000;
+  int v_n_min = 5;
+#endif
+
+  ats_minimum_interval = ATS_MIN_INTERVAL;
+  ats_regular_interval = ATS_EXEC_INTERVAL;
+
+  /* loading cost ressources */
+  for (co=0; co<available_ressources; co++)
+  {
+    GNUNET_asprintf(&section,"%s_UP",ressources[co].cfg_param);
+    if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
+    {
+      if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg,
+          "transport",
+          section,
+          &value))
+      {
+#if DEBUG_ATS
+              GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "Found ressource cost: [%s] = %llu\n",
+                  section, value);
+#endif
+              ressources[co].c_max = value;
+      }
+    }
+    GNUNET_free (section);
+    GNUNET_asprintf(&section,"%s_DOWN",ressources[co].cfg_param);
+    if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
+    {
+      if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg,
+          "transport",
+          section,
+          &value))
+      {
+#if DEBUG_ATS
+              GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "Found ressource cost: [%s] = %llu\n",
+                  section, value);
+#endif
+              ressources[co].c_min = value;
+      }
+    }
+    GNUNET_free (section);
+  }
+#if HAVE_LIBGLPK
+  ats = ats_init (D, U, R, v_b_min, v_n_min,
+                  ATS_MAX_ITERATIONS, ATS_MAX_EXEC_DURATION,
+                  &create_ats_information,
+                  ats_result_cb);
+  ats_set_logging_options (ats,
+                          stats,
+                          cfg);
+  GNUNET_break (GNUNET_OK ==
+               GNUNET_CONFIGURATION_get_value_time (cfg,
+                                                    "transport",
+                                                    "ATS_EXEC_INTERVAL", 
+                                                    &ats_regular_interval));
+  GNUNET_break (GNUNET_OK ==
+               GNUNET_CONFIGURATION_get_value_time (cfg,
+                                                    "transport",
+                                                    "ATS_MIN_INTERVAL", 
+                                                    &ats_minimum_interval));
+  if (ats != NULL)
+    ats_task = GNUNET_SCHEDULER_add_now (&schedule_ats, ats);
+#endif
+
 
 #if DEBUG_TRANSPORT
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, 
+             _("Transport service ready.\n"));
 #endif
   /* If we have a blacklist file, read from it */
   read_blacklist_file(cfg);