the new formulation including feasibility constraints
[oweals/gnunet.git] / src / transport / gnunet-service-transport.c
index 573f8ef9a7a4b8921bb1267916800a157562edfd..839e3fd38f7034a22dd132eabd6efa39c6680578 100644 (file)
 #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 DEBUG_TRANSPORT_HELLO GNUNET_YES
+#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
@@ -562,6 +568,16 @@ 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;
+
 };
 
 /**
@@ -842,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.
  */
@@ -898,6 +909,11 @@ 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
  * has disconnected.  We may either need to do nothing (other plugins
@@ -917,10 +933,28 @@ 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.
@@ -967,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;
         }
     }
@@ -1027,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
@@ -1115,7 +1151,7 @@ read_blacklist_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
       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));
@@ -1160,6 +1196,7 @@ read_blacklist_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
       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);
 }
@@ -1188,8 +1225,10 @@ 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))
         {
@@ -1374,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;
@@ -1387,8 +1428,11 @@ 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;
+  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);
 }
 
@@ -1401,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
@@ -1433,8 +1477,6 @@ transmit_send_continuation (void *cls,
                                mq->message_buf_size,
                                GNUNET_NO);
     }
-  n = find_neighbour(&mq->neighbour_id);
-  GNUNET_assert (n != NULL);
   if (mq->specific_address != NULL)
     {
       if (result == GNUNET_OK)
@@ -1466,10 +1508,12 @@ transmit_send_continuation (void *cls,
       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);
 }
 
 
@@ -1490,6 +1534,9 @@ 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)
     {
@@ -1531,6 +1578,12 @@ find_ready_address(struct NeighbourList *neighbour)
                        (unsigned long long) addresses->timeout.abs_value,
                        (unsigned int) addresses->distance);
 #endif
+                if (0==strcmp(head->plugin->short_name,"unix"))
+                {
+                        if ((unix_address == NULL) || ((unix_address != NULL) &&
+                                (addresses->latency.rel_value < unix_address->latency.rel_value)))
+                               unix_address = addresses;
+                }
           if ( ( (best_address == NULL) ||
                 (addresses->connected == GNUNET_YES) ||
                 (best_address->connected == GNUNET_NO) ) &&
@@ -1542,19 +1595,29 @@ find_ready_address(struct NeighbourList *neighbour)
             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,
+
+         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.abs_value);
+                  best_address->latency.rel_value);
 #endif
     }
   else
@@ -1564,6 +1627,7 @@ find_ready_address(struct NeighbourList *neighbour)
                                1,
                                GNUNET_NO);
     }
+
   return best_address;
 
 }
@@ -1591,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;
@@ -1599,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,
@@ -1609,11 +1673,12 @@ 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,
@@ -1644,9 +1709,9 @@ try_transmission_to_peer (struct NeighbourList *neighbour)
                                    mq->message_buf_size,
                                    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 */
@@ -1655,26 +1720,24 @@ try_transmission_to_peer (struct NeighbourList *neighbour)
                                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.abs_value);
+                 timeout.rel_value);
 #endif
       /* FIXME: might want to trigger peerinfo lookup here
         (unless that's already pending...) */
       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++;
@@ -1912,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;
@@ -1924,7 +1988,7 @@ 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;
@@ -1962,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);
 }
 
@@ -2126,8 +2189,7 @@ plugin_env_session_end  (void *cls,
     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);
@@ -2190,9 +2252,9 @@ plugin_env_notify_address (void *cls,
   while (al != NULL)
     {
       if ((addrlen == al->addrlen) && (0 == memcmp (addr, &al[1], addrlen)))
-        {
-          if (al->expires.abs_value < abex.abs_value)
-            al->expires = abex;
+        {            
+         al->expires = abex;
+         update_addresses (p, GNUNET_NO);
           return;
         }
       al = al->next;
@@ -2214,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,
@@ -2228,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);
 }
 
 
@@ -2264,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)
     {
@@ -2518,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)
     {
@@ -2656,7 +2744,7 @@ add_to_foreign_address_list (void *cls,
     }
   if (fal == NULL)
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                  "Failed to add new address for `%4s'\n",
                  GNUNET_i2s (&n->id));
       return GNUNET_OK;
@@ -2686,15 +2774,23 @@ 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 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)
+                   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"),
@@ -2776,8 +2872,7 @@ 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)
     {
@@ -2932,7 +3027,6 @@ static void
 do_blacklist_check (void *cls,
                    const struct GNUNET_SCHEDULER_TaskContext *tc);
 
-
 /**
  * Transmit blacklist query to the client.
  *
@@ -2954,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;
     }
@@ -3047,8 +3140,7 @@ 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);
 }
 
@@ -3120,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;
     }
@@ -3164,8 +3255,7 @@ handle_blacklist_reply (void *cls,
   else
     {
       bc->bl_pos = bc->bl_pos->next;
-      bc->task = GNUNET_SCHEDULER_add_now (sched,
-                                          &do_blacklist_check,
+      bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
                                           bc);
     }
   /* check if any other bc's are waiting for this blacklister */
@@ -3174,8 +3264,7 @@ 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->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
                                             bc);
       bc = bc->next;
     }
@@ -3258,8 +3347,7 @@ send_periodic_ping (void *cls,
         &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,
@@ -3384,8 +3472,7 @@ schedule_next_ping (struct ForeignAddressList *fal)
                                    GNUNET_TIME_UNIT_SECONDS);
   /* randomize a bit (to avoid doing all at the same time) */
   delay.rel_value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
-  fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(sched,
-                                                     delay,
+  fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(delay,
                                                      &send_periodic_ping,
                                                      fal);
 }
@@ -3402,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;
@@ -3458,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)
     {
@@ -3681,6 +3780,7 @@ check_pending_validation (void *cls,
       if (GNUNET_NO == n->received_pong)
        {
          n->received_pong = GNUNET_YES;
+
          notify_clients_connect (&target, n->latency, n->distance);
          if (NULL != (prem = n->pre_connect_message_buffer))
            {
@@ -3691,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);
        }
@@ -3981,8 +4080,7 @@ run_validation (void *cls,
   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,
@@ -4003,11 +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 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)
+                       const struct GNUNET_HELLO_Message *h,
+                       const char *err_msg)
 {
   struct CheckHelloValidatedContext *chvc = cls;
   struct GNUNET_HELLO_Message *plain_hello;
@@ -4015,6 +4115,13 @@ 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,
@@ -4146,8 +4253,7 @@ process_hello (struct TransportPlugin *plugin,
                            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"),
@@ -4351,8 +4457,7 @@ disconnect_neighbour (struct NeighbourList *n, int check)
                                      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);
@@ -4381,12 +4486,12 @@ disconnect_neighbour (struct NeighbourList *n, int check)
     }
   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)
@@ -4442,7 +4547,7 @@ handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
                    plugin->env.my_identity,
                    sizeof (struct GNUNET_PeerIdentity)))
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                   _("Received `%s' message from `%s' destined for `%s' which is not me!\n"),
                  "PING",
                  (sender_address != NULL)
@@ -4497,9 +4602,10 @@ handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
       memcpy (&pong[1],
              plugin->short_name,
              slen);
-      memcpy (&((char*)&pong[1])[slen],
-             sender_address,
-             sender_address_len);
+      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 */
@@ -4674,7 +4780,8 @@ 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
@@ -4684,9 +4791,10 @@ handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
 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;
@@ -4697,6 +4805,8 @@ plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
   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)
@@ -4706,6 +4816,17 @@ 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) ||
@@ -4736,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)
        {
@@ -4816,8 +4935,10 @@ handle_start (void *cls,
 {
   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
@@ -4852,7 +4973,7 @@ handle_start (void *cls,
   clients = c;
   c->client = client;
   if (our_hello != NULL)
-    {
+  {
 #if DEBUG_TRANSPORT
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                   "Sending our own `%s' to new client\n", "HELLO");
@@ -4861,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);
+      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);
 }
 
@@ -5074,7 +5208,7 @@ handle_set_quota (void *cls,
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
               "SET_QUOTA",
-             (unsigned int) ntohl (qsm->quota.rel_value__),
+             (unsigned int) ntohl (qsm->quota.value__),
              (unsigned int) n->in_tracker.available_bytes_per_s__,
              GNUNET_i2s (&qsm->peer));
 #endif
@@ -5191,7 +5325,6 @@ 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;
@@ -5276,8 +5409,7 @@ client_disconnect_notification (void *cls,
                      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;
                }
@@ -5359,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));
@@ -5383,6 +5514,8 @@ 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))
     {
@@ -5418,18 +5551,564 @@ 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 server the initialized server
  * @param c configuration to use
  */
 static void
 run (void *cls,
-     struct GNUNET_SCHEDULER_Handle *s,
      struct GNUNET_SERVER_Handle *server,
      const struct GNUNET_CONFIGURATION_Handle *c)
 {
@@ -5459,9 +6138,8 @@ run (void *cls,
   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 !=
@@ -5477,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);
@@ -5487,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);
+      GNUNET_SCHEDULER_shutdown ();
       if (stats != NULL)
        {
          GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
@@ -5511,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);
@@ -5544,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 ();