the new formulation including feasibility constraints
[oweals/gnunet.git] / src / transport / gnunet-service-transport.c
index 44d2ff72600d56f0f620def9b631808db81ad6e8..839e3fd38f7034a22dd132eabd6efa39c6680578 100644 (file)
@@ -4,7 +4,7 @@
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 2, or (at your
+     by the Free Software Foundation; either version 3, or (at your
      option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
 #include "gnunet_protocols.h"
 #include "gnunet_service_lib.h"
 #include "gnunet_signatures.h"
-#include "plugin_transport.h"
+#include "gnunet_transport_plugin.h"
 #include "transport.h"
+#if HAVE_LIBGLPK
+#include <glpk.h>
+#endif
 
 #define DEBUG_BLACKLIST GNUNET_NO
 
 #define DEBUG_PING_PONG GNUNET_NO
 
-#define SIGN_USELESS GNUNET_NO
+#define DEBUG_TRANSPORT_HELLO GNUNET_NO
+
+#define DEBUG_ATS GNUNET_NO
+#define VERBOSE_ATS GNUNET_NO
 
 /**
  * Should we do some additional checks (to validate behavior
  * How many messages can we have pending for a given client process
  * before we start to drop incoming messages?  We typically should
  * have only one client and so this would be the primary buffer for
- * messages, so the number should be chosen rather generously.
 * messages, so the number should be chosen rather generously.
  *
  * The expectation here is that most of the time the queue is large
- * enough so that a drop is virtually never required.
+ * enough so that a drop is virtually never required.  Note that
+ * this value must be about as large as 'TOTAL_MSGS' in the
+ * 'test_transport_api_reliability.c', otherwise that testcase may
+ * fail.
  */
-#define MAX_PENDING 128
+#define MAX_PENDING (128 * 1024)
 
 /**
  * Size of the per-transport blacklist hash maps.
@@ -75,8 +84,8 @@
 #define MAX_CONNECT_RETRY 3
 
 /**
- * Limit on the number of ready-to-run tasks when validating 
- * HELLOs.  If more tasks are ready to run, we will drop 
+ * Limit on the number of ready-to-run tasks when validating
+ * HELLOs.  If more tasks are ready to run, we will drop
  * HELLOs instead of validating them.
  */
 #define MAX_HELLO_LOAD 4
  */
 #define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
 
+/**
+ * How long is a PONG signature valid?  We'll recycle a signature until
+ * 1/4 of this time is remaining.  PONGs should expire so that if our
+ * external addresses change an adversary cannot replay them indefinitely.
+ * OTOH, we don't want to spend too much time generating PONG signatures,
+ * so they must have some lifetime to reduce our CPU usage.
+ */
+#define PONG_SIGNATURE_LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
+
 /**
  * Priority to use for PONG messages.
  */
@@ -194,7 +212,7 @@ struct ForeignAddressList
   unsigned int connect_attempts;
 
   /**
-   * DV distance to this peer (1 if no DV is used). 
+   * DV distance to this peer (1 if no DV is used).
    * FIXME: need to set this from transport plugins!
    */
   uint32_t distance;
@@ -216,7 +234,7 @@ struct ForeignAddressList
    * successfully transmit or receive data to a peer via a particular
    * address, we set this to GNUNET_YES.  If we later get an error
    * (disconnect notification, transmission failure, timeout), we set
-   * it back to GNUNET_NO.  
+   * it back to GNUNET_NO.
    */
   int8_t connected;
 
@@ -236,7 +254,8 @@ struct ForeignAddressList
 
 
 /**
- * Entry in linked list of network addresses for ourselves.
+ * Entry in linked list of network addresses for ourselves.  Also
+ * includes a cached signature for 'struct TransportPongMessage's.
  */
 struct OwnAddressList
 {
@@ -246,21 +265,26 @@ struct OwnAddressList
   struct OwnAddressList *next;
 
   /**
-   * The address, actually a pointer to the end
-   * of this struct.  Do not free!
-   */
-  const void *addr;
-  
-  /**
-   * How long until we auto-expire this address (unless it is
+   * 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).
+   */
+  struct GNUNET_TIME_Absolute pong_sig_expires;
+
+  /**
+   * Signature for a 'struct TransportPongMessage' for this address.
+   */
+  struct GNUNET_CRYPTO_RsaSignature pong_signature;
+
   /**
    * Length of addr.
    */
-  uint16_t addrlen;
+  uint32_t addrlen;
 
 };
 
@@ -461,7 +485,7 @@ struct NeighbourList
    * Buffer for at most one payload message used when we receive
    * payload data before our PING-PONG has succeeded.  We then
    * store such messages in this intermediary buffer until the
-   * connection is fully up.  
+   * connection is fully up.
    */
   struct GNUNET_MessageHeader *pre_connect_message_buffer;
 
@@ -529,7 +553,7 @@ struct NeighbourList
   unsigned int quota_violation_count;
 
   /**
-   * DV distance to this peer (1 if no DV is used). 
+   * DV distance to this peer (1 if no DV is used).
    */
   uint32_t distance;
 
@@ -544,11 +568,23 @@ struct NeighbourList
    */
   int public_key_valid;
 
+  /**
+   * Performance data for the peer.
+   */
+  struct GNUNET_TRANSPORT_ATS_Information *ats;
+
+  /**
+   * Identity of the neighbour.
+   */
+  struct GNUNET_PeerIdentity peer;
+
 };
 
 /**
  * Message used to ask a peer to validate receipt (to check an address
- * from a HELLO).  
+ * from a HELLO).  Followed by the address we are trying to validate,
+ * or an empty address if we are just sending a PING to confirm that a
+ * connection which the receiver (of the PING) initiated is still valid.
  */
 struct TransportPingMessage
 {
@@ -559,7 +595,7 @@ struct TransportPingMessage
   struct GNUNET_MessageHeader header;
 
   /**
-   * Random challenge number (in network byte order).
+   * Challenge code (to ensure fresh reply).
    */
   uint32_t challenge GNUNET_PACKED;
 
@@ -574,14 +610,12 @@ struct TransportPingMessage
 /**
  * Message used to validate a HELLO.  The challenge is included in the
  * confirmation to make matching of replies to requests possible.  The
- * signature signs the original challenge number, our public key, the
- * sender's address (so that the sender can check that the address we
- * saw is plausible for him and possibly detect a MiM attack) and a
- * timestamp (to limit replay).<p>
+ * signature signs our public key, an expiration time and our address.<p>
  *
- * This message is followed by the address of the
- * client that we are observing (which is part of what
- * is being signed).
+ * This message is followed by our transport address that the PING tried
+ * to confirm (if we liked it).  The address can be empty (zero bytes)
+ * if the PING had not address either (and we received the request via
+ * a connection that we initiated).
  */
 struct TransportPongMessage
 {
@@ -592,9 +626,10 @@ struct TransportPongMessage
   struct GNUNET_MessageHeader header;
 
   /**
-   * For padding, always zero.
+   * Challenge code from PING (showing freshness).  Not part of what
+   * is signed so that we can re-use signatures.
    */
-  uint32_t reserved GNUNET_PACKED;
+  uint32_t challenge GNUNET_PACKED;
 
   /**
    * Signature.
@@ -602,24 +637,31 @@ struct TransportPongMessage
   struct GNUNET_CRYPTO_RsaSignature signature;
 
   /**
-   * What are we signing and why?
+   * What are we signing and why?  Two possible reason codes can be here:
+   * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN to confirm that this is a
+   * plausible address for this peer (pid is set to identity of signer); or
+   * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING to confirm that this is
+   * an address we used to connect to the peer with the given pid.
    */
   struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
 
   /**
-   * Random challenge number (in network byte order).
+   * When does this signature expire?
    */
-  uint32_t challenge GNUNET_PACKED;
+  struct GNUNET_TIME_AbsoluteNBO expiration;
 
   /**
-   * Who signed this message?
+   * Either the identity of the peer Who signed this message, or the
+   * identity of the peer that we're connected to using the given
+   * address (depending on purpose.type).
    */
-  struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded signer;
+  struct GNUNET_PeerIdentity pid;
 
   /**
-   * Size of address appended to this message
+   * Size of address appended to this message (part of what is
+   * being signed, hence not redundant).
    */
-  uint16_t addrlen;
+  uint32_t addrlen;
 
 };
 
@@ -672,7 +714,7 @@ struct TransportClient
 
   /**
    * Current transmit request handle.
-   */ 
+   */
   struct GNUNET_CONNECTION_TransmitHandle *th;
 
   /**
@@ -781,7 +823,7 @@ struct CheckHelloValidatedContext
    * NULL after we are done processing peerinfo's information.
    */
   struct GNUNET_PEERINFO_IteratorContext *piter;
-  
+
   /**
    * Was a HELLO known for this peer to peerinfo?
    */
@@ -801,12 +843,6 @@ struct CheckHelloValidatedContext
  */
 static struct GNUNET_HELLO_Message *our_hello;
 
-/**
- * "version" of "our_hello".  Used to see if a given neighbour has
- * already been sent the latest version of our HELLO message.
- */
-static unsigned int our_hello_version;
-
 /**
  * Our public key.
  */
@@ -822,11 +858,6 @@ static struct GNUNET_PeerIdentity my_identity;
  */
 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
 
-/**
- * Our scheduler.
- */
-struct GNUNET_SCHEDULER_Handle *sched;
-
 /**
  * Our configuration.
  */
@@ -842,11 +873,6 @@ static struct TransportClient *clients;
  */
 static struct TransportPlugin *plugins;
 
-/**
- * Our server.
- */
-static struct GNUNET_SERVER_Handle *server;
-
 /**
  * Handle to peerinfo service.
  */
@@ -883,6 +909,10 @@ static struct GNUNET_CONTAINER_MultiHashMap *validation_map;
  */
 static struct GNUNET_STATISTICS_Handle *stats;
 
+/**
+ * Handle for ats information
+ */
+static struct ATS_info *ats;
 
 /**
  * The peer specified by the given neighbour has timed-out or a plugin
@@ -903,14 +933,32 @@ static void disconnect_neighbour (struct NeighbourList *n, int check);
  * 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
+ * @param nexi target peer for which to transmit
  */
-static void try_transmission_to_peer (struct NeighbourList *neighbour);
+static void try_transmission_to_peer (struct NeighbourList *n);
+
+
+struct ATS_info * ats_init ();
+
+void ats_shutdown ( );
+
+void ats_notify_peer_connect (
+               const struct GNUNET_PeerIdentity *peer,
+               const struct GNUNET_TRANSPORT_ATS_Information *ats_data);
+
+void ats_notify_peer_disconnect (
+               const struct GNUNET_PeerIdentity *peer);
 
+void ats_notify_ats_data (
+               const struct GNUNET_PeerIdentity *peer,
+               const struct GNUNET_TRANSPORT_ATS_Information *ats_data);
+
+struct ForeignAddressList * ats_get_preferred_address (
+               struct NeighbourList *n);
 
 /**
  * Find an entry in the neighbour list for a particular peer.
- *  
+ *
  * @return NULL if not found.
  */
 static struct NeighbourList *
@@ -953,13 +1001,15 @@ is_blacklisted (const struct GNUNET_PeerIdentity *peer, struct TransportPlugin *
 
   if (plugin->blacklist != NULL)
     {
-      if (GNUNET_CONTAINER_multihashmap_contains(plugin->blacklist, &peer->hashPubKey) == GNUNET_YES)
+      if (GNUNET_CONTAINER_multihashmap_contains (plugin->blacklist, &peer->hashPubKey) == GNUNET_YES)
         {
 #if DEBUG_BLACKLIST
           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                      _("Peer `%s:%s' is blacklisted!\n"),
+                      "Peer `%s:%s' is blacklisted!\n",
                       plugin->short_name, GNUNET_i2s (peer));
 #endif
+          if (stats != NULL)
+            GNUNET_STATISTICS_update (stats, "# blacklisted peers refused", 1, GNUNET_NO);
           return GNUNET_YES;
         }
     }
@@ -976,11 +1026,11 @@ add_peer_to_blacklist (struct GNUNET_PeerIdentity *peer, char *transport_name)
   plugin = find_transport(transport_name);
   if (plugin == NULL) /* Nothing to do */
     return;
-  if (plugin->blacklist == NULL)    
-    plugin->blacklist = GNUNET_CONTAINER_multihashmap_create(TRANSPORT_BLACKLIST_HT_SIZE);    
+  if (plugin->blacklist == NULL)
+    plugin->blacklist = GNUNET_CONTAINER_multihashmap_create(TRANSPORT_BLACKLIST_HT_SIZE);
   GNUNET_assert(plugin->blacklist != NULL);
   GNUNET_CONTAINER_multihashmap_put(plugin->blacklist, &peer->hashPubKey,
-                                   NULL, 
+                                   NULL,
                                    GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
 }
 
@@ -1013,7 +1063,7 @@ read_blacklist_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
     {
 #if DEBUG_TRANSPORT
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  _("Option `%s' in section `%s' not specified!\n"),
+                  "Option `%s' in section `%s' not specified!\n",
                   "BLACKLIST_FILE",
                   "TRANSPORT");
 #endif
@@ -1031,14 +1081,17 @@ read_blacklist_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
     }
   if (frstat.st_size == 0)
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+#if DEBUG_TRANSPORT
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                   _("Blacklist file `%s' is empty.\n"),
                   fn);
+#endif
       GNUNET_free (fn);
       return;
     }
   /* FIXME: use mmap */
   data = GNUNET_malloc_large (frstat.st_size);
+  GNUNET_assert(data != NULL);
   if (frstat.st_size !=
       GNUNET_DISK_fn_read (fn, data, frstat.st_size))
     {
@@ -1050,13 +1103,13 @@ read_blacklist_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
     }
   entries_found = 0;
   pos = 0;
-  while ((pos < frstat.st_size) && isspace (data[pos]))
+  while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
     pos++;
   while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) &&
          (pos <= frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
     {
       colon_pos = pos;
-      while ((colon_pos < frstat.st_size) && (data[colon_pos] != ':') && !isspace (data[colon_pos]))
+      while ((colon_pos < frstat.st_size) && (data[colon_pos] != ':') && !isspace ( (unsigned char) data[colon_pos]))
         colon_pos++;
 
       if (colon_pos >= frstat.st_size)
@@ -1069,18 +1122,18 @@ read_blacklist_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
           return;
         }
 
-      if (isspace(data[colon_pos]))
+      if (isspace( (unsigned char) data[colon_pos]))
       {
         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                     _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
                     (unsigned long long) colon_pos);
         pos = colon_pos;
-        while ((pos < frstat.st_size) && isspace (data[pos]))
+        while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
           pos++;
         continue;
       }
       tsize = colon_pos - pos;
-      if ((pos >= frstat.st_size) || (pos + tsize >= frstat.st_size))
+      if ((pos >= frstat.st_size) || (pos + tsize >= frstat.st_size) || (tsize == 0))
         {
           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                       _("Syntax error in blacklist file at offset %llu, giving up!\n"),
@@ -1090,23 +1143,25 @@ read_blacklist_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
           return;
         }
 
-      transport_name = GNUNET_malloc(tsize);
+      if (tsize < 1)
+        continue;
+
+      transport_name = GNUNET_malloc(tsize + 1);
       memcpy(transport_name, &data[pos], tsize);
       pos = colon_pos + 1;
-
-
+#if DEBUG_TRANSPORT
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  _("Read transport name %s in blacklist file.\n"),
+                  "Read transport name %s in blacklist file.\n",
                   transport_name);
-
+#endif
       memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
-      if (!isspace (enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
+      if (!isspace ( (unsigned char) enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
         {
           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                       _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
                       (unsigned long long) pos);
           pos++;
-          while ((pos < frstat.st_size) && (!isspace (data[pos])))
+          while ((pos < frstat.st_size) && (!isspace ( (unsigned char) data[pos])))
             pos++;
           GNUNET_free_non_null(transport_name);
           continue;
@@ -1127,10 +1182,7 @@ read_blacklist_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
             {
               entries_found++;
               add_peer_to_blacklist (&pid,
-                              transport_name);
-              GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                          _("Found blacklisted peer `%s:%s' in configuration\n"),
-                          transport_name, GNUNET_i2s (&pid));
+                                     transport_name);
             }
           else
             {
@@ -1141,9 +1193,10 @@ read_blacklist_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
         }
       pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
       GNUNET_free_non_null(transport_name);
-      while ((pos < frstat.st_size) && isspace (data[pos]))
+      while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
         pos++;
     }
+  GNUNET_STATISTICS_update (stats, "# Transport entries blacklisted", entries_found, GNUNET_NO);
   GNUNET_free (data);
   GNUNET_free (fn);
 }
@@ -1172,15 +1225,17 @@ transmit_to_client_callback (void *cls, size_t size, void *buf)
   client->th = NULL;
   if (buf == NULL)
     {
+#if DEBUG_TRANSPORT
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                   "Transmission to client failed, closing connection.\n");
+#endif
       /* fatal error with client, free message queue! */
       while (NULL != (q = client->message_queue_head))
         {
          GNUNET_STATISTICS_update (stats,
                                    gettext_noop ("# bytes discarded (could not transmit to client)"),
                                    ntohs (((const struct GNUNET_MessageHeader*)&q[1])->size),
-                                   GNUNET_NO);      
+                                   GNUNET_NO);
          GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
                                       client->message_queue_tail,
                                       q);
@@ -1224,6 +1279,32 @@ transmit_to_client_callback (void *cls, size_t size, void *buf)
 }
 
 
+/**
+ * Convert an address to a string.
+ *
+ * @param plugin name of the plugin responsible for the address
+ * @param addr binary address
+ * @param addr_len number of bytes in addr
+ * @return NULL on error, otherwise address string
+ */
+static const char*
+a2s (const char *plugin,
+     const void *addr,
+     uint16_t addr_len)
+{
+  struct TransportPlugin *p;
+
+  if (plugin == NULL)
+    return NULL;
+  p = find_transport (plugin);
+  if (p == NULL)
+    return NULL;
+  return p->api->address_to_string (p->api->cls,
+                                   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'
@@ -1246,9 +1327,20 @@ mark_address_connected (struct ForeignAddressList *fal)
     {
       if (GNUNET_YES == pos->connected)
        {
+#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);
        }
       pos = pos->next;
     }
@@ -1284,9 +1376,15 @@ transmit_to_client (struct TransportClient *client,
     {
       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
                   _
-                  ("Dropping message, have %u messages pending (%u is the soft limit)\n"),
-                  client->message_count, MAX_PENDING);
-      /* TODO: call to statistics... */
+                  ("Dropping message of type %u and size %u, have %u messages pending (%u is the soft limit)\n"),
+                 ntohs (msg->type),
+                 ntohs (msg->size),
+                  client->message_count,
+                 MAX_PENDING);
+      GNUNET_STATISTICS_update (stats,
+                               gettext_noop ("# messages dropped due to slow client"),
+                               1,
+                               GNUNET_NO);
       return;
     }
   msize = ntohs (msg->size);
@@ -1296,7 +1394,7 @@ transmit_to_client (struct TransportClient *client,
   GNUNET_CONTAINER_DLL_insert_after (client->message_queue_head,
                                     client->message_queue_tail,
                                     client->message_queue_tail,
-                                    q);                                     
+                                    q);                                
   client->message_count++;
   if (client->th == NULL)
     {
@@ -1315,12 +1413,14 @@ transmit_to_client (struct TransportClient *client,
  * given neighbour.
  *
  * @param client who to notify
- * @param n neighbour to notify about
+ * @param n neighbour to notify about, can be NULL (on failure)
+ * @param target target of the transmission
  * @param result status code for the transmission request
  */
 static void
 transmit_send_ok (struct TransportClient *client,
                  struct NeighbourList *n,
+                 const struct GNUNET_PeerIdentity *target,
                  int result)
 {
   struct SendOkMessage send_ok_msg;
@@ -1328,9 +1428,12 @@ transmit_send_ok (struct TransportClient *client,
   send_ok_msg.header.size = htons (sizeof (send_ok_msg));
   send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
   send_ok_msg.success = htonl (result);
-  send_ok_msg.latency = GNUNET_TIME_relative_hton (n->latency);
-  send_ok_msg.peer = n->id;
-  transmit_to_client (client, &send_ok_msg.header, GNUNET_NO); 
+  if (n != NULL)
+    send_ok_msg.latency = GNUNET_TIME_relative_hton (n->latency);
+  else
+    send_ok_msg.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_FOREVER_REL);
+  send_ok_msg.peer = *target;
+  transmit_to_client (client, &send_ok_msg.header, GNUNET_NO);
 }
 
 
@@ -1342,7 +1445,7 @@ transmit_send_ok (struct TransportClient *client,
  *
  * @param cls closure, identifies the entry on the
  *            message queue that was transmitted and the
- *            client responsible for queueing the message
+ *            client responsible for queuing the message
  * @param target the peer receiving the message
  * @param result GNUNET_OK on success, if the transmission
  *           failed, we should not tell the client to transmit
@@ -1355,7 +1458,7 @@ transmit_send_continuation (void *cls,
 {
   struct MessageQueue *mq = cls;
   struct NeighbourList *n;
-  
+
   GNUNET_STATISTICS_update (stats,
                            gettext_noop ("# bytes pending with plugins"),
                            - (int64_t) mq->message_buf_size,
@@ -1365,74 +1468,55 @@ transmit_send_continuation (void *cls,
       GNUNET_STATISTICS_update (stats,
                                gettext_noop ("# bytes successfully transmitted by plugins"),
                                mq->message_buf_size,
-                               GNUNET_NO);      
+                               GNUNET_NO);
     }
   else
     {
       GNUNET_STATISTICS_update (stats,
                                gettext_noop ("# bytes with transmission failure by plugins"),
                                mq->message_buf_size,
-                               GNUNET_NO);      
-    }  
-  n = find_neighbour(&mq->neighbour_id);
-  GNUNET_assert (n != NULL);
+                               GNUNET_NO);
+    }
   if (mq->specific_address != NULL)
     {
-      if (result == GNUNET_OK)    
+      if (result == GNUNET_OK)
        {
          mq->specific_address->timeout =
            GNUNET_TIME_relative_to_absolute
            (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
          if (mq->specific_address->validated == GNUNET_YES)
            mark_address_connected (mq->specific_address);
-       }    
+       }
       else
        {
          if (mq->specific_address->connected != GNUNET_NO)
            {
+#if DEBUG_TRANSPORT
+             GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                         "Marking address `%s' as no longer connected (due to transmission problem)\n",
+                         a2s (mq->specific_address->ready_list->plugin->short_name,
+                              mq->specific_address->addr,
+                              mq->specific_address->addrlen));
+#endif
              GNUNET_STATISTICS_update (stats,
                                        gettext_noop ("# connected addresses"),
                                        -1,
                                        GNUNET_NO);
              mq->specific_address->connected = GNUNET_NO;
            }
-       }    
-      if (! mq->internal_msg) 
+       }
+      if (! mq->internal_msg)
        mq->specific_address->in_transmit = GNUNET_NO;
     }
+  n = find_neighbour(&mq->neighbour_id);
   if (mq->client != NULL)
-    transmit_send_ok (mq->client, n, result);
+    transmit_send_ok (mq->client, n, target, result);
   GNUNET_free (mq);
-  try_transmission_to_peer (n);
+  if (n != NULL)
+    try_transmission_to_peer (n);
 }
 
 
-/**
- * Convert an address to a string.
- *
- * @param plugin name of the plugin responsible for the address
- * @param addr binary address
- * @param addr_len number of bytes in addr
- * @return NULL on error, otherwise address string
- */
-static const char*
-a2s (const char *plugin,
-     const void *addr,
-     uint16_t addr_len)
-{
-  struct TransportPlugin *p;
-
-  if (plugin == NULL)
-    return NULL;
-  p = find_transport (plugin);
-  if (p == NULL)
-    return NULL;
-  return p->api->address_to_string (p->api->cls,
-                                   addr,
-                                   addr_len);
-}   
-
-
 /**
  * Find an address in any of the available transports for
  * the given neighbour that would be good for message
@@ -1450,13 +1534,16 @@ find_ready_address(struct NeighbourList *neighbour)
   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.value < now.value) && 
+          if ( (addresses->timeout.abs_value < now.abs_value) &&
               (addresses->connected == GNUNET_YES) )
             {
 #if DEBUG_TRANSPORT
@@ -1488,28 +1575,49 @@ find_ready_address(struct NeighbourList *neighbour)
                        addresses->in_transmit,
                        addresses->validated,
                        addresses->connect_attempts,
-                       (unsigned long long) addresses->timeout.value,
+                       (unsigned long long) addresses->timeout.abs_value,
                        (unsigned int) addresses->distance);
 #endif
-          if ( ( (best_address == NULL) || 
+                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.value < best_address->latency.value)) )
-           best_address = addresses;            
+              ( (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_ERROR, "Found unix address, forced this address\n");
+#endif
+  }
   if (best_address != NULL)
     {
 #if DEBUG_TRANSPORT
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "Best address found has latency of %llu ms.\n",
-                  best_address->latency.value);
+
+         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "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
@@ -1519,6 +1627,7 @@ find_ready_address(struct NeighbourList *neighbour)
                                1,
                                GNUNET_NO);
     }
+
   return best_address;
 
 }
@@ -1546,7 +1655,7 @@ retry_transmission_task (void *cls,
  * @param neighbour target peer for which to transmit
  */
 static void
-try_transmission_to_peer (struct NeighbourList *neighbour)
+try_transmission_to_peer (struct NeighbourList *n)
 {
   struct ReadyList *rl;
   struct MessageQueue *mq;
@@ -1554,7 +1663,7 @@ try_transmission_to_peer (struct NeighbourList *neighbour)
   ssize_t ret;
   int force_address;
 
-  if (neighbour->messages_head == NULL)
+  if (n->messages_head == NULL)
     {
 #if DEBUG_TRANSPORT
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -1564,15 +1673,16 @@ try_transmission_to_peer (struct NeighbourList *neighbour)
       return;                     /* nothing to do */
     }
   rl = NULL;
-  mq = neighbour->messages_head;
+  mq = n->messages_head;
   force_address = GNUNET_YES;
   if (mq->specific_address == NULL)
     {
-      mq->specific_address = find_ready_address(neighbour); 
+         /* TODO: ADD ATS */
+      mq->specific_address = ats_get_preferred_address(n);
       GNUNET_STATISTICS_update (stats,
                                gettext_noop ("# transport selected peer address freely"),
                                1,
-                               GNUNET_NO); 
+                               GNUNET_NO);
       force_address = GNUNET_NO;
     }
   if (mq->specific_address == NULL)
@@ -1580,9 +1690,9 @@ try_transmission_to_peer (struct NeighbourList *neighbour)
       GNUNET_STATISTICS_update (stats,
                                gettext_noop ("# transport failed to selected peer address"),
                                1,
-                               GNUNET_NO); 
+                               GNUNET_NO);
       timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
-      if (timeout.value == 0)
+      if (timeout.rel_value == 0)
        {
 #if DEBUG_TRANSPORT
          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -1597,39 +1707,37 @@ try_transmission_to_peer (struct NeighbourList *neighbour)
          GNUNET_STATISTICS_update (stats,
                                    gettext_noop ("# bytes discarded (no destination address available)"),
                                    mq->message_buf_size,
-                                   GNUNET_NO);      
+                                   GNUNET_NO);
          if (mq->client != NULL)
-           transmit_send_ok (mq->client, neighbour, GNUNET_NO);
-         GNUNET_CONTAINER_DLL_remove (neighbour->messages_head,
-                                      neighbour->messages_tail,
+           transmit_send_ok (mq->client, n, &n->id, GNUNET_NO);
+         GNUNET_CONTAINER_DLL_remove (n->messages_head,
+                                      n->messages_tail,
                                       mq);
          GNUNET_free (mq);
-         return;               /* nobody ready */ 
+         return;               /* nobody ready */
        }
       GNUNET_STATISTICS_update (stats,
                                gettext_noop ("# message delivery deferred (no address)"),
                                1,
                                GNUNET_NO);
-      if (neighbour->retry_task != GNUNET_SCHEDULER_NO_TASK)
-       GNUNET_SCHEDULER_cancel (sched,
-                                neighbour->retry_task);
-      neighbour->retry_task = GNUNET_SCHEDULER_add_delayed (sched,
-                                                           timeout,
+      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,
-                                                           neighbour);
+                                                           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",
                  mq->message_buf_size,
                  GNUNET_i2s (&mq->neighbour_id),
-                 timeout.value);
+                 timeout.rel_value);
 #endif
       /* FIXME: might want to trigger peerinfo lookup here
         (unless that's already pending...) */
-      return;    
+      return;
     }
-  GNUNET_CONTAINER_DLL_remove (neighbour->messages_head,
-                              neighbour->messages_tail,
+  GNUNET_CONTAINER_DLL_remove (n->messages_head,
+                              n->messages_tail,
                               mq);
   if (mq->specific_address->connected == GNUNET_NO)
     mq->specific_address->connect_attempts++;
@@ -1641,7 +1749,7 @@ try_transmission_to_peer (struct NeighbourList *neighbour)
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
               mq->message_buf_size,
-              GNUNET_i2s (&neighbour->id), 
+              GNUNET_i2s (&neighbour->id),
              (mq->specific_address->addr != NULL)
              ? a2s (mq->plugin->short_name,
                     mq->specific_address->addr,
@@ -1672,7 +1780,7 @@ try_transmission_to_peer (struct NeighbourList *neighbour)
     {
       /* failure, but 'send' would not call continuation in this case,
         so we need to do it here! */
-      transmit_send_continuation (mq, 
+      transmit_send_continuation (mq,
                                  &mq->neighbour_id,
                                  GNUNET_SYSERR);
     }
@@ -1728,6 +1836,7 @@ transmit_to_peer (struct TransportClient *client,
   mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
   mq->specific_address = peer_address;
   mq->client = client;
+  /* FIXME: this memcpy can be up to 7% of our total runtime! */
   memcpy (&mq[1], message_buf, message_buf_size);
   mq->message_buf = (const char*) &mq[1];
   mq->message_buf_size = message_buf_size;
@@ -1735,7 +1844,7 @@ transmit_to_peer (struct TransportClient *client,
   mq->internal_msg = is_internal;
   mq->priority = priority;
   mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
-  if (is_internal)    
+  if (is_internal)
     GNUNET_CONTAINER_DLL_insert (neighbour->messages_head,
                                 neighbour->messages_tail,
                                 mq);
@@ -1780,7 +1889,7 @@ address_generator (void *cls, size_t max, void *buf)
     }
   ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
                                   gc->expiration,
-                                  gc->addr_pos->addr,
+                                  &gc->addr_pos[1],
                                   gc->addr_pos->addrlen, buf, max);
   gc->addr_pos = gc->addr_pos->next;
   return ret;
@@ -1822,7 +1931,6 @@ refresh_hello ()
 
   GNUNET_free_non_null (our_hello);
   our_hello = hello;
-  our_hello_version++;
   GNUNET_PEERINFO_add_peer (peerinfo, our_hello);
   npos = neighbours;
   while (npos != NULL)
@@ -1838,7 +1946,7 @@ refresh_hello ()
                                GNUNET_NO);
       transmit_to_peer (NULL, NULL, 0,
                        HELLO_ADDRESS_EXPIRATION,
-                        (const char *) our_hello, 
+                        (const char *) our_hello,
                        GNUNET_HELLO_size(our_hello),
                         GNUNET_NO, npos);
       npos = npos->next;
@@ -1867,7 +1975,8 @@ expire_address_task (void *cls,
  *        expired
  */
 static void
-update_addresses (struct TransportPlugin *plugin, int fresh)
+update_addresses (struct TransportPlugin *plugin, 
+                 int fresh)
 {
   static struct GNUNET_TIME_Absolute last_update;
   struct GNUNET_TIME_Relative min_remaining;
@@ -1879,29 +1988,29 @@ update_addresses (struct TransportPlugin *plugin, int fresh)
   int expired;
 
   if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
-    GNUNET_SCHEDULER_cancel (plugin->env.sched, plugin->address_update_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).value > (HELLO_ADDRESS_EXPIRATION.value / 4));
+  expired = (GNUNET_TIME_absolute_get_duration (last_update).rel_value > (HELLO_ADDRESS_EXPIRATION.rel_value / 4));
   prev = NULL;
   pos = plugin->addresses;
   while (pos != NULL)
     {
       next = pos->next;
-      if (pos->expires.value < now.value)
+      if (pos->expires.abs_value < now.abs_value)
         {
           expired = GNUNET_YES;
           if (prev == NULL)
             plugin->addresses = pos->next;
           else
-            prev->next = pos->next;  
+            prev->next = pos->next;
           GNUNET_free (pos);
         }
       else
         {
           remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
-          if (remaining.value < min_remaining.value)
+          if (remaining.rel_value < min_remaining.rel_value)
             min_remaining = remaining;
           prev = pos;
         }
@@ -1917,8 +2026,7 @@ update_addresses (struct TransportPlugin *plugin, int fresh)
                                            GNUNET_TIME_relative_divide (HELLO_ADDRESS_EXPIRATION,
                                                                         2));
   plugin->address_update_task
-    = GNUNET_SCHEDULER_add_delayed (plugin->env.sched,
-                                   min_remaining,
+    = GNUNET_SCHEDULER_add_delayed (min_remaining,
                                    &expire_address_task, plugin);
 }
 
@@ -1949,7 +2057,7 @@ expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  * @param value value in the hash map ('struct ValidationEntry*')
  * @return GNUNET_YES (we should continue to iterate)
  */
-static int 
+static int
 remove_session_validations (void *cls,
                            const GNUNET_HashCode * key,
                            void *value)
@@ -1963,15 +2071,72 @@ remove_session_validations (void *cls,
 }
 
 
+/**
+ * We've been disconnected from the other peer (for some
+ * connection-oriented transport).  Either quickly
+ * re-establish the connection or signal the disconnect
+ * to the CORE.
+ *
+ * Only signal CORE level disconnect if ALL addresses
+ * for the peer are exhausted.
+ *
+ * @param p overall plugin context
+ * @param nl neighbour that was disconnected
+ */
+static void
+try_fast_reconnect (struct TransportPlugin *p,
+                   struct NeighbourList *nl)
+{
+  /* FIXME-MW: fast reconnect / transport switching not implemented... */
+  /* Note: the idea here is to hide problems with transports (or
+     switching between plugins) from the core to eliminate the need to
+     re-negotiate session keys and the like; OTOH, we should tell core
+     quickly (much faster than timeout) `if a connection was lost and
+     could not be re-established (i.e. other peer went down or is
+     unable / refuses to communicate);
+
+     So we should consider:
+     1) ideally: our own willingness / need to connect
+     2) prior failures to connect to this peer (by plugin)
+     3) ideally: reasons why other peer terminated (as far as knowable)
+
+     Most importantly, it must be POSSIBLE for another peer to terminate
+     a connection for a while (without us instantly re-establishing it).
+     Similarly, if another peer is gone we should quickly notify CORE.
+     OTOH, if there was a minor glitch (i.e. crash of gnunet-service-transport
+     on the other end), we should reconnect in such a way that BOTH CORE
+     services never even notice.
+     Furthermore, the same mechanism (or small variation) could be used
+     to switch to a better-performing plugin (ATS).
+
+     Finally, this needs to be tested throughly... */                                                          
+
+  /*
+   * 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.
+   *
+   * More specifically, half the places it was used had it WRONG.
+   */
+
+  /* No reconnect, signal disconnect instead! */
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+            "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
+            "try_fast_reconnect");
+  disconnect_neighbour (nl, GNUNET_YES);
+}
+
+
 /**
  * Function that will be called whenever the plugin internally
  * cleans up a session pointer and hence the service needs to
  * discard all of those sessions as well.  Plugins that do not
  * use sessions can simply omit calling this function and always
  * use NULL wherever a session pointer is needed.
- * 
+ *
  * @param cls closure
- * @param peer which peer was the session for 
+ * @param peer which peer was the session for
  * @param session which session is being destoyed
  */
 static void
@@ -1990,7 +2155,7 @@ plugin_env_session_end  (void *cls,
                                         session);
   nl = find_neighbour (peer);
   if (nl == NULL)
-    return;
+    return; /* was never marked as connected */
   rl = nl->plugins;
   while (rl != NULL)
     {
@@ -1999,7 +2164,7 @@ plugin_env_session_end  (void *cls,
       rl = rl->next;
     }
   if (rl == NULL)
-    return;
+    return; /* was never marked as connected */
   prev = NULL;
   pos = rl->addresses;
   while ( (pos != NULL) &&
@@ -2009,33 +2174,51 @@ plugin_env_session_end  (void *cls,
       pos = pos->next;
     }
   if (pos == NULL)
-    return;
+    return; /* was never marked as connected */
   pos->session = NULL;
   if (pos->addrlen != 0)
-    return;
+    {
+      if (nl->received_pong != GNUNET_NO)
+       try_fast_reconnect (p, nl);
+      return;
+    }
+  /* was inbound connection, free 'pos' */
   if (prev == NULL)
     rl->addresses = pos->next;
   else
     prev->next = pos->next;
   if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
     {
-      GNUNET_SCHEDULER_cancel (sched,
-                              pos->revalidate_task);
+      GNUNET_SCHEDULER_cancel (pos->revalidate_task);
       pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
     }
   GNUNET_free (pos);
   if (nl->received_pong == GNUNET_NO)
-    return; /* nothing to do */
+    return; /* nothing to do, never connected... */
   /* check if we have any validated addresses left */
   pos = rl->addresses;
   while (pos != NULL)
     {
       if (pos->validated)
-       return;
+       {
+         try_fast_reconnect (p, nl);
+         return;
+       }
       pos = pos->next;
     }
   /* no valid addresses left, signal disconnect! */
-  disconnect_neighbour (nl, GNUNET_NO);  
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+            "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
+            "plugin_env_session_end");
+  /* FIXME: This doesn't mean there are no addresses left for this PEER,
+   * it means there aren't any left for this PLUGIN/PEER combination! So
+   * calling disconnect_neighbor here with GNUNET_NO forces disconnect
+   * when it isn't necessary. Using GNUNET_YES at least checks to see
+   * if there are any addresses that work first, so as not to overdo it.
+   * --NE
+   */
+  disconnect_neighbour (nl, GNUNET_YES);
 }
 
 
@@ -2069,16 +2252,15 @@ plugin_env_notify_address (void *cls,
   while (al != NULL)
     {
       if ((addrlen == al->addrlen) && (0 == memcmp (addr, &al[1], addrlen)))
-        {
-          if (al->expires.value < abex.value)
-            al->expires = abex;
+        {            
+         al->expires = abex;
+         update_addresses (p, GNUNET_NO);
           return;
         }
       al = al->next;
     }
 
   al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
-  al->addr = &al[1];
   al->next = p->addresses;
   p->addresses = al;
   al->expires = abex;
@@ -2094,10 +2276,12 @@ plugin_env_notify_address (void *cls,
 static void
 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
                         struct GNUNET_TIME_Relative latency,
-                       uint32_t distance)
+                        uint32_t distance)
 {
-  struct ConnectInfoMessage cim;
+  struct ConnectInfoMessage cim;
   struct TransportClient *cpos;
+  uint32_t ats_count;
+  size_t size;
 
 #if DEBUG_TRANSPORT
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -2108,17 +2292,37 @@ notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
                            gettext_noop ("# peers connected"),
                            1,
                            GNUNET_NO);
-  cim.header.size = htons (sizeof (struct ConnectInfoMessage));
-  cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
-  cim.distance = htonl (distance);
-  cim.latency = GNUNET_TIME_relative_hton (latency);
-  memcpy (&cim.id, peer, sizeof (struct GNUNET_PeerIdentity));
+
+  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(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);
+  memcpy (&cim->id, peer, sizeof (struct GNUNET_PeerIdentity));
+
+  /* notify ats about connecting peer */
+  ats_notify_peer_connect (peer, &(cim->ats));
+
   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);
 }
 
 
@@ -2144,6 +2348,10 @@ notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
   dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
   dim.reserved = htonl (0);
   memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
+
+  /* notify ats about connecting peer */
+  ats_notify_peer_disconnect (peer);
+
   cpos = clients;
   while (cpos != NULL)
     {
@@ -2216,7 +2424,7 @@ static struct ForeignAddressList *
 add_peer_address (struct NeighbourList *neighbour,
                  const char *tname,
                  struct Session *session,
-                 const char *addr, 
+                 const char *addr,
                  uint16_t addrlen)
 {
   struct ReadyList *head;
@@ -2252,7 +2460,7 @@ add_peer_address (struct NeighbourList *neighbour,
   ret->latency = GNUNET_TIME_relative_get_forever();
   ret->distance = -1;
   ret->timeout = GNUNET_TIME_relative_to_absolute
-    (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); 
+    (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
   ret->ready_list = head;
   ret->next = head->addresses;
   head->addresses = ret;
@@ -2390,7 +2598,7 @@ check_address_exists (void *cls,
  * @param value value in the hash map (validation to abort)
  * @return GNUNET_YES (always)
  */
-static int 
+static int
 abort_validation (void *cls,
                  const GNUNET_HashCode * key,
                  void *value)
@@ -2398,7 +2606,7 @@ abort_validation (void *cls,
   struct ValidationEntry *va = value;
 
   if (GNUNET_SCHEDULER_NO_TASK != va->timeout_task)
-    GNUNET_SCHEDULER_cancel (sched, va->timeout_task);
+    GNUNET_SCHEDULER_cancel (va->timeout_task);
   GNUNET_free (va->transport_name);
   if (va->chvc != NULL)
     {
@@ -2500,18 +2708,18 @@ add_to_foreign_address_list (void *cls,
   GNUNET_STATISTICS_update (stats,
                            gettext_noop ("# valid peer addresses returned by PEERINFO"),
                            1,
-                           GNUNET_NO);      
+                           GNUNET_NO);
   try = GNUNET_NO;
   fal = find_peer_address (n, tname, NULL, addr, addrlen);
   if (fal == NULL)
     {
-#if DEBUG_TRANSPORT
+#if DEBUG_TRANSPORT_HELLO
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                  "Adding address `%s' (%s) for peer `%4s' due to PEERINFO data for %llums.\n",
                  a2s (tname, addr, addrlen),
                  tname,
                  GNUNET_i2s (&n->id),
-                 expiration.value);
+                 expiration.abs_value);
 #endif
       fal = add_peer_address (n, tname, NULL, addr, addrlen);
       if (fal == NULL)
@@ -2519,7 +2727,7 @@ add_to_foreign_address_list (void *cls,
          GNUNET_STATISTICS_update (stats,
                                    gettext_noop ("# previously validated addresses lacking transport"),
                                    1,
-                                   GNUNET_NO); 
+                                   GNUNET_NO);
        }
       else
        {
@@ -2543,11 +2751,11 @@ add_to_foreign_address_list (void *cls,
     }
   if (fal->validated == GNUNET_NO)
     {
-      fal->validated = GNUNET_YES;  
+      fal->validated = GNUNET_YES;
       GNUNET_STATISTICS_update (stats,
                                gettext_noop ("# peer addresses considered valid"),
                                1,
-                               GNUNET_NO);      
+                               GNUNET_NO);
     }
   if (try == GNUNET_YES)
     {
@@ -2566,21 +2774,31 @@ add_to_foreign_address_list (void *cls,
  * @param cls closure ('struct NeighbourList*')
  * @param peer id of the peer, NULL for last call
  * @param h hello message for the peer (can be NULL)
- * @param trust amount of trust we have in the peer (not used)
+ * @param err_msg NULL if successful, otherwise contains error message
  */
 static void
 add_hello_for_peer (void *cls,
                    const struct GNUNET_PeerIdentity *peer,
-                   const struct GNUNET_HELLO_Message *h, 
-                   uint32_t trust)
+                   const struct GNUNET_HELLO_Message *h,
+                   const char *err_msg)
 {
   struct NeighbourList *n = cls;
 
-  if (peer == NULL)
+  if (err_msg != NULL)
+  {
+         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                     _("Error in communication with PEERINFO service\n"));
+       /* return; */
+  }
+  if ((peer == NULL))
     {
+      GNUNET_STATISTICS_update (stats,
+                                gettext_noop ("# outstanding peerinfo iterate requests"),
+                                -1,
+                                GNUNET_NO);
       n->piter = NULL;
       return;
-    } 
+    }
   if (h == NULL)
     return; /* no HELLO available */
 #if DEBUG_TRANSPORT
@@ -2603,7 +2821,7 @@ add_hello_for_peer (void *cls,
 
 /**
  * Create a fresh entry in our neighbour list for the given peer.
- * Will try to transmit our current HELLO to the new neighbour. 
+ * Will try to transmit our current HELLO to the new neighbour.
  * Do not call this function directly, use 'setup_peer_check_blacklist.
  *
  * @param peer the peer for which we create the entry
@@ -2654,14 +2872,26 @@ setup_new_neighbour (const struct GNUNET_PeerIdentity *peer,
     }
   n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
   n->distance = -1;
-  n->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
-                                                  GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
+  n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
                                                   &neighbour_timeout_task, n);
   if (do_hello)
     {
+      GNUNET_STATISTICS_update (stats,
+                                gettext_noop ("# peerinfo new neighbor iterate requests"),
+                                1,
+                                GNUNET_NO);
+      GNUNET_STATISTICS_update (stats,
+                                gettext_noop ("# outstanding peerinfo iterate requests"),
+                                1,
+                                GNUNET_NO);
       n->piter = GNUNET_PEERINFO_iterate (peerinfo, peer,
-                                         0, GNUNET_TIME_UNIT_FOREVER_REL,
+                                         GNUNET_TIME_UNIT_FOREVER_REL,
                                          &add_hello_for_peer, n);
+
+      GNUNET_STATISTICS_update (stats,
+                                gettext_noop ("# HELLO's sent to new neighbors"),
+                                1,
+                                GNUNET_NO);
       transmit_to_peer (NULL, NULL, 0,
                        HELLO_ADDRESS_EXPIRATION,
                        (const char *) our_hello, GNUNET_HELLO_size(our_hello),
@@ -2673,7 +2903,7 @@ setup_new_neighbour (const struct GNUNET_PeerIdentity *peer,
 
 /**
  * Function called after we have checked if communicating
- * with a given peer is acceptable.  
+ * with a given peer is acceptable.
  *
  * @param cls closure
  * @param n NULL if communication is not acceptable
@@ -2727,12 +2957,12 @@ static struct Blacklisters *bl_tail;
  */
 struct BlacklistCheck
 {
-  
+
   /**
    * This is a linked list.
    */
   struct BlacklistCheck *next;
-  
+
   /**
    * This is a linked list.
    */
@@ -2791,13 +3021,12 @@ static struct BlacklistCheck *bc_tail;
  * Perform next action in the blacklist check.
  *
  * @param cls the 'struct BlacklistCheck*'
- * @param tc unused 
+ * @param tc unused
  */
 static void
 do_blacklist_check (void *cls,
                    const struct GNUNET_SCHEDULER_TaskContext *tc);
 
-
 /**
  * Transmit blacklist query to the client.
  *
@@ -2819,8 +3048,7 @@ transmit_blacklist_message (void *cls,
   if (size == 0)
     {
       GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK);
-      bc->task = GNUNET_SCHEDULER_add_now (sched,
-                                          &do_blacklist_check,
+      bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
                                           bc);
       return 0;
     }
@@ -2829,7 +3057,7 @@ transmit_blacklist_message (void *cls,
   bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
   bm.is_allowed = htonl (0);
   bm.peer = bc->peer;
-  memcpy (buf, &bm, sizeof (bm)); 
+  memcpy (buf, &bm, sizeof (bm));
   GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
   return sizeof (bm);
 }
@@ -2839,7 +3067,7 @@ transmit_blacklist_message (void *cls,
  * Perform next action in the blacklist check.
  *
  * @param cls the 'struct BlacklistCheck*'
- * @param tc unused 
+ * @param tc unused
  */
 static void
 do_blacklist_check (void *cls,
@@ -2857,14 +3085,14 @@ do_blacklist_check (void *cls,
       GNUNET_free (bc);
       return;
     }
-  if (bl->bc == NULL) 
+  if (bl->bc == NULL)
     {
       bl->bc = bc;
       bc->th = GNUNET_SERVER_notify_transmit_ready (bl->client,
                                                    sizeof (struct BlacklistMessage),
                                                    GNUNET_TIME_UNIT_FOREVER_REL,
                                                    &transmit_blacklist_message,
-                                                   bc); 
+                                                   bc);
     }
 }
 
@@ -2893,13 +3121,16 @@ setup_peer_check_blacklist (const struct GNUNET_PeerIdentity *peer,
   n = find_neighbour(peer);
   if (n != NULL)
     {
-      cont (cont_cls, n);
+      if (cont != NULL)
+        cont (cont_cls, n);
       return;
     }
   if (bl_head == NULL)
     {
-      cont (cont_cls,
-           setup_new_neighbour (peer, do_hello));
+      if (cont != NULL)
+        cont (cont_cls, setup_new_neighbour (peer, do_hello));
+      else
+        setup_new_neighbour(peer, do_hello);
       return;
     }
   bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
@@ -2909,14 +3140,13 @@ setup_peer_check_blacklist (const struct GNUNET_PeerIdentity *peer,
   bc->cont = cont;
   bc->cont_cls = cont_cls;
   bc->bl_pos = bl_head;
-  bc->task = GNUNET_SCHEDULER_add_now (sched,
-                                      &do_blacklist_check,
+  bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
                                       bc);
 }
 
 
 /**
- * Function called with the result of querying a new blacklister about 
+ * 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'
@@ -2929,7 +3159,12 @@ confirm_or_drop_neighbour (void *cls,
   struct NeighbourList * orig = cls;
 
   if (n == NULL)
-    disconnect_neighbour (orig, GNUNET_NO);
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&orig->id),
+              "confirm_or_drop_neighboUr");
+      disconnect_neighbour (orig, GNUNET_NO);
+    }
 }
 
 
@@ -2977,8 +3212,7 @@ handle_blacklist_init (void *cls,
       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 (sched,
-                                            &do_blacklist_check,
+       bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
                                             bc);
       n = n->next;
     }
@@ -3004,16 +3238,16 @@ handle_blacklist_reply (void *cls,
   bl = bl_head;
   while ( (bl != NULL) &&
          (bl->client != client) )
-    bl = bl->next;  
+    bl = bl->next;
   if (bl == NULL)
     {
       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
       return;
     }
   bc = bl->bc;
-  bl->bc = NULL;  
+  bl->bc = NULL;
   if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
-    {    
+    {
       bc->cont (bc->cont_cls, NULL);
       GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
       GNUNET_free (bc);
@@ -3021,9 +3255,8 @@ handle_blacklist_reply (void *cls,
   else
     {
       bc->bl_pos = bc->bl_pos->next;
-      bc->task = GNUNET_SCHEDULER_add_now (sched,
-                                          &do_blacklist_check,
-                                          bc);      
+      bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
+                                          bc);
     }
   /* check if any other bc's are waiting for this blacklister */
   bc = bc_head;
@@ -3031,9 +3264,8 @@ handle_blacklist_reply (void *cls,
     {
       if ( (bc->bl_pos == bl) &&
           (GNUNET_SCHEDULER_NO_TASK == bc->task) )
-       bc->task = GNUNET_SCHEDULER_add_now (sched,
-                                            &do_blacklist_check,
-                                            bc);      
+       bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
+                                            bc);
       bc = bc->next;
     }
 }
@@ -3045,8 +3277,8 @@ handle_blacklist_reply (void *cls,
  * @param cls our 'struct PeriodicValidationContext*'
  * @param tc task context
  */
-static void 
-send_periodic_ping (void *cls, 
+static void
+send_periodic_ping (void *cls,
                    const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
   struct ForeignAddressList *peer_address = cls;
@@ -3057,17 +3289,18 @@ send_periodic_ping (void *cls,
   struct CheckAddressExistsClosure caec;
   char * message_buf;
   uint16_t hello_size;
+  size_t slen;
   size_t tsize;
 
   peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
-    return; 
+    return;
   tp = peer_address->ready_list->plugin;
   neighbour = peer_address->ready_list->neighbour;
   if (GNUNET_YES != neighbour->public_key_valid)
     {
       /* no public key yet, try again later */
-      schedule_next_ping (peer_address);     
+      schedule_next_ping (peer_address);
       return;
     }
   caec.addr = peer_address->addr;
@@ -3095,13 +3328,13 @@ send_periodic_ping (void *cls,
                   tp->short_name,
                   GNUNET_i2s (&neighbour->id));
 #endif
-      schedule_next_ping (peer_address);     
+      schedule_next_ping (peer_address);
       return;
     }
   va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
   va->transport_name = GNUNET_strdup (tp->short_name);
-  va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
-                                            (unsigned int) -1);
+  va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
+                                            UINT_MAX);
   va->send_time = GNUNET_TIME_absolute_get();
   va->session = peer_address->session;
   if (peer_address->addr != NULL)
@@ -3111,32 +3344,67 @@ send_periodic_ping (void *cls,
       va->addrlen = peer_address->addrlen;
     }
   memcpy(&va->publicKey,
-        &neighbour->publicKey, 
+        &neighbour->publicKey,
         sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
 
-  va->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
-                                                   HELLO_VERIFICATION_TIMEOUT,
+  va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
                                                    &timeout_hello_validation,
                                                    va);
   GNUNET_CONTAINER_multihashmap_put (validation_map,
                                      &neighbour->id.hashPubKey,
                                      va,
                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
-  hello_size = GNUNET_HELLO_size(our_hello);
+
+  if (peer_address->validated != GNUNET_YES)
+    hello_size = GNUNET_HELLO_size(our_hello);
+  else
+    hello_size = 0;
+
   tsize = sizeof(struct TransportPingMessage) + hello_size;
+
+  if (peer_address->addr != NULL)
+    {
+      slen = strlen (tp->short_name) + 1;
+      tsize += slen + peer_address->addrlen;
+    }
+  else
+    {
+      slen = 0; /* make gcc happy */
+    }
   message_buf = GNUNET_malloc(tsize);
-  ping.challenge = htonl(va->challenge);
-  ping.header.size = htons(sizeof(struct TransportPingMessage));
   ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
+  ping.challenge = htonl(va->challenge);
   memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
-  memcpy(message_buf, our_hello, hello_size);
+  if (peer_address->validated != GNUNET_YES)
+    {
+      memcpy(message_buf, our_hello, hello_size);
+    }
+
+  if (peer_address->addr != NULL)
+    {
+      ping.header.size = htons(sizeof(struct TransportPingMessage) +
+                              peer_address->addrlen +
+                              slen);
+      memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
+            tp->short_name,
+            slen);
+      memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
+            peer_address->addr,
+            peer_address->addrlen);
+    }
+  else
+    {
+      ping.header.size = htons(sizeof(struct TransportPingMessage));
+    }
+
   memcpy(&message_buf[hello_size],
          &ping,
          sizeof(struct TransportPingMessage));
+
 #if DEBUG_TRANSPORT_REVALIDATION
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
-              (peer_address->addr != NULL) 
+              "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s'\n",
+              (peer_address->addr != NULL)
              ? a2s (peer_address->plugin->short_name,
                     peer_address->addr,
                     peer_address->addrlen)
@@ -3144,8 +3412,18 @@ send_periodic_ping (void *cls,
               tp->short_name,
               GNUNET_i2s (&neighbour->id),
               "HELLO", hello_size,
-              "PING", sizeof (struct TransportPingMessage));
+              "PING");
 #endif
+  if (peer_address->validated != GNUNET_YES)
+    GNUNET_STATISTICS_update (stats,
+                              gettext_noop ("# PING with HELLO messages sent"),
+                              1,
+                              GNUNET_NO);
+  else
+    GNUNET_STATISTICS_update (stats,
+                              gettext_noop ("# PING without HELLO messages sent"),
+                              1,
+                              GNUNET_NO);
   GNUNET_STATISTICS_update (stats,
                            gettext_noop ("# PING messages sent for re-validation"),
                            1,
@@ -3174,29 +3452,28 @@ schedule_next_ping (struct ForeignAddressList *fal)
   if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
     return;
   delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
-  delay.value /= 2; /* do before expiration */
+  delay.rel_value /= 2; /* do before expiration */
   delay = GNUNET_TIME_relative_min (delay,
                                    LATENCY_EVALUATION_MAX_DELAY);
   if (GNUNET_YES != fal->estimated)
     {
       delay = GNUNET_TIME_UNIT_ZERO;
       fal->estimated = GNUNET_YES;
-    }                              
+    }                          
   if (GNUNET_YES == fal->connected)
     {
       delay = GNUNET_TIME_relative_min (delay,
                                        CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
-    }  
+    }
   /* FIXME: also adjust delay based on how close the last
      observed latency is to the latency of the best alternative */
   /* bound how fast we can go */
   delay = GNUNET_TIME_relative_max (delay,
                                    GNUNET_TIME_UNIT_SECONDS);
   /* randomize a bit (to avoid doing all at the same time) */
-  delay.value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
-  fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(sched, 
-                                                     delay,
-                                                     &send_periodic_ping, 
+  delay.rel_value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
+  fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(delay,
+                                                     &send_periodic_ping,
                                                      fal);
 }
 
@@ -3212,7 +3489,7 @@ schedule_next_ping (struct ForeignAddressList *fal)
  */
 static void
 handle_payload_message (const struct GNUNET_MessageHeader *message,
-                       struct NeighbourList *n)
+                                               struct NeighbourList *n)
 {
   struct InboundMessage *im;
   struct TransportClient *cpos;
@@ -3221,15 +3498,22 @@ handle_payload_message (const struct GNUNET_MessageHeader *message,
   msize = ntohs (message->size);
   if (n->received_pong == GNUNET_NO)
     {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "Received message of type %u and size %u from `%4s', but no pong yet!!\n",
+                  ntohs (message->type),
+                  ntohs (message->size),
+                  GNUNET_i2s (&n->id));
       GNUNET_free_non_null (n->pre_connect_message_buffer);
       n->pre_connect_message_buffer = GNUNET_malloc (msize);
       memcpy (n->pre_connect_message_buffer, message, msize);
       return;
     }
+
 #if DEBUG_TRANSPORT
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Received message of type %u from `%4s', sending to all clients.\n",
-             ntohs (message->type), 
+             "Received message of type %u and size %u from `%4s', sending to all clients.\n",
+             ntohs (message->type),
+             ntohs (message->size),
              GNUNET_i2s (&n->id));
 #endif
   if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
@@ -3237,8 +3521,8 @@ handle_payload_message (const struct GNUNET_MessageHeader *message,
     {
       n->quota_violation_count++;
 #if DEBUG_TRANSPORT
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,                       
-                 "Bandwidth quota (%u b/s) violation detected (total of %u).\n", 
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,                     
+                 "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
                  n->in_tracker.available_bytes_per_s__,
                  n->quota_violation_count);
 #endif
@@ -3246,7 +3530,7 @@ handle_payload_message (const struct GNUNET_MessageHeader *message,
       GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
                                        - 32 * 1024);           
     }
-  else 
+  else
     {
       if (n->quota_violation_count > 0)
        {
@@ -3261,13 +3545,25 @@ handle_payload_message (const struct GNUNET_MessageHeader *message,
                            msize,
                            GNUNET_NO);
   /* transmit message to all clients */
-  im = GNUNET_malloc (sizeof (struct InboundMessage) + msize);
-  im->header.size = htons (sizeof (struct InboundMessage) + msize);
+  uint32_t ats_count = 2;
+  size_t size = sizeof (struct InboundMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information) + msize;
+  if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
+         GNUNET_break(0);
+
+  im = GNUNET_malloc (size);
+  im->header.size = htons (size);
   im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
-  im->latency = GNUNET_TIME_relative_hton (n->latency);
   im->peer = n->id;
-  im->distance = ntohl(n->distance);
-  memcpy (&im[1], message, msize);
+  im->ats_count = htonl(ats_count);
+  /* Setting ATS data */
+  (&(im->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
+  (&(im->ats))[0].value = htonl (n->distance);
+  (&(im->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
+  (&(im->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
+  (&(im->ats))[ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
+  (&(im->ats))[ats_count].value = htonl (0);
+
+  memcpy (&((&(im->ats))[ats_count+1]), message, msize);
   cpos = clients;
   while (cpos != NULL)
     {
@@ -3301,34 +3597,141 @@ check_pending_validation (void *cls,
   struct GNUNET_PeerIdentity target;
   struct NeighbourList *n;
   struct ForeignAddressList *fal;
+  struct OwnAddressList *oal;
+  struct TransportPlugin *tp;
   struct GNUNET_MessageHeader *prem;
+  uint16_t ps;
+  const char *addr;
+  size_t slen;
+  size_t alen;
 
-  if (ve->challenge != challenge)
-    return GNUNET_YES;
-
-#if SIGN_USELESS
-  if (GNUNET_OK !=
-      GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PING,
-                               &pong->purpose, 
-                               &pong->signature,
-                               &ve->publicKey))
+  ps = ntohs (pong->header.size);
+  if (ps < sizeof (struct TransportPongMessage))
     {
       GNUNET_break_op (0);
-      return GNUNET_YES;
+      return GNUNET_NO;
+    }
+  addr = (const char*) &pong[1];
+  slen = strlen (ve->transport_name) + 1;
+  if ( (ps - sizeof (struct TransportPongMessage) < slen) ||
+       (ve->challenge != challenge) ||
+       (addr[slen-1] != '\0') ||
+       (0 != strcmp (addr, ve->transport_name)) ||
+       (ntohl (pong->purpose.size)
+       != sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
+       sizeof (uint32_t) +
+       sizeof (struct GNUNET_TIME_AbsoluteNBO) +
+       sizeof (struct GNUNET_PeerIdentity) + ps - sizeof (struct TransportPongMessage)) )
+    {
+      return GNUNET_YES;
     }
+
+  alen = ps - sizeof (struct TransportPongMessage) - slen;
+  switch (ntohl (pong->purpose.purpose))
+    {
+    case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN:
+      if ( (ve->addrlen + slen != ntohl (pong->addrlen)) ||
+          (0 != memcmp (&addr[slen],
+                        ve->addr,
+                        ve->addrlen)) )
+        {
+          return GNUNET_YES; /* different entry, keep trying! */
+        }
+      if (0 != memcmp (&pong->pid,
+                      key,
+                      sizeof (struct GNUNET_PeerIdentity)))
+       {
+         GNUNET_break_op (0);
+         return GNUNET_NO;
+       }
+      if (GNUNET_OK !=
+         GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
+                                   &pong->purpose,
+                                   &pong->signature,
+                                   &ve->publicKey))
+       {
+         GNUNET_break_op (0);
+         return GNUNET_NO;
+       }
+
+#if DEBUG_TRANSPORT
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                 "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
+                 GNUNET_h2s (key),
+                 a2s (ve->transport_name,
+                      (const struct sockaddr *) ve->addr,
+                      ve->addrlen),
+                 ve->transport_name);
 #endif
+      break;
+    case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING:
+      if (0 != memcmp (&pong->pid,
+                        &my_identity,
+                        sizeof (struct GNUNET_PeerIdentity)))
+       {
+         GNUNET_break_op (0);
+         return GNUNET_NO;
+       }
+      if (ve->addrlen != 0)
+        {
+          /* must have been for a different validation entry */
+          return GNUNET_YES;
+        }
+      tp = find_transport (ve->transport_name);
+      if (tp == NULL)
+       {
+         GNUNET_break (0);
+         return GNUNET_YES;
+       }
+      oal = tp->addresses;
+      while (NULL != oal)
+       {
+         if ( (oal->addrlen == alen) &&
+              (0 == memcmp (&oal[1],
+                            &addr[slen],
+                            alen)) )
+           break;
+         oal = oal->next;
+       }
+      if (oal == NULL)
+       {
+         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                     _("Not accepting PONG with address `%s' since I cannot confirm having this address.\n"),
+                     a2s (ve->transport_name,
+                          &addr[slen],
+                          alen));
+         return GNUNET_NO;     
+       }
+      if (GNUNET_OK !=
+         GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING,
+                                   &pong->purpose,
+                                   &pong->signature,
+                                   &ve->publicKey))
+       {
+         GNUNET_break_op (0);
+         return GNUNET_NO;
+       }
 
 #if DEBUG_TRANSPORT
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
-             GNUNET_h2s (key),
-             (ve->addr != NULL) 
-             ? a2s (ve->transport_name,
-                    (const struct sockaddr *) ve->addr,
-                    ve->addrlen)
-             : "<inbound>",
-             ve->transport_name);
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                 "Confirmed that peer `%4s' is talking to us using address `%s' (%s) for us.\n",
+                 GNUNET_h2s (key),
+                 a2s (ve->transport_name,
+                      &addr[slen],
+                      alen),
+                 ve->transport_name);
 #endif
+      break;
+    default:
+      GNUNET_break_op (0);
+      return GNUNET_NO;
+    }
+  if (GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value == 0)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                 _("Received expired signature.  Check system time.\n"));
+      return GNUNET_NO;
+    }
   GNUNET_STATISTICS_update (stats,
                            gettext_noop ("# address validation successes"),
                            1,
@@ -3365,18 +3768,19 @@ check_pending_validation (void *cls,
       GNUNET_STATISTICS_update (stats,
                                gettext_noop ("# peer addresses considered valid"),
                                1,
-                               GNUNET_NO);      
+                               GNUNET_NO);
       fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
       schedule_next_ping (fal);
-      if (n->latency.value == GNUNET_TIME_UNIT_FOREVER_REL.value)
+      if (n->latency.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
        n->latency = fal->latency;
       else
-       n->latency.value = (fal->latency.value + n->latency.value) / 2;
+       n->latency.rel_value = (fal->latency.rel_value + n->latency.rel_value) / 2;
 
       n->distance = fal->distance;
       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))
            {
@@ -3387,8 +3791,7 @@ check_pending_validation (void *cls,
        }
       if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
        {
-         GNUNET_SCHEDULER_cancel (sched,
-                                  n->retry_task);
+         GNUNET_SCHEDULER_cancel (n->retry_task);
          n->retry_task = GNUNET_SCHEDULER_NO_TASK;
          try_transmission_to_peer (n);
        }
@@ -3478,6 +3881,7 @@ transmit_hello_and_ping (void *cls,
   size_t tsize;
   char * message_buf;
   struct GNUNET_PeerIdentity id;
+  size_t slen;
 
   GNUNET_CRYPTO_hash (&va->publicKey,
                      sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
@@ -3502,7 +3906,7 @@ transmit_hello_and_ping (void *cls,
     {
       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                   "Failed to add peer `%4s' for plugin `%s'\n",
-                  GNUNET_i2s (&neighbour->id), 
+                  GNUNET_i2s (&neighbour->id),
                  va->transport_name);
       GNUNET_break (GNUNET_OK ==
                    GNUNET_CONTAINER_multihashmap_remove (validation_map,
@@ -3512,30 +3916,40 @@ transmit_hello_and_ping (void *cls,
       return;
     }
   hello_size = GNUNET_HELLO_size(our_hello);
-  tsize = sizeof(struct TransportPingMessage) + hello_size;
+  slen = strlen(va->transport_name) + 1;
+  tsize = sizeof(struct TransportPingMessage) + hello_size + va->addrlen + slen;
   message_buf = GNUNET_malloc(tsize);
   ping.challenge = htonl(va->challenge);
-  ping.header.size = htons(sizeof(struct TransportPingMessage));
+  ping.header.size = htons(sizeof(struct TransportPingMessage) + slen + va->addrlen);
   ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
   memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
   memcpy(message_buf, our_hello, hello_size);
   memcpy(&message_buf[hello_size],
         &ping,
         sizeof(struct TransportPingMessage));
+  memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
+        va->transport_name,
+        slen);
+  memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
+        &va[1],
+        va->addrlen);
 #if DEBUG_TRANSPORT
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
-              a2s (va->transport_name,
-                  (const void*) &va[1], va->addrlen),
+             (va->addrlen == 0)
+             ? "<inbound>"
+             : a2s (va->transport_name,
+                    (const void*) &va[1], va->addrlen),
              va->transport_name,
              GNUNET_i2s (&neighbour->id),
              "HELLO", hello_size,
-             "PING", sizeof (struct TransportPingMessage));
+             "PING", sizeof (struct TransportPingMessage) + va->addrlen + slen);
 #endif
+
   GNUNET_STATISTICS_update (stats,
                            gettext_noop ("# PING messages sent for initial validation"),
                            1,
-                           GNUNET_NO);      
+                           GNUNET_NO);
   transmit_to_peer (NULL, peer_address,
                    GNUNET_SCHEDULER_PRIORITY_DEFAULT,
                    HELLO_VERIFICATION_TIMEOUT,
@@ -3561,7 +3975,7 @@ static int
 run_validation (void *cls,
                 const char *tname,
                 struct GNUNET_TIME_Absolute expiration,
-                const void *addr, 
+                const void *addr,
                uint16_t addrlen)
 {
   struct CheckHelloValidatedContext *chvc = cls;
@@ -3573,10 +3987,11 @@ run_validation (void *cls,
   struct OwnAddressList *oal;
 
   GNUNET_assert (addr != NULL);
+
   GNUNET_STATISTICS_update (stats,
                            gettext_noop ("# peer addresses scheduled for validation"),
                            1,
-                           GNUNET_NO);      
+                           GNUNET_NO);
   tp = find_transport (tname);
   if (tp == NULL)
     {
@@ -3588,7 +4003,7 @@ run_validation (void *cls,
       GNUNET_STATISTICS_update (stats,
                                gettext_noop ("# peer addresses not validated (plugin not available)"),
                                1,
-                               GNUNET_NO);      
+                               GNUNET_NO);
       return GNUNET_OK;
     }
   /* check if this is one of our own addresses */
@@ -3596,7 +4011,7 @@ run_validation (void *cls,
   while (NULL != oal)
     {
       if ( (oal->addrlen == addrlen) &&
-          (0 == memcmp (oal->addr,
+          (0 == memcmp (&oal[1],
                         addr,
                         addrlen)) )
        {
@@ -3604,7 +4019,7 @@ run_validation (void *cls,
          GNUNET_STATISTICS_update (stats,
                                    gettext_noop ("# peer addresses not validated (loopback)"),
                                    1,
-                                   GNUNET_NO);      
+                                   GNUNET_NO);
          return GNUNET_OK;
        }
       oal = oal->next;
@@ -3619,8 +4034,8 @@ run_validation (void *cls,
     {
 #if DEBUG_TRANSPORT
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "Attempted to validate blacklisted peer `%s' using `%s'!\n", 
-                 GNUNET_i2s(&id), 
+                  "Attempted to validate blacklisted peer `%s' using `%s'!\n",
+                 GNUNET_i2s(&id),
                  tname);
 #endif
       return GNUNET_OK;
@@ -3650,23 +4065,22 @@ run_validation (void *cls,
       GNUNET_STATISTICS_update (stats,
                                gettext_noop ("# peer addresses not validated (in progress)"),
                                1,
-                               GNUNET_NO);      
+                               GNUNET_NO);
       return GNUNET_OK;
     }
   va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
   va->chvc = chvc;
   chvc->ve_count++;
   va->transport_name = GNUNET_strdup (tname);
-  va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
-                                            (unsigned int) -1);
+  va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
+                                            UINT_MAX);
   va->send_time = GNUNET_TIME_absolute_get();
   va->addr = (const void*) &va[1];
   memcpy (&va[1], addr, addrlen);
   va->addrlen = addrlen;
   GNUNET_HELLO_get_key (chvc->hello,
                        &va->publicKey);
-  va->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
-                                                  HELLO_VERIFICATION_TIMEOUT,
+  va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
                                                   &timeout_hello_validation,
                                                   va);
   GNUNET_CONTAINER_multihashmap_put (validation_map,
@@ -3687,13 +4101,13 @@ run_validation (void *cls,
  * @param cls closure
  * @param peer id of the peer, NULL for last call
  * @param h hello message for the peer (can be NULL)
- * @param trust amount of trust we have in the peer (not used)
+ * @param err_msg NULL if successful, otherwise contains error message
  */
 static void
 check_hello_validated (void *cls,
                        const struct GNUNET_PeerIdentity *peer,
-                       const struct GNUNET_HELLO_Message *h, 
-                      uint32_t trust)
+                       const struct GNUNET_HELLO_Message *h,
+                       const char *err_msg)
 {
   struct CheckHelloValidatedContext *chvc = cls;
   struct GNUNET_HELLO_Message *plain_hello;
@@ -3701,10 +4115,20 @@ check_hello_validated (void *cls,
   struct GNUNET_PeerIdentity target;
   struct NeighbourList *n;
 
+  if (err_msg != NULL)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                _("Error in communication with PEERINFO service\n"));
+   /* return; */
+  }
+
   if (peer == NULL)
     {
+      GNUNET_STATISTICS_update (stats,
+                                gettext_noop ("# outstanding peerinfo iterate requests"),
+                                -1,
+                                GNUNET_NO);
       chvc->piter = NULL;
-      chvc->ve_count++;
       if (GNUNET_NO == chvc->hello_known)
        {
          /* notify PEERINFO about the peer now, so that we at least
@@ -3714,11 +4138,11 @@ check_hello_validated (void *cls,
                              sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
                              &target.hashPubKey);
          plain_hello = GNUNET_HELLO_create (&pk,
-                                            NULL, 
+                                            NULL,
                                             NULL);
          GNUNET_PEERINFO_add_peer (peerinfo, plain_hello);
          GNUNET_free (plain_hello);
-#if DEBUG_TRANSPORT || 1
+#if DEBUG_TRANSPORT_HELLO
          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                      "PEERINFO had no `%s' message for peer `%4s', full validation needed.\n",
                      "HELLO",
@@ -3727,10 +4151,10 @@ check_hello_validated (void *cls,
          GNUNET_STATISTICS_update (stats,
                                    gettext_noop ("# new HELLOs requiring full validation"),
                                    1,
-                                   GNUNET_NO);      
+                                   GNUNET_NO);
          GNUNET_HELLO_iterate_addresses (chvc->hello,
-                                         GNUNET_NO, 
-                                         &run_validation, 
+                                         GNUNET_NO,
+                                         &run_validation,
                                          chvc);
        }
       else
@@ -3738,7 +4162,7 @@ check_hello_validated (void *cls,
          GNUNET_STATISTICS_update (stats,
                                    gettext_noop ("# duplicate HELLO (peer known)"),
                                    1,
-                                   GNUNET_NO);      
+                                   GNUNET_NO);
        }
       chvc->ve_count--;
       if (chvc->ve_count == 0)
@@ -3746,13 +4170,13 @@ check_hello_validated (void *cls,
          GNUNET_CONTAINER_DLL_remove (chvc_head,
                                       chvc_tail,
                                       chvc);
-         GNUNET_free (chvc);
+         GNUNET_free (chvc);   
        }
       return;
-    } 
+    }
   if (h == NULL)
     return;
-#if DEBUG_TRANSPORT
+#if DEBUG_TRANSPORT_HELLO
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "PEERINFO had `%s' message for peer `%4s', validating only new addresses.\n",
              "HELLO",
@@ -3762,6 +4186,11 @@ check_hello_validated (void *cls,
   n = find_neighbour (peer);
   if (n != NULL)
     {
+#if DEBUG_TRANSPORT_HELLO
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "Calling hello_iterate_addresses for %s!\n",
+                  GNUNET_i2s (peer));
+#endif
       GNUNET_HELLO_iterate_addresses (h,
                                      GNUNET_NO,
                                      &add_to_foreign_address_list,
@@ -3770,22 +4199,25 @@ check_hello_validated (void *cls,
     }
   else
     {
+#if DEBUG_TRANSPORT_HELLO
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "No existing neighbor record for %s!\n",
+                  GNUNET_i2s (peer));
+#endif
       GNUNET_STATISTICS_update (stats,
                                gettext_noop ("# no existing neighbour record (validating HELLO)"),
                                1,
-                               GNUNET_NO);      
+                               GNUNET_NO);
     }
   GNUNET_STATISTICS_update (stats,
                            gettext_noop ("# HELLO validations (update case)"),
                            1,
-                           GNUNET_NO);      
-  chvc->ve_count++;
+                           GNUNET_NO);
   GNUNET_HELLO_iterate_new_addresses (chvc->hello,
                                      h,
                                      GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME),
-                                     &run_validation, 
+                                     &run_validation,
                                      chvc);
-  chvc->ve_count--;
 }
 
 
@@ -3805,7 +4237,9 @@ process_hello (struct TransportPlugin *plugin,
   const struct GNUNET_HELLO_Message *hello;
   struct CheckHelloValidatedContext *chvc;
   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
-
+#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)))
@@ -3816,26 +4250,47 @@ process_hello (struct TransportPlugin *plugin,
   GNUNET_STATISTICS_update (stats,
                            gettext_noop ("# HELLOs received for validation"),
                            1,
-                           GNUNET_NO);      
+                           GNUNET_NO);
+
   /* first, check if load is too high */
-  if (GNUNET_SCHEDULER_get_load (sched,
-                                GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
+  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);      
+                               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))
     {
+#if DEBUG_TRANSPORT_HELLO
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "Unable to get public key from `%s' for `%4s'!\n",
+                  "HELLO",
+                  GNUNET_i2s (&target));
+#endif
       GNUNET_break_op (0);
       return GNUNET_SYSERR;
     }
+
   GNUNET_CRYPTO_hash (&publicKey,
                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
                       &target.hashPubKey);
+
+#if DEBUG_TRANSPORT_HELLO
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Received `%s' message for `%4s'\n",
+              "HELLO",
+              GNUNET_i2s (&target));
+#endif
+
   if (0 == memcmp (&my_identity,
                   &target,
                   sizeof (struct GNUNET_PeerIdentity)))
@@ -3843,20 +4298,20 @@ process_hello (struct TransportPlugin *plugin,
       GNUNET_STATISTICS_update (stats,
                                gettext_noop ("# HELLOs ignored for validation (is my own HELLO)"),
                                1,
-                               GNUNET_NO);      
-      return GNUNET_OK;      
+                               GNUNET_NO);
+      return GNUNET_OK;
     }
   chvc = chvc_head;
   while (NULL != chvc)
     {
       if (GNUNET_HELLO_equals (hello,
                               chvc->hello,
-                              GNUNET_TIME_absolute_get ()).value > 0)
+                              GNUNET_TIME_absolute_get ()).abs_value > 0)
        {
-#if DEBUG_TRANSPORT
+#if DEBUG_TRANSPORT_HELLO > 2
          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                      "Received duplicate `%s' message for `%4s'; ignored\n",
-                     "HELLO", 
+                     "HELLO",
                      GNUNET_i2s (&target));
 #endif
          return GNUNET_OK; /* validation already pending */
@@ -3866,14 +4321,32 @@ process_hello (struct TransportPlugin *plugin,
                                   GNUNET_HELLO_size(hello)));
       chvc = chvc->next;
     }
-#if DEBUG_TRANSPORT 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Starting validation of `%s' message for `%4s' of size %u\n",
-              "HELLO", 
-             GNUNET_i2s (&target), 
-             GNUNET_HELLO_size(hello));
+
+#if BREAK_TESTS
+  struct NeighbourList *temp_neighbor = find_neighbour(&target);
+  if ((NULL != temp_neighbor))
+    {
+      fprintf(stderr, "Already know peer, ignoring hello\n");
+      return GNUNET_OK;
+    }
+#endif
+
+#if DEBUG_TRANSPORT_HELLO > 2
+  if (plugin != NULL)
+    {
+      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,
+                  "HELLO",
+                  GNUNET_i2s (&target),
+                  plugin->short_name,
+                  GNUNET_HELLO_size(hello));
+      GNUNET_free(my_id);
+    }
 #endif
   chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
+  chvc->ve_count = 1;
   chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
   memcpy (&chvc[1], hello, hsize);
   GNUNET_CONTAINER_DLL_insert (chvc_head,
@@ -3881,9 +4354,16 @@ process_hello (struct TransportPlugin *plugin,
                               chvc);
   /* finally, check if HELLO was previously validated
      (continuation will then schedule actual validation) */
+  GNUNET_STATISTICS_update (stats,
+                            gettext_noop ("# peerinfo process hello iterate requests"),
+                            1,
+                            GNUNET_NO);
+  GNUNET_STATISTICS_update (stats,
+                            gettext_noop ("# outstanding peerinfo iterate requests"),
+                            1,
+                            GNUNET_NO);
   chvc->piter = GNUNET_PEERINFO_iterate (peerinfo,
                                          &target,
-                                         0,
                                          HELLO_VERIFICATION_TIMEOUT,
                                          &check_hello_validated, chvc);
   return GNUNET_OK;
@@ -3899,9 +4379,9 @@ process_hello (struct TransportPlugin *plugin,
  * gone.
  *
  * @param n the neighbour list entry for the peer
- * @param check should we just check if all plugins
- *        disconnected or must we ask all plugins to
- *        disconnect?
+ * @param check GNUNET_YES to check if ALL addresses for this peer
+ *              are gone, GNUNET_NO to force a disconnect of the peer
+ *              regardless of whether other addresses exist.
  */
 static void
 disconnect_neighbour (struct NeighbourList *n, int check)
@@ -3922,7 +4402,12 @@ disconnect_neighbour (struct NeighbourList *n, int check)
           while (peer_addresses != NULL)
             {
               if (GNUNET_YES == peer_addresses->connected)
-                return;             /* still connected */
+                {
+                  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                            "NOT Disconnecting from `%4s', still have live addresses!\n",
+                            GNUNET_i2s (&n->id));
+                  return;             /* still connected */
+                }
               peer_addresses = peer_addresses->next;
             }
           rpos = rpos->next;
@@ -3964,16 +4449,15 @@ disconnect_neighbour (struct NeighbourList *n, int check)
            GNUNET_STATISTICS_update (stats,
                                      gettext_noop ("# connected addresses"),
                                      -1,
-                                     GNUNET_NO); 
+                                     GNUNET_NO);
          if (GNUNET_YES == peer_pos->validated)
            GNUNET_STATISTICS_update (stats,
                                      gettext_noop ("# peer addresses considered valid"),
                                      -1,
-                                     GNUNET_NO);      
+                                     GNUNET_NO);
          if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
            {
-             GNUNET_SCHEDULER_cancel (sched,
-                                      peer_pos->revalidate_task);
+             GNUNET_SCHEDULER_cancel (peer_pos->revalidate_task);
              peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
            }
           GNUNET_free(peer_pos);
@@ -3995,24 +4479,28 @@ disconnect_neighbour (struct NeighbourList *n, int check)
       GNUNET_CONTAINER_DLL_remove (n->messages_head,
                                   n->messages_tail,
                                   mq);
-      GNUNET_assert (0 == memcmp(&mq->neighbour_id, 
+      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 (sched, n->timeout_task);
+      GNUNET_SCHEDULER_cancel (n->timeout_task);
       n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
     }
   if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
     {
-      GNUNET_SCHEDULER_cancel (sched, n->retry_task);
+      GNUNET_SCHEDULER_cancel (n->retry_task);
       n->retry_task = GNUNET_SCHEDULER_NO_TASK;
     }
   if (n->piter != NULL)
     {
       GNUNET_PEERINFO_iterate_cancel (n->piter);
+      GNUNET_STATISTICS_update (stats,
+                                gettext_noop ("# outstanding peerinfo iterate requests"),
+                                -1,
+                                GNUNET_NO);
       n->piter = NULL;
     }
   /* finally, free n itself */
@@ -4027,22 +4515,28 @@ disconnect_neighbour (struct NeighbourList *n, int check)
 
 /**
  * We have received a PING message from someone.  Need to send a PONG message
- * in response to the peer by any means necessary. 
+ * in response to the peer by any means necessary.
  */
-static int 
+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)
 {
   struct TransportPlugin *plugin = cls;
+  struct SessionHeader *session_header = (struct SessionHeader*) session;
   struct TransportPingMessage *ping;
   struct TransportPongMessage *pong;
   struct NeighbourList *n;
   struct ReadyList *rl;
   struct ForeignAddressList *fal;
+  struct OwnAddressList *oal;
+  const char *addr;
+  size_t alen;
+  size_t slen;
 
-  if (ntohs (message->size) != sizeof (struct TransportPingMessage))
+  if (ntohs (message->size) < sizeof (struct TransportPingMessage))
     {
       GNUNET_break_op (0);
       return GNUNET_SYSERR;
@@ -4053,18 +4547,24 @@ handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
                    plugin->env.my_identity,
                    sizeof (struct GNUNET_PeerIdentity)))
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                  _("Received `%s' message not destined for me!\n"), 
-                 "PING");
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  _("Received `%s' message from `%s' destined for `%s' which is not me!\n"),
+                 "PING",
+                 (sender_address != NULL)
+                 ? a2s (plugin->short_name,
+                        (const struct sockaddr *)sender_address,
+                        sender_address_len)
+                 : "<inbound>",
+                 GNUNET_i2s (&ping->target));
       return GNUNET_SYSERR;
     }
 #if DEBUG_PING_PONG
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
              "Processing `%s' from `%s'\n",
-             "PING", 
-             (sender_address != NULL) 
+             "PING",
+             (sender_address != NULL)
              ? a2s (plugin->short_name,
-                    (const struct sockaddr *)sender_address, 
+                    (const struct sockaddr *)sender_address,
                     sender_address_len)
              : "<inbound>");
 #endif
@@ -4072,26 +4572,144 @@ handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
                            gettext_noop ("# PING messages received"),
                            1,
                            GNUNET_NO);
-  pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len);
-  pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len);
-  pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
-  pong->purpose.size =
-    htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
-           sizeof (uint32_t) +
-           sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + sender_address_len);
-  pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PING);
-  pong->challenge = ping->challenge;
-  pong->addrlen = htons(sender_address_len);
-  memcpy(&pong->signer, 
-        &my_public_key, 
-        sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
-  if (sender_address != NULL)
-    memcpy (&pong[1], sender_address, sender_address_len);
-#if SIGN_USELESS
-  GNUNET_assert (GNUNET_OK ==
-                 GNUNET_CRYPTO_rsa_sign (my_private_key,
-                                         &pong->purpose, &pong->signature));
+  addr = (const char*) &ping[1];
+  alen = ntohs (message->size) - sizeof (struct TransportPingMessage);
+  slen = strlen (plugin->short_name) + 1;
+  if (alen == 0)
+    {
+      /* peer wants to confirm that we have an outbound connection to him */
+      if (session == NULL)
+       {
+         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                     _("Refusing to create PONG since I do not have a session with `%s'.\n"),
+                     GNUNET_i2s (peer));
+         return GNUNET_SYSERR;
+       }
+      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);
+      pong->purpose.size =
+       htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
+              sizeof (uint32_t) +
+              sizeof (struct GNUNET_TIME_AbsoluteNBO) +
+              sizeof (struct GNUNET_PeerIdentity) + sender_address_len + slen);
+      pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING);
+      pong->challenge = ping->challenge;
+      pong->addrlen = htonl(sender_address_len + slen);
+      memcpy(&pong->pid,
+            peer,
+            sizeof(struct GNUNET_PeerIdentity));
+      memcpy (&pong[1],
+             plugin->short_name,
+             slen);
+      if ((sender_address!=NULL) && (sender_address_len > 0))
+                 memcpy (&((char*)&pong[1])[slen],
+                         sender_address,
+                         sender_address_len);
+      if (GNUNET_TIME_absolute_get_remaining (session_header->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4)
+       {
+         /* create / update cached sig */
+#if DEBUG_TRANSPORT
+         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                     "Creating PONG signature to indicate active connection.\n");
 #endif
+         session_header->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
+         pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
+         GNUNET_assert (GNUNET_OK ==
+                        GNUNET_CRYPTO_rsa_sign (my_private_key,
+                                                &pong->purpose,
+                                                &session_header->pong_signature));
+       }
+      else
+       {
+         pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
+       }
+      memcpy (&pong->signature,
+             &session_header->pong_signature,
+             sizeof (struct GNUNET_CRYPTO_RsaSignature));
+
+
+    }
+  else
+    {
+      /* peer wants to confirm that this is one of our addresses */
+      addr += slen;
+      alen -= slen;
+      if (GNUNET_OK !=
+         plugin->api->check_address (plugin->api->cls,
+                                     addr,
+                                     alen))
+       {
+         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                     _("Not confirming PING with address `%s' since I cannot confirm having this address.\n"),
+                     a2s (plugin->short_name,
+                          addr,
+                          alen));
+         return GNUNET_NO;
+       }
+      oal = plugin->addresses;
+      while (NULL != oal)
+       {
+         if ( (oal->addrlen == alen) &&
+              (0 == memcmp (addr,
+                            &oal[1],
+                            alen)) )
+           break;
+         oal = oal->next;
+       }
+      pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + alen + slen);
+      pong->header.size = htons (sizeof (struct TransportPongMessage) + alen + slen);
+      pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
+      pong->purpose.size =
+       htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
+              sizeof (uint32_t) +
+              sizeof (struct GNUNET_TIME_AbsoluteNBO) +
+              sizeof (struct GNUNET_PeerIdentity) + alen + slen);
+      pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN);
+      pong->challenge = ping->challenge;
+      pong->addrlen = htonl(alen + slen);
+      memcpy(&pong->pid,
+            &my_identity,
+            sizeof(struct GNUNET_PeerIdentity));
+      memcpy (&pong[1], plugin->short_name, slen);
+      memcpy (&((char*)&pong[1])[slen], addr, alen);
+      if ( (oal != NULL) &&
+          (GNUNET_TIME_absolute_get_remaining (oal->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4) )
+       {
+         /* create / update cached sig */
+#if DEBUG_TRANSPORT
+         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));
+         pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
+         GNUNET_assert (GNUNET_OK ==
+                        GNUNET_CRYPTO_rsa_sign (my_private_key,
+                                                &pong->purpose,
+                                                &oal->pong_signature));        
+         memcpy (&pong->signature,
+                 &oal->pong_signature,
+                 sizeof (struct GNUNET_CRYPTO_RsaSignature));
+       }
+      else if (oal == NULL)
+       {
+         /* not using cache (typically DV-only) */
+         pong->expiration = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
+         GNUNET_assert (GNUNET_OK ==
+                        GNUNET_CRYPTO_rsa_sign (my_private_key,
+                                                &pong->purpose,
+                                                &pong->signature));    
+       }
+      else
+       {
+         /* can used cached version */
+         pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
+         memcpy (&pong->signature,
+                 &oal->pong_signature,
+                 sizeof (struct GNUNET_CRYPTO_RsaSignature));
+       }
+    }
   n = find_neighbour(peer);
   GNUNET_assert (n != NULL);
   /* first try reliable response transmission */
@@ -4105,7 +4723,7 @@ handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
                                           peer,
                                           (const char*) pong,
                                           ntohs (pong->header.size),
-                                          TRANSPORT_PONG_PRIORITY, 
+                                          TRANSPORT_PONG_PRIORITY,
                                           HELLO_VERIFICATION_TIMEOUT,
                                           fal->session,
                                           fal->addr,
@@ -4117,7 +4735,7 @@ handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
              GNUNET_STATISTICS_update (stats,
                                        gettext_noop ("# PONGs unicast via reliable transport"),
                                        1,
-                                       GNUNET_NO);      
+                                       GNUNET_NO);
              GNUNET_free (pong);
              return GNUNET_OK;
            }
@@ -4129,7 +4747,7 @@ handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
   GNUNET_STATISTICS_update (stats,
                            gettext_noop ("# PONGs multicast to all available addresses"),
                            1,
-                           GNUNET_NO);      
+                           GNUNET_NO);
   rl = n->plugins;
   while (rl != NULL)
     {
@@ -4137,11 +4755,11 @@ handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
       while (fal != NULL)
        {
          transmit_to_peer(NULL, fal,
-                          TRANSPORT_PONG_PRIORITY, 
+                          TRANSPORT_PONG_PRIORITY,
                           HELLO_VERIFICATION_TIMEOUT,
-                          (const char *)pong, 
-                          ntohs(pong->header.size), 
-                          GNUNET_YES, 
+                          (const char *)pong,
+                          ntohs(pong->header.size),
+                          GNUNET_YES,
                           n);
          fal = fal->next;
        }
@@ -4162,19 +4780,21 @@ handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
  * @param peer (claimed) identity of the other peer
  * @param message the message, NULL if we only care about
  *                learning about the delay until we should receive again
- * @param distance in overlay hops; use 1 unless DV (or 0 if message == NULL)
+ * @param ats_data information for automatic transport selection
+ * @param ats_count number of elements in ats not including 0-terminator
  * @param session identifier used for this session (can be NULL)
  * @param sender_address binary address of the sender (if observed)
  * @param sender_address_len number of bytes in sender_address
- * @return how long the plugin should wait until receiving more data
+ * @return how long in ms the plugin should wait until receiving more data
  *         (plugins that do not support this, can ignore the return value)
  */
 static struct GNUNET_TIME_Relative
 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
                     const struct GNUNET_MessageHeader *message,
-                    uint32_t distance,
-                   struct Session *session,
-                   const char *sender_address,
+                    const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
+                    uint32_t ats_count,
+                    struct Session *session,
+                    const char *sender_address,
                     uint16_t sender_address_len)
 {
   struct TransportPlugin *plugin = cls;
@@ -4183,9 +4803,10 @@ plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
   uint16_t msize;
   struct NeighbourList *n;
   struct GNUNET_TIME_Relative ret;
-
   if (is_blacklisted (peer, plugin))
     return GNUNET_TIME_UNIT_FOREVER_REL;
+  uint32_t distance;
+  int c;
 
   n = find_neighbour (peer);
   if (n == NULL)
@@ -4195,15 +4816,26 @@ plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
     service_context = service_context->next;
   GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
   peer_address = NULL;
+  distance = 1;
+  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)
     {
       if ( (session != NULL) ||
           (sender_address != NULL) )
-       peer_address = add_peer_address (n, 
+       peer_address = add_peer_address (n,
                                         plugin->short_name,
                                         session,
-                                        sender_address, 
-                                        sender_address_len);  
+                                        sender_address,
+                                        sender_address_len);
       if (peer_address != NULL)
        {
          peer_address->distance = distance;
@@ -4216,7 +4848,7 @@ plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
          schedule_next_ping (peer_address);
        }
       /* update traffic received amount ... */
-      msize = ntohs (message->size);      
+      msize = ntohs (message->size);
       GNUNET_STATISTICS_update (stats,
                                gettext_noop ("# bytes received from other peers"),
                                msize,
@@ -4225,11 +4857,9 @@ plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
       n->peer_timeout =
        GNUNET_TIME_relative_to_absolute
        (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
-      GNUNET_SCHEDULER_cancel (sched,
-                              n->timeout_task);
+      GNUNET_SCHEDULER_cancel (n->timeout_task);
       n->timeout_task =
-       GNUNET_SCHEDULER_add_delayed (sched,
-                                     GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
+       GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
                                      &neighbour_timeout_task, n);
       if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
        {
@@ -4237,7 +4867,7 @@ plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
          GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
                      GNUNET_ERROR_TYPE_BULK,
                      _
-                     ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"), 
+                     ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
                      n->in_tracker.available_bytes_per_s__,
                      n->quota_violation_count);
          GNUNET_STATISTICS_update (stats,
@@ -4246,10 +4876,13 @@ plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
                                    GNUNET_NO);
          return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
        }
+
 #if DEBUG_PING_PONG
           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                      "Received message of type %u from `%4s', sending to all clients.\n",
-                      ntohs (message->type), GNUNET_i2s (peer));
+                      "Received message of type %u and size %u from `%4s', sending to all clients.\n",
+                      ntohs (message->type),
+                      ntohs (message->size),
+                     GNUNET_i2s (peer));
 #endif
       switch (ntohs (message->type))
        {
@@ -4261,7 +4894,7 @@ plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
          process_hello (plugin, message);
          break;
        case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
-         handle_ping (plugin, message, peer, sender_address, sender_address_len);
+         handle_ping (plugin, message, peer, session, sender_address, sender_address_len);
          break;
        case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
          handle_pong (plugin, message, peer, sender_address, sender_address_len);
@@ -4270,19 +4903,19 @@ plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
          handle_payload_message (message, n);
          break;
        }
-    }  
+    }
   ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
-  if (ret.value > 0)
+  if (ret.rel_value > 0)
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                  "Throttling read (%llu bytes excess at %u b/s), waiting %llums before reading more.\n",
                  (unsigned long long) n->in_tracker.consumption_since_last_update__,
                  (unsigned int) n->in_tracker.available_bytes_per_s__,
-                 (unsigned long long) ret.value);
+                 (unsigned long long) ret.rel_value);
       GNUNET_STATISTICS_update (stats,
                                gettext_noop ("# ms throttling suggested"),
-                               (int64_t) ret.value,
-                               GNUNET_NO);      
+                               (int64_t) ret.rel_value,
+                               GNUNET_NO);
     }
   return ret;
 }
@@ -4300,10 +4933,14 @@ handle_start (void *cls,
               struct GNUNET_SERVER_Client *client,
               const struct GNUNET_MessageHeader *message)
 {
+  const struct StartMessage *start;
   struct TransportClient *c;
-  struct ConnectInfoMessage cim;
+  struct ConnectInfoMessage cim;
   struct NeighbourList *n;
+  uint32_t ats_count;
+  size_t size;
 
+  start = (const struct StartMessage*) message;
 #if DEBUG_TRANSPORT
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Received `%s' request from client\n", "START");
@@ -4320,12 +4957,23 @@ handle_start (void *cls,
         }
       c = c->next;
     }
+  if ( (GNUNET_NO != ntohl (start->do_check)) &&
+       (0 != memcmp (&start->self,
+                    &my_identity,
+                    sizeof (struct GNUNET_PeerIdentity))) )
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                 _("Rejecting control connection from peer `%s', which is not me!\n"),
+                 GNUNET_i2s (&start->self));
+      GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+      return;
+    }
   c = GNUNET_malloc (sizeof (struct TransportClient));
   c->next = clients;
   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");
@@ -4334,21 +4982,34 @@ handle_start (void *cls,
                           (const struct GNUNET_MessageHeader *) our_hello,
                           GNUNET_NO);
       /* tell new client about all existing connections */
-      cim.header.size = htons (sizeof (struct ConnectInfoMessage));
-      cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
-      n = neighbours; 
+      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.id = n->id;
-             cim.latency = GNUNET_TIME_relative_hton (n->latency);
-             cim.distance = htonl (n->distance);
-             transmit_to_client (c, &cim.header, GNUNET_NO);
-            }
+         {
+                 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_SERVER_receive_done (client, GNUNET_OK);
 }
 
@@ -4370,7 +5031,7 @@ handle_hello (void *cls,
   GNUNET_STATISTICS_update (stats,
                            gettext_noop ("# HELLOs received from clients"),
                            1,
-                           GNUNET_NO);      
+                           GNUNET_NO);
   ret = process_hello (NULL, message);
   GNUNET_SERVER_receive_done (client, ret);
 }
@@ -4380,7 +5041,7 @@ handle_hello (void *cls,
  * Closure for 'transmit_client_message'; followed by
  * 'msize' bytes of the actual message.
  */
-struct TransmitClientMessageContext 
+struct TransmitClientMessageContext
 {
   /**
    * Client on whom's behalf we are sending.
@@ -4391,7 +5052,7 @@ struct TransmitClientMessageContext
    * Timeout for the transmission.
    */
   struct GNUNET_TIME_Absolute timeout;
-  
+
   /**
    * Message priority.
    */
@@ -4399,7 +5060,7 @@ struct TransmitClientMessageContext
 
   /**
    * Size of the message in bytes.
-   */ 
+   */
   uint16_t msize;
 };
 
@@ -4423,7 +5084,7 @@ transmit_client_message (void *cls,
 
   if (n != NULL)
     {
-      transmit_to_peer (tc, NULL, tcmc->priority, 
+      transmit_to_peer (tc, NULL, tcmc->priority,
                        GNUNET_TIME_absolute_get_remaining (tcmc->timeout),
                        (char *)&tcmc[1],
                        tcmc->msize, GNUNET_NO, n);
@@ -4463,22 +5124,23 @@ handle_send (void *cls,
   GNUNET_STATISTICS_update (stats,
                            gettext_noop ("# payload received for other peers"),
                            size,
-                           GNUNET_NO);      
+                           GNUNET_NO);
   obm = (const struct OutboundMessage *) message;
   obmm = (const struct GNUNET_MessageHeader *) &obm[1];
   msize = size - sizeof (struct OutboundMessage);
-#if DEBUG_TRANSPORT
+
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Received `%s' request from client with target `%4s' and message of type %u and size %u\n",
               "SEND", GNUNET_i2s (&obm->peer),
               ntohs (obmm->type),
               msize);
-#endif
+
   tcmc = GNUNET_malloc (sizeof (struct TransmitClientMessageContext) + msize);
   tcmc->client = client;
   tcmc->priority = ntohl (obm->priority);
   tcmc->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
   tcmc->msize = msize;
+  /* FIXME: this memcpy can be up to 7% of our total runtime */
   memcpy (&tcmc[1], obmm, msize);
   GNUNET_SERVER_client_keep (client);
   setup_peer_check_blacklist (&obm->peer, GNUNET_YES,
@@ -4487,6 +5149,31 @@ handle_send (void *cls,
 }
 
 
+/**
+ * Handle request connect message
+ *
+ * @param cls closure (always NULL)
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_request_connect (void *cls,
+                        struct GNUNET_SERVER_Client *client,
+                        const struct GNUNET_MessageHeader *message)
+{
+  const struct TransportRequestConnectMessage *trcm =
+    (const struct TransportRequestConnectMessage *) message;
+
+  GNUNET_STATISTICS_update (stats,
+                            gettext_noop ("# REQUEST CONNECT messages received"),
+                            1,
+                            GNUNET_NO);
+  GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Received a request connect message for peer %s\n", GNUNET_i2s(&trcm->peer));
+  setup_peer_check_blacklist (&trcm->peer, GNUNET_YES,
+                              NULL, NULL);
+  GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
 /**
  * Handle SET_QUOTA-message.
  *
@@ -4502,11 +5189,11 @@ handle_set_quota (void *cls,
   const struct QuotaSetMessage *qsm =
     (const struct QuotaSetMessage *) message;
   struct NeighbourList *n;
-  
+
   GNUNET_STATISTICS_update (stats,
                            gettext_noop ("# SET QUOTA messages received"),
                            1,
-                           GNUNET_NO);      
+                           GNUNET_NO);
   n = find_neighbour (&qsm->peer);
   if (n == NULL)
     {
@@ -4514,29 +5201,34 @@ handle_set_quota (void *cls,
       GNUNET_STATISTICS_update (stats,
                                gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
                                1,
-                               GNUNET_NO);      
+                               GNUNET_NO);
       return;
     }
 #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", 
+              "SET_QUOTA",
              (unsigned int) ntohl (qsm->quota.value__),
              (unsigned int) n->in_tracker.available_bytes_per_s__,
              GNUNET_i2s (&qsm->peer));
 #endif
   GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
                                         qsm->quota);
-  if (0 == ntohl (qsm->quota.value__)) 
-    disconnect_neighbour (n, GNUNET_NO);    
+  if (0 == ntohl (qsm->quota.value__))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&n->id),
+                "SET_QUOTA");
+      disconnect_neighbour (n, GNUNET_NO);
+    }
   GNUNET_SERVER_receive_done (client, GNUNET_OK);
 }
 
 
 /**
- * Take the given address and append it to the set of results send back to
+ * Take the given address and append it to the set of results sent back to
  * the client.
- * 
+ *
  * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
  * @param address the resolved name, NULL to indicate the last response
  */
@@ -4550,6 +5242,7 @@ transmit_address_to_client (void *cls, const char *address)
     slen = 0;
   else
     slen = strlen (address) + 1;
+
   GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
                                              GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
   if (NULL == address)
@@ -4618,35 +5311,12 @@ handle_address_lookup (void *cls,
   tc = GNUNET_SERVER_transmit_context_create (client);
   lsPlugin->api->address_pretty_printer (lsPlugin->api->cls,
                                         nameTransport,
-                                         address, addressLen, 
+                                         address, addressLen,
                                         numeric,
                                          rtimeout,
                                          &transmit_address_to_client, tc);
 }
 
-/**
- * List of handlers for the messages understood by this
- * service.
- */
-static struct GNUNET_SERVER_MessageHandler handlers[] = {
-  {&handle_start, NULL,
-   GNUNET_MESSAGE_TYPE_TRANSPORT_START, 0},
-  {&handle_hello, NULL,
-   GNUNET_MESSAGE_TYPE_HELLO, 0},
-  {&handle_send, NULL,
-   GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
-  {&handle_set_quota, NULL,
-   GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
-  {&handle_address_lookup, NULL,
-   GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
-   0},
-  {&handle_blacklist_init, NULL,
-   GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT, sizeof (struct GNUNET_MessageHeader)},
-  {&handle_blacklist_reply, NULL,
-   GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY, sizeof (struct BlacklistMessage)},
-  {NULL, NULL, 0, 0}
-};
-
 
 /**
  * Setup the environment for this plugin.
@@ -4655,8 +5325,8 @@ static void
 create_environment (struct TransportPlugin *plug)
 {
   plug->env.cfg = cfg;
-  plug->env.sched = sched;
   plug->env.my_identity = &my_identity;
+  plug->env.our_hello = &our_hello;
   plug->env.cls = plug;
   plug->env.receive = &plugin_env_receive;
   plug->env.notify_address = &plugin_env_notify_address;
@@ -4670,7 +5340,7 @@ create_environment (struct TransportPlugin *plug)
  * Start the specified transport (load the plugin).
  */
 static void
-start_transport (struct GNUNET_SERVER_Handle *server, 
+start_transport (struct GNUNET_SERVER_Handle *server,
                 const char *name)
 {
   struct TransportPlugin *plug;
@@ -4736,11 +5406,10 @@ client_disconnect_notification (void *cls,
                  if (bc->th != NULL)
                    {
                      GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th);
-                     bc->th = NULL;                  
+                     bc->th = NULL;            
                    }
                  if (bc->task == GNUNET_SCHEDULER_NO_TASK)
-                   bc->task = GNUNET_SCHEDULER_add_now (sched,
-                                                        &do_blacklist_check,
+                   bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
                                                         bc);
                  break;
                }
@@ -4807,7 +5476,12 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
   struct CheckHelloValidatedContext *chvc;
 
   while (neighbours != NULL)
-    disconnect_neighbour (neighbours, GNUNET_NO);
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&neighbours->id),
+              "SHUTDOWN_TASK");
+      disconnect_neighbour (neighbours, GNUNET_NO);
+    }
 #if DEBUG_TRANSPORT
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Transport service is unloading plugins...\n");
@@ -4817,8 +5491,7 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
       plugins = plug->next;
       if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
        {
-         GNUNET_SCHEDULER_cancel (plug->env.sched, 
-                                  plug->address_update_task);
+         GNUNET_SCHEDULER_cancel (plug->address_update_task);
          plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
        }
       GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
@@ -4841,12 +5514,20 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
   GNUNET_CONTAINER_multihashmap_destroy (validation_map);
   validation_map = NULL;
 
+  ats_shutdown(ats);
+
   /* free 'chvc' data structure */
   while (NULL != (chvc = chvc_head))
     {
       chvc_head = chvc->next;
       if (chvc->piter != NULL)
-       GNUNET_PEERINFO_iterate_cancel (chvc->piter);      
+        {
+          GNUNET_PEERINFO_iterate_cancel (chvc->piter);
+          GNUNET_STATISTICS_update (stats,
+                                    gettext_noop ("# outstanding peerinfo iterate requests"),
+                                    -1,
+                                    GNUNET_NO);
+        }
       else
        GNUNET_break (0);
       GNUNET_assert (chvc->ve_count == 0);
@@ -4870,30 +5551,595 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
   GNUNET_break (bc_head == NULL);
 }
 
+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;
+       double c_max;
+       double c_1;
+};
+
+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;
+};
+
+
+static void ats_create_problem (int max_it, int max_dur )
+{
+#if !HAVE_LIBGLPK
+       if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "no glpk installed\n");
+       return;
+#else
+       if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "glpk installed\n");
+#endif
+
+       glp_prob *prob;
+
+       int c_peers = 0;
+       int c_mechs = 0;
+
+       int c_c_ressources = 0;
+       int c_q_metrics = 0;
+
+       double v_b_min = 100;
+       double v_n_min = 2;
+       double M = 1000000000;
+
+       struct NeighbourList *next = neighbours;
+       while (next!=NULL)
+       {
+               struct ReadyList *r_next = next->plugins;
+               while (r_next != NULL)
+               {
+                       struct ForeignAddressList * a_next = r_next->addresses;
+                       while (a_next != NULL)
+                       {
+                               c_mechs++;
+                               a_next = a_next->next;
+                       }
+                       r_next = r_next->next;
+               }
+               next = next->next;
+               c_peers++;
+       }
+
+       if (c_mechs==0)
+       {
+               GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No addresses for bw distribution available\n", c_peers);
+               return;
+       }
+
+       struct ATS_mechanism * mechanisms = GNUNET_malloc((1+c_mechs) * sizeof (struct ATS_mechanism));
+       struct ATS_peer * peers = GNUNET_malloc((1+c_peers) * sizeof (struct ATS_peer));
+
+       if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found mechanisms: %i\n", c_mechs);
+       c_mechs = 1;
+       c_peers = 1;
+       next = neighbours;
+       while (next!=NULL)
+       {
+               peers[c_peers].peer = next->id;
+               peers[c_peers].m_head = NULL;
+               peers[c_peers].m_tail = NULL;
+
+               struct ReadyList *r_next = next->plugins;
+               while (r_next != NULL)
+               {
+                       struct ForeignAddressList * a_next = r_next->addresses;
+                       while (a_next != NULL)
+                       {
+                               if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%i Peer: `%s' %x:\n", c_mechs, GNUNET_i2s(&next->id),
+                                                                                               a_next);
+                               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;
+
+                               GNUNET_CONTAINER_DLL_insert_tail(peers[c_peers].m_head, peers[c_peers].m_tail, &mechanisms[c_mechs]);
+                               c_mechs++;
+                               a_next = a_next->next;
+                       }
+                       r_next = r_next->next;
+               }
+               c_peers++;
+               next = next->next;
+       }
+       c_mechs--;
+       c_peers--;
+
+       /* number of variables == coloumns */
+       //int c_cols = 2 * c_mechs + 3 + c_q_metrics;
+       /* number of constraints == rows */
+       //int c_rows = 2 * c_peers + 2 * c_mechs + c_c_ressources + c_q_metrics + 3;
+
+       if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Creating problem with: %i peers, %i mechanisms\n", c_peers, c_mechs);
+
+       int size = 6 *c_mechs;
+       int row_index;
+       int array_index=0;
+       int * ia = GNUNET_malloc (size * sizeof (int));
+       int * ja = GNUNET_malloc (size * sizeof (int));
+       double * ar = GNUNET_malloc(size* sizeof (double));
+
+       prob = glp_create_prob();
+       glp_set_prob_name(prob, "gnunet ats bandwidth distribution");
+       glp_set_obj_dir(prob, GLP_MAX);
+
+       /* adding columns */
+       int c;
+       char * name;
+       glp_add_cols(prob, 2 * c_mechs);
+       for (c=1; c <= c_mechs; c++)
+       {
+               GNUNET_asprintf(&name, "b%i",c);
+               glp_set_col_name(prob, c, name);
+               GNUNET_free (name);
+               glp_set_col_bnds(prob, c, GLP_LO, 0.0, 0.0);
+               glp_set_obj_coef(prob, c, 1.0);
+
+       }
+       for (c=c_mechs; c <= 2*c_mechs; c++)
+       {
+               GNUNET_asprintf(&name, "n%i",c);
+               glp_set_col_name(prob, c, "n1");
+               glp_set_col_bnds(prob, c, GLP_LO, 0.0, 0.0);
+               glp_set_col_bnds(prob, c, GLP_LO, 0.0, 1.0);
+               glp_set_col_kind(prob, c, GLP_IV);
+               glp_set_obj_coef(prob, c, 1.0);
+               GNUNET_free (name);
+       }
+
+       /* feasibility constraints */
+       /* one address per peer*/
+       if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 1\n");
+       row_index = 1;
+       glp_add_rows(prob, c_peers);
+       for (c=1; c<=c_peers; c++)
+       {
+               glp_set_row_bnds(prob, row_index, GLP_DB, 0.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]);
+                       array_index++;
+                       m = m->next;
+               }
+               row_index++;
+       }
+       GNUNET_assert (row_index-1==c_peers);
+       GNUNET_assert (array_index==c_mechs);
+
+       /* Constraint 1: only active mechanism gets bandwidth assigned */
+       if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 2\n");
+       glp_add_rows(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);
+               glp_set_row_bnds(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]);
+               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]);
+               array_index++;
+               row_index ++;
+       }
+       GNUNET_assert (row_index-1==c_peers+c_mechs);
+       GNUNET_assert (array_index==c_mechs+(2*c_mechs));
+
+       /* Constraint 3: minimum bandwidth*/
+       if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 3\n");
+       glp_add_rows(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);
+               glp_set_row_bnds(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]);
+               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]);
+               array_index++;
+               row_index ++;
+       }
+       GNUNET_assert (row_index-1==c_peers+(2*c_mechs));
+       GNUNET_assert (array_index==c_mechs+(4*c_mechs));
+
+       /* Constraint 4: max ressource capacity */
+       /*
+       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 3\n");
+       glp_add_rows(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);
+               glp_set_row_bnds(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]);
+               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]);
+               array_index++;
+               row_index ++;
+       }
+       GNUNET_assert (row_index-1==c_peers+(2*c_mechs));
+       GNUNET_assert (array_index==5*c_mechs);
+       */
+
+       /* Constraint 5: min number of connections*/
+       if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 5\n");
+       glp_add_rows(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);
+               glp_set_row_bnds(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]);
+               array_index++;
+       }
+       row_index ++;
+       GNUNET_assert (row_index-1==c_peers+(2*c_mechs)+1);
+       GNUNET_assert (array_index==6*c_mechs);
+
+       glp_load_matrix(prob, array_index-1, ia, ja, ar);
+
+       glp_delete_prob(prob);
+
+       /* clean up */
+
+       GNUNET_free (ja);
+       GNUNET_free (ia);
+       GNUNET_free (ar);
+
+       GNUNET_free(mechanisms);
+       GNUNET_free(peers);
+}
+
+/* To remove: just for testing */
+void ats_benchmark (int peers, int transports, int start_peers, int end_peers)
+{
+       struct GNUNET_TIME_Absolute start;
+       struct GNUNET_TIME_Relative duration;
+/*
+       int test = 11;
+       int mlp = GNUNET_NO;
+
+       for (test=start_peers; test<=end_peers; test++)
+       {
+       int peers = test;
+       int transports = 3;
+
+       double b_min   = 5;
+       double b_max   = 50;
+       double r           = 0.85;//1.0;
+       double R           = 1.0;
+
+       int it = ATS_MAX_ITERATIONS;
+       int dur = 500;
+       if (INT_MAX < ats->max_exec_duration.rel_value)
+               dur = INT_MAX;
+       else
+               dur = (int) ats->max_exec_duration.rel_value;
+
+
+       struct ATS_mechanism * tl = GNUNET_malloc(transports * sizeof (struct ATS_peer));
+
+       struct ATS_peer * pl = GNUNET_malloc(peers * sizeof (struct ATS_peer));
+       int c = 0;
+       while (c < peers)
+       {
+               pl[c].peer.hashPubKey.bits[0] = c+1;
+               pl[c].f = 1 / (double) peers ;
+               pl[c].t = 1;
+               //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_calculate_bandwidth_distribution Peer[%i] : %s %p \n",c , GNUNET_i2s(&pl[c].peer), &pl[c].peer);
+               c++;
+       }
+       c = 0;
+       while (c < transports)
+       {
+               tl[c].id = c;
+               tl[c].c_max = 10000;
+               tl[c].c_1 = 1;
+               //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_calculate_bandwidth_distribution Peer[%i] : %i \n",c , tl[c].id);
+               c++;
+
+       }
+
+       // test //
+
+       //pl[0].f = 0.33;
+       //pl[2].f = 0.43;
+       //pl[1].f = 0.33;
+       // test //
+        *
+        */
+       start = GNUNET_TIME_absolute_get();
+       ats_create_problem(5000,5000);
+
+       duration = GNUNET_TIME_absolute_get_difference(start,GNUNET_TIME_absolute_get());
+
+       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "benchmark result: %llu\n", duration);
+
+       GNUNET_STATISTICS_set (stats, "ATS execution time 100 peers", duration.rel_value, GNUNET_NO);
+}
+
+void ats_calculate_bandwidth_distribution ()
+{
+       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;
+       }
+
+       struct GNUNET_TIME_Absolute start;
+       /*
+       int mlp = GNUNET_NO;
+       int peers;
+       int transports;
+
+       double b_min;
+       double b_max;
+       double r;
+       double R;
+
+       int it = ATS_MAX_ITERATIONS;
+       */
+       int dur = 500;
+       if (INT_MAX < ats->max_exec_duration.rel_value)
+               dur = INT_MAX;
+       else
+               dur = (int) ats->max_exec_duration.rel_value;
+
+       struct ATS_mechanism * tl = NULL;
+       struct ATS_peer * pl = NULL;
+
+       start = GNUNET_TIME_absolute_get();
+       ats_benchmark(100,3,100,100);
+       //ats_create_problem(peers, transports, b_min, b_max, r, R, pl, tl, it, dur, mlp);
+
+       GNUNET_free_non_null (pl);
+       GNUNET_free_non_null (tl);
+
+       ats->last = GNUNET_TIME_absolute_get();
+}
+
+
+
+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 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_intervall,
+                                       &ats_schedule_calculation, ats);
+}
+
+
+int ats_map_remove_peer (void *cls,
+               const GNUNET_HashCode * key,
+               void *value)
+{
+
+       struct ATS_peer * p =  (struct ATS_peer *) value;
+#if DEBUG_ATS
+       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "map_remove_peer_it: `%s'\n", GNUNET_i2s(&p->peer));
+#endif
+       /* cleanup peer */
+       GNUNET_free(p);
+
+       return GNUNET_YES;
+}
+
+
+struct ATS_info * ats_init ()
+{
+       struct ATS_info * ats;
+#if DEBUG_ATS
+       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_init\n");
+#endif
+       ats = GNUNET_malloc(sizeof (struct ATS_info));
+       ats->peers = GNUNET_CONTAINER_multihashmap_create(10);
+       GNUNET_assert(ats->peers!=NULL);
+
+       ats->min_delta = ATS_MIN_INTERVAL;
+       ats->exec_intervall = ATS_EXEC_INTERVAL;
+       ats->max_exec_duration = ATS_MAX_EXEC_DURATION;
+       ats->max_iterations = ATS_MAX_ITERATIONS;
+
+       ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
+/*
+       ats->ats_task = GNUNET_SCHEDULER_add_delayed (ats->reg_delta,
+                                       &schedule_calculation, NULL);
+
+       ats->ats_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
+                                       &schedule_calculation, NULL);
+*/
+       ats->ats_task = GNUNET_SCHEDULER_add_now(&ats_schedule_calculation, ats);
+
+       return ats;
+}
+
+
+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;
+
+       GNUNET_CONTAINER_multihashmap_iterate (ats->peers,ats_map_remove_peer,NULL);
+       GNUNET_CONTAINER_multihashmap_destroy (ats->peers);
+       GNUNET_free (ats);
+}
+
+
+void ats_notify_peer_connect (
+               const struct GNUNET_PeerIdentity *peer,
+               const struct GNUNET_TRANSPORT_ATS_Information *ats_data)
+{
+       int c = 0;
+#if DEBUG_ATS
+       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_notify_peer_connect: %s\n",GNUNET_i2s(peer));
+#endif
+
+       while (ntohl(ats_data[c].type)!=0)
+       {
+#if DEBUG_ATS
+               GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats type [%i]: %i\n",ntohl(ats_data[c].type), ntohl(ats_data[c].value));
+#endif
+               c++;
+       }
+       /* check if peer is already known */
+       if (!GNUNET_CONTAINER_multihashmap_contains (ats->peers,&peer->hashPubKey))
+       {
+               struct ATS_peer * p = GNUNET_malloc (sizeof (struct ATS_peer));
+               memcpy(&p->peer, peer, sizeof (struct GNUNET_PeerIdentity));
+               GNUNET_CONTAINER_multihashmap_put(ats->peers, &p->peer.hashPubKey, p, GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
+       }
+
+       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
+       /* remove peer */
+       if (GNUNET_CONTAINER_multihashmap_contains (ats->peers, &peer->hashPubKey))
+       {
+               ats_map_remove_peer(NULL, &peer->hashPubKey, GNUNET_CONTAINER_multihashmap_get (ats->peers, &peer->hashPubKey));
+               GNUNET_CONTAINER_multihashmap_remove_all (ats->peers, &peer->hashPubKey);
+       }
+
+       ats_calculate_bandwidth_distribution (ats);
+}
+
+
+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
+       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);
+}
 
 /**
  * Initiate transport service.
  *
  * @param cls closure
- * @param s scheduler to use
- * @param serv the initialized server
+ * @param server the initialized server
  * @param c configuration to use
  */
 static void
 run (void *cls,
-     struct GNUNET_SCHEDULER_Handle *s,
-     struct GNUNET_SERVER_Handle *serv,
+     struct GNUNET_SERVER_Handle *server,
      const struct GNUNET_CONFIGURATION_Handle *c)
 {
+  static const struct GNUNET_SERVER_MessageHandler handlers[] = {
+    {&handle_start, NULL,
+     GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)},
+    {&handle_hello, NULL,
+     GNUNET_MESSAGE_TYPE_HELLO, 0},
+    {&handle_send, NULL,
+     GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
+    {&handle_request_connect, NULL,
+     GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT, sizeof(struct TransportRequestConnectMessage)},
+    {&handle_set_quota, NULL,
+     GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
+    {&handle_address_lookup, NULL,
+     GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
+     0},
+    {&handle_blacklist_init, NULL,
+     GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT, sizeof (struct GNUNET_MessageHeader)},
+    {&handle_blacklist_reply, NULL,
+     GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY, sizeof (struct BlacklistMessage)},
+    {NULL, NULL, 0, 0}
+  };
   char *plugs;
   char *pos;
   int no_transports;
   unsigned long long tneigh;
   char *keyfile;
 
-  sched = s;
   cfg = c;
-  stats = GNUNET_STATISTICS_create (sched, "transport", cfg);
+  stats = GNUNET_STATISTICS_create ("transport", cfg);
   validation_map = GNUNET_CONTAINER_multihashmap_create (64);
   /* parse configuration */
   if ((GNUNET_OK !=
@@ -4909,7 +6155,7 @@ run (void *cls,
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                   _
                   ("Transport service is lacking key configuration settings.  Exiting.\n"));
-      GNUNET_SCHEDULER_shutdown (s);
+      GNUNET_SCHEDULER_shutdown ();
       if (stats != NULL)
        {
          GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
@@ -4919,13 +6165,15 @@ run (void *cls,
       validation_map = NULL;
       return;
     }
+
+  ats = ats_init();
   max_connect_per_transport = (uint32_t) tneigh;
-  peerinfo = GNUNET_PEERINFO_connect (sched, cfg);
+  peerinfo = GNUNET_PEERINFO_connect (cfg);
   if (peerinfo == NULL)
     {
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                 _("Could not access PEERINFO service.  Exiting.\n"));     
-      GNUNET_SCHEDULER_shutdown (s);
+                 _("Could not access PEERINFO service.  Exiting.\n")); 
+      GNUNET_SCHEDULER_shutdown ();
       if (stats != NULL)
        {
          GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
@@ -4943,7 +6191,7 @@ run (void *cls,
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                   _
                   ("Transport service could not access hostkey.  Exiting.\n"));
-      GNUNET_SCHEDULER_shutdown (s);
+      GNUNET_SCHEDULER_shutdown ();
       if (stats != NULL)
        {
          GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
@@ -4957,7 +6205,6 @@ run (void *cls,
   GNUNET_CRYPTO_hash (&my_public_key,
                       sizeof (my_public_key), &my_identity.hashPubKey);
   /* setup notification */
-  server = serv;
   GNUNET_SERVER_disconnect_notify (server,
                                    &client_disconnect_notification, NULL);
   /* load plugins... */
@@ -4977,8 +6224,7 @@ run (void *cls,
         }
       GNUNET_free (plugs);
     }
-  GNUNET_SCHEDULER_add_delayed (sched,
-                                GNUNET_TIME_UNIT_FOREVER_REL,
+  GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
                                 &shutdown_task, NULL);
   if (no_transports)
     refresh_hello ();