bugfixes and redesigning scheduler API
[oweals/gnunet.git] / src / transport / gnunet-service-transport.c
index 18b50b38a85b38128f4be854cb042665b782420b..efe53e0215388c90c214f377540e225ca77e5ed1 100644 (file)
@@ -29,6 +29,7 @@
  */
 #include "platform.h"
 #include "gnunet_client_lib.h"
+#include "gnunet_constants.h"
 #include "gnunet_getopt_lib.h"
 #include "gnunet_hello_lib.h"
 #include "gnunet_os_lib.h"
 
 /**
  * How long until a HELLO verification attempt should time out?
+ * Must be rather small, otherwise a partially successful HELLO
+ * validation (some addresses working) might not be available
+ * before a client's request for a connection fails for good.
+ * Besides, if a single request to an address takes a long time,
+ * then the peer is unlikely worthwhile anyway.
  */
-#define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_UNIT_MINUTES
+#define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3)
 
 /**
  * How often do we re-add (cheaper) plugins to our list of plugins
  */
 #define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
 
-/**
- * After how long do we consider a connection to a peer dead
- * if we don't receive messages from the peer?
- */
-#define IDLE_CONNECTION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
-
 
 /**
  * Entry in linked list of network addresses.
@@ -219,6 +219,11 @@ struct MessageQueue
    */
   int internal_msg;
 
+  /**
+   * How important is the message?
+   */
+  unsigned int priority;
+  
 };
 
 
@@ -356,16 +361,10 @@ struct NeighbourList
   uint64_t last_received;
 
   /**
-   * Global quota for outbound traffic for the neighbour in bytes/ms.
+   * Global quota for inbound traffic for the neighbour in bytes/ms.
    */
   uint32_t quota_in;
 
-  /**
-   * What is the latest version of our HELLO that we have
-   * sent to this neighbour?
-   */
-  unsigned int hello_version_sent;
-
   /**
    * How often has the other peer (recently) violated the
    * inbound traffic limit?  Incremented by 10 per violation,
@@ -442,70 +441,6 @@ struct TransportClient
 };
 
 
-/**
- * Message used to ask a peer to validate receipt (to check an address
- * from a HELLO).  Followed by the address used.  Note that the
- * recipients response does not affirm that he has this address,
- * only that he got the challenge message.
- */
-struct ValidationChallengeMessage
-{
-
-  /**
-   * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
-   */
-  struct GNUNET_MessageHeader header;
-
-  /**
-   * What are we signing and why?
-   */
-  struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
-
-  /**
-   * Random challenge number (in network byte order).
-   */
-  uint32_t challenge GNUNET_PACKED;
-
-  /**
-   * Who is the intended recipient?
-   */
-  struct GNUNET_PeerIdentity target;
-};
-
-
-/**
- * Message used to validate a HELLO.  If this was
- * the right recipient, the response is a signature
- * of the original validation request.  The
- * challenge is included in the confirmation to make
- * matching of replies to requests possible.
- */
-struct ValidationChallengeResponse
-{
-
-  /**
-   * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
-   */
-  struct GNUNET_MessageHeader header;
-
-  /**
-   * Random challenge number (in network byte order).
-   */
-  uint32_t challenge GNUNET_PACKED;
-
-  /**
-   * Who signed this message?
-   */
-  struct GNUNET_PeerIdentity sender;
-
-  /**
-   * Signature.
-   */
-  struct GNUNET_CRYPTO_RsaSignature signature;
-
-};
-
-
 /**
  * For each HELLO, we may have to validate multiple addresses;
  * each address gets its own request entry.
@@ -517,12 +452,6 @@ struct ValidationAddress
    */
   struct ValidationAddress *next;
 
-  /**
-   * Our challenge message.  Points to after this
-   * struct, so this field should not be freed.
-   */
-  struct ValidationChallengeMessage *msg;
-
   /**
    * Name of the transport.
    */
@@ -538,6 +467,11 @@ struct ValidationAddress
    */
   size_t addr_len;
 
+  /**
+   * Challenge number we used.
+   */
+  uint32_t challenge;
+
   /**
    * Set to GNUNET_YES if the challenge was met,
    * GNUNET_SYSERR if we know it failed, GNUNET_NO
@@ -618,7 +552,7 @@ struct GNUNET_SCHEDULER_Handle *sched;
 /**
  * Our configuration.
  */
-struct GNUNET_CONFIGURATION_Handle *cfg;
+const struct GNUNET_CONFIGURATION_Handle *cfg;
 
 /**
  * Linked list of all clients to this service.
@@ -640,16 +574,6 @@ static struct GNUNET_SERVER_Handle *server;
  */
 static struct NeighbourList *neighbours;
 
-/**
- * Default bandwidth quota for receiving for new peers in bytes/ms.
- */
-static uint32_t default_quota_in;
-
-/**
- * Default bandwidth quota for sending for new peers in bytes/ms.
- */
-static uint32_t default_quota_out;
-
 /**
  * Number of neighbours we'd like to have.
  */
@@ -748,7 +672,7 @@ transmit_to_client_callback (void *cls, size_t size, void *buf)
   uint16_t msize;
   size_t tsize;
   const struct GNUNET_MessageHeader *msg;
-  struct GNUNET_NETWORK_TransmitHandle *th;
+  struct GNUNET_CONNECTION_TransmitHandle *th;
   char *cbuf;
 
   if (buf == NULL)
@@ -773,6 +697,11 @@ transmit_to_client_callback (void *cls, size_t size, void *buf)
       msize = ntohs (msg->size);
       if (msize + tsize > size)
         break;
+#if DEBUG_TRANSPORT
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                 "Transmitting message of type %u to client.\n",
+                 ntohs (msg->type));
+#endif
       client->message_queue_head = q->next;
       if (q->next == NULL)
         client->message_queue_tail = NULL;
@@ -781,9 +710,9 @@ transmit_to_client_callback (void *cls, size_t size, void *buf)
       GNUNET_free (q);
       client->message_count--;
     }
-  GNUNET_assert (tsize > 0);
   if (NULL != q)
     {
+      GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
       th = GNUNET_SERVER_notify_transmit_ready (client->client,
                                                 msize,
                                                 GNUNET_TIME_UNIT_FOREVER_REL,
@@ -811,7 +740,7 @@ transmit_to_client (struct TransportClient *client,
 {
   struct ClientMessageQueueEntry *q;
   uint16_t msize;
-  struct GNUNET_NETWORK_TransmitHandle *th;
+  struct GNUNET_CONNECTION_TransmitHandle *th;
 
   if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
     {
@@ -824,6 +753,7 @@ transmit_to_client (struct TransportClient *client,
     }
   client->message_count++;
   msize = ntohs (msg->size);
+  GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
   q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
   memcpy (&q[1], msg, msize);
   /* append to message queue */
@@ -878,6 +808,24 @@ try_alternative_plugins (struct NeighbourList *neighbour)
 }
 
 
+/**
+ * The peer specified by the given neighbour has timed-out or a plugin
+ * has disconnected.  We may either need to do nothing (other plugins
+ * still up), or trigger a full disconnect and clean up.  This
+ * function updates our state and do the necessary notifications.
+ * Also notifies our clients that the neighbour is now officially
+ * 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?
+ */
+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
@@ -885,7 +833,8 @@ try_alternative_plugins (struct NeighbourList *neighbour)
  *
  * @param neighbour target peer for which to check the plugins
  */
-static void try_transmission_to_peer (struct NeighbourList *neighbour);
+static void 
+try_transmission_to_peer (struct NeighbourList *neighbour);
 
 
 /**
@@ -930,18 +879,24 @@ transmit_send_continuation (void *cls,
     }
   if (result == GNUNET_OK)
     {
-      rl->timeout = GNUNET_TIME_relative_to_absolute (IDLE_CONNECTION_TIMEOUT);
+      rl->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
     }
   else
     {
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                 "Transmission failed, marking connection as down.\n");
+                 "Transmission to peer `%s' failed, marking connection as down.\n",
+                 GNUNET_i2s(target));
       rl->connected = GNUNET_NO;
+      rl->plugin_handle = NULL;
     }
   if (!mq->internal_msg)
     rl->transmit_ready = GNUNET_YES;
   if (mq->client != NULL)
     {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                 "Notifying client %p about failed transission to peer `%4s'.\n",
+                 mq->client,
+                 GNUNET_i2s(target));
       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);
@@ -952,115 +907,10 @@ transmit_send_continuation (void *cls,
   GNUNET_free (mq);
   /* one plugin just became ready again, try transmitting
      another message (if available) */
-  try_transmission_to_peer (n);
-}
-
-
-
-
-/**
- * We could not use an existing (or validated) connection to
- * talk to a peer.  Try addresses that have not yet been
- * validated.
- *
- * @param n neighbour we want to communicate with
- * @return plugin ready to talk, or NULL if none is available
- */
-static struct ReadyList *
-try_unvalidated_addresses (struct NeighbourList *n)
-{
-  struct ValidationList *vl;
-  struct ValidationAddress *va;
-  struct GNUNET_PeerIdentity id;
-  struct GNUNET_TIME_Absolute now;
-  unsigned int total;
-  unsigned int cnt;
-  struct ReadyList *rl;
-  struct TransportPlugin *plugin;
-
-#if DEBUG_TRANSPORT
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Trying to connect to `%4s' using unvalidated addresses\n",
-              GNUNET_i2s (&n->id));
-#endif
-  /* NOTE: this function needs to not only identify the
-     plugin but also setup "plugin_handle", binding it to the
-     right address using the plugin's "send_to" API */
-  now = GNUNET_TIME_absolute_get ();
-  vl = pending_validations;
-  while (vl != NULL)
-    {
-      GNUNET_CRYPTO_hash (&vl->publicKey,
-                          sizeof (struct
-                                  GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
-                          &id.hashPubKey);
-      if (0 == memcmp (&id, &n->id, sizeof (struct GNUNET_PeerIdentity)))
-        break;
-      vl = vl->next;
-    }
-  if (vl == NULL)
-    {
-#if DEBUG_TRANSPORT
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "No unvalidated address found for peer `%4s'\n",
-                  GNUNET_i2s (&n->id));
-#endif
-      return NULL;
-    }
-  total = 0;
-  cnt = 0;
-  va = vl->addresses;
-  while (va != NULL)
-    {
-      cnt++;
-      if (va->expiration.value > now.value)
-        total++;
-      va = va->next;
-    }
-  if (total == 0)
-    {
-#if DEBUG_TRANSPORT
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "All %u unvalidated addresses for peer have expired\n",
-                  cnt);
-#endif
-      return NULL;
-    }
-  total = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, total);
-  for (va = vl->addresses; va != NULL; va = va->next)
-    {
-      if (va->expiration.value <= now.value)
-        continue;
-      if (total > 0)
-        {
-          total--;
-          continue;
-        }
-#if DEBUG_TRANSPORT
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
-                  "Trying unvalidated address of `%s' transport\n",
-                  va->transport_name);
-#endif
-      plugin = find_transport (va->transport_name);
-      if (plugin == NULL)
-        {
-          GNUNET_break (0);
-          break;
-        }
-      rl = GNUNET_malloc (sizeof (struct ReadyList));
-      rl->next = n->plugins;
-      n->plugins = rl;
-      rl->plugin = plugin;
-      rl->plugin_handle = plugin->api->send_to (plugin->api->cls,
-                                                &n->id,
-                                                NULL,
-                                                NULL,
-                                                GNUNET_TIME_UNIT_ZERO,
-                                                &va->msg[1], va->addr_len);
-      rl->transmit_ready = GNUNET_YES;
-      return rl;
-    }
-  return NULL;
+  if (result == GNUNET_OK)
+    try_transmission_to_peer (n);
+  else    
+    disconnect_neighbour (n, GNUNET_YES); 
 }
 
 
@@ -1108,8 +958,6 @@ try_transmission_to_peer (struct NeighbourList *neighbour)
         }
       pos = pos->next;
     }
-  if (rl == NULL)
-    rl = try_unvalidated_addresses (neighbour);
   if (rl == NULL)
     {
 #if DEBUG_TRANSPORT
@@ -1122,6 +970,11 @@ try_transmission_to_peer (struct NeighbourList *neighbour)
     {
       rl->connect_attempts++;
       rl->connected = GNUNET_YES;
+#if DEBUG_TRANSPORT
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Establishing fresh connection with `%4s' via plugin `%s'\n",
+              GNUNET_i2s (&neighbour->id), rl->plugin->short_name);
+#endif
     }
   neighbour->messages = mq->next;
   mq->plugin = rl->plugin;
@@ -1138,8 +991,9 @@ try_transmission_to_peer (struct NeighbourList *neighbour)
                              rl->plugin_handle,
                              rl,
                              &neighbour->id,
+                            mq->priority,
                              mq->message,
-                             IDLE_CONNECTION_TIMEOUT,
+                             GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
                              &transmit_send_continuation, mq);
 }
 
@@ -1148,12 +1002,14 @@ try_transmission_to_peer (struct NeighbourList *neighbour)
  * Send the specified message to the specified peer.
  *
  * @param client source of the transmission request (can be NULL)
+ * @param priority how important is the message
  * @param msg message to send
  * @param is_internal is this an internal message
  * @param neighbour handle to the neighbour for transmission
  */
 static void
 transmit_to_peer (struct TransportClient *client,
+                 unsigned int priority,
                   const struct GNUNET_MessageHeader *msg,
                   int is_internal, struct NeighbourList *neighbour)
 {
@@ -1189,6 +1045,7 @@ transmit_to_peer (struct TransportClient *client,
   mq->message = m;
   mq->neighbour = neighbour;
   mq->internal_msg = is_internal;
+  mq->priority = priority;
 
   /* find tail */
   mqe = neighbour->messages;
@@ -1209,6 +1066,9 @@ transmit_to_peer (struct TransportClient *client,
 }
 
 
+/**
+ * FIXME: document.
+ */
 struct GeneratorContext
 {
   struct TransportPlugin *plug_pos;
@@ -1217,6 +1077,9 @@ struct GeneratorContext
 };
 
 
+/**
+ * FIXME: document.
+ */
 static size_t
 address_generator (void *cls, size_t max, void *buf)
 {
@@ -1253,7 +1116,8 @@ refresh_hello ()
 
 #if DEBUG_TRANSPORT
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
-              "Refreshing my HELLO\n");
+              "Refreshing my `%s'\n",
+             "HELLO");
 #endif
   gc.plug_pos = plugins;
   gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
@@ -1274,7 +1138,13 @@ refresh_hello ()
   npos = neighbours;
   while (npos != NULL)
     {
-      transmit_to_peer (NULL,
+#if DEBUG_TRANSPORT
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
+                 "Transmitting updated `%s' to neighbour `%4s'\n",
+                 "HELLO",
+                 GNUNET_i2s(&npos->id));
+#endif
+      transmit_to_peer (NULL, 0,
                         (const struct GNUNET_MessageHeader *) our_hello,
                         GNUNET_YES, npos);
       npos = npos->next;
@@ -1313,9 +1183,9 @@ update_addresses (struct TransportPlugin *plugin, int fresh)
   struct AddressList *next;
   int expired;
 
-  if (plugin->address_update_task != GNUNET_SCHEDULER_NO_PREREQUISITE_TASK)
+  if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
     GNUNET_SCHEDULER_cancel (plugin->env.sched, plugin->address_update_task);
-  plugin->address_update_task = GNUNET_SCHEDULER_NO_PREREQUISITE_TASK;
+  plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
   now = GNUNET_TIME_absolute_get ();
   min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
   expired = GNUNET_NO;
@@ -1348,9 +1218,6 @@ update_addresses (struct TransportPlugin *plugin, int fresh)
   if (min_remaining.value < GNUNET_TIME_UNIT_FOREVER_REL.value)
     plugin->address_update_task
       = GNUNET_SCHEDULER_add_delayed (plugin->env.sched,
-                                      GNUNET_NO,
-                                      GNUNET_SCHEDULER_PRIORITY_IDLE,
-                                      GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
                                       min_remaining,
                                       &expire_address_task, plugin);
 
@@ -1367,7 +1234,7 @@ static void
 expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
   struct TransportPlugin *plugin = cls;
-  plugin->address_update_task = GNUNET_SCHEDULER_NO_PREREQUISITE_TASK;
+  plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
   update_addresses (plugin, GNUNET_NO);
 }
 
@@ -1395,11 +1262,6 @@ plugin_env_notify_address (void *cls,
   struct AddressList *al;
   struct GNUNET_TIME_Absolute abex;
 
-#if DEBUG_TRANSPORT
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Plugin `%s' informs us about a new address `%s'\n", name,
-             GNUNET_a2s(addr, addrlen));
-#endif
   abex = GNUNET_TIME_relative_to_absolute (expires);
   GNUNET_assert (p == find_transport (name));
 
@@ -1414,6 +1276,11 @@ plugin_env_notify_address (void *cls,
         }
       al = al->next;
     }
+#if DEBUG_TRANSPORT
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Plugin `%s' informs us about a new address `%s'\n", name,
+             GNUNET_a2s(addr, addrlen));
+#endif
   al = GNUNET_malloc (sizeof (struct AddressList) + addrlen);
   al->addr = &al[1];
   al->next = p->addresses;
@@ -1425,6 +1292,9 @@ plugin_env_notify_address (void *cls,
 }
 
 
+/**
+ * FIXME: document.
+ */
 struct LookupHelloContext
 {
   GNUNET_TRANSPORT_AddressCallback iterator;
@@ -1433,6 +1303,9 @@ struct LookupHelloContext
 };
 
 
+/**
+ * FIXME: document.
+ */
 static int
 lookup_address_callback (void *cls,
                          const char *tname,
@@ -1445,6 +1318,9 @@ lookup_address_callback (void *cls,
 }
 
 
+/**
+ * FIXME: document.
+ */
 static void
 lookup_hello_callback (void *cls,
                        const struct GNUNET_PeerIdentity *peer,
@@ -1510,7 +1386,7 @@ notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
 #endif
   cim.header.size = htons (sizeof (struct ConnectInfoMessage));
   cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
-  cim.quota_out = htonl (default_quota_out);
+  cim.quota_out = htonl (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT / (60*1000));
   cim.latency = GNUNET_TIME_relative_hton (latency);
   memcpy (&cim.id, peer, sizeof (struct GNUNET_PeerIdentity));
   cpos = clients;
@@ -1567,7 +1443,7 @@ list_validated_addresses (void *cls, size_t max, void *buf)
     return 0;
   ret = GNUNET_HELLO_add_address ((*va)->transport_name,
                                   (*va)->expiration,
-                                  &(*va)->msg[1], (*va)->addr_len, buf, max);
+                                  &(*va)[1], (*va)->addr_len, buf, max);
   *va = (*va)->next;
   return ret;
 }
@@ -1583,8 +1459,10 @@ cleanup_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
   struct ValidationList *pos;
   struct ValidationList *prev;
   struct GNUNET_TIME_Absolute now;
+  struct GNUNET_TIME_Absolute first;
   struct GNUNET_HELLO_Message *hello;
   struct GNUNET_PeerIdentity pid;
+  struct NeighbourList *n;
 
 #if DEBUG_TRANSPORT
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
@@ -1614,6 +1492,9 @@ cleanup_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
                       "HELLO", GNUNET_i2s (&pid));
 #endif
           GNUNET_PEERINFO_add_peer (cfg, sched, &pid, hello);
+         n = find_neighbour (&pid);
+         if (NULL != n)
+           try_transmission_to_peer (n);           
           GNUNET_free (hello);
           while (NULL != (va = pos->addresses))
             {
@@ -1634,16 +1515,132 @@ cleanup_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 
   /* finally, reschedule cleanup if needed; list is
      ordered by timeout, so we need the last element... */
+  if (NULL != pending_validations)
+    {
+      first = pending_validations->timeout;
+      pos = pending_validations;
+      while (pos != NULL) 
+       {
+         first = GNUNET_TIME_absolute_min (first, pos->timeout);
+         pos = pos->next;
+       }
+      GNUNET_SCHEDULER_add_delayed (sched,
+                                   GNUNET_TIME_absolute_get_remaining (first),
+                                   &cleanup_validation, NULL);
+    }
+}
+
+
+
+
+/**
+ * Function that will be called if we receive a validation
+ * of an address challenge that we transmitted to another
+ * peer.  Note that the validation should only be considered
+ * acceptable if the challenge matches AND if the sender
+ * address is at least a plausible address for this peer
+ * (otherwise we may be seeing a MiM attack).
+ *
+ * @param cls closure
+ * @param name name of the transport that generated the address
+ * @param peer who responded to our challenge
+ * @param challenge the challenge number we presumably used
+ * @param sender_addr string describing our sender address (as observed
+ *         by the other peer in human-readable format)
+ */
+static void
+plugin_env_notify_validation (void *cls,
+                             const char *name,
+                             const struct GNUNET_PeerIdentity *peer,
+                             uint32_t challenge,
+                             const char *sender_addr)
+{
+  unsigned int not_done;
+  int matched;
+  struct ValidationList *pos;
+  struct ValidationAddress *va;
+  struct GNUNET_PeerIdentity id;
+
   pos = pending_validations;
-  while ((pos != NULL) && (pos->next != NULL))
-    pos = pos->next;
-  if (NULL != pos)
-    GNUNET_SCHEDULER_add_delayed (sched,
-                                  GNUNET_NO,
-                                  GNUNET_SCHEDULER_PRIORITY_IDLE,
-                                  GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
-                                  GNUNET_TIME_absolute_get_remaining
-                                  (pos->timeout), &cleanup_validation, NULL);
+  while (pos != NULL)
+    {
+      GNUNET_CRYPTO_hash (&pos->publicKey,
+                          sizeof (struct
+                                  GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
+                          &id.hashPubKey);
+      if (0 ==
+          memcmp (peer, &id, sizeof (struct GNUNET_PeerIdentity)))
+        break;
+      pos = pos->next;
+    }
+  if (pos == NULL)
+    {
+      /* TODO: call statistics (unmatched PONG) */
+      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                  _
+                  ("Received validation response but have no record of any validation request for `%4s'. Ignoring.\n"),
+                 GNUNET_i2s(peer));
+      return;
+    }
+  not_done = 0;
+  matched = GNUNET_NO;
+  va = pos->addresses;
+  while (va != NULL)
+    {
+      if (va->challenge == challenge)
+       {
+#if DEBUG_TRANSPORT
+         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                     "Confirmed validity of address, peer `%4s' has address `%s'.\n",
+                     GNUNET_i2s (peer),
+                     GNUNET_a2s ((const struct sockaddr*) &va[1], 
+                                 va->addr_len));
+#endif
+         GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
+                     _("Another peer saw us using the address `%s' via `%s'. If this is not plausible, this address should be listed in the configuration as implausible to avoid MiM attacks.\n"),
+                     sender_addr, 
+                     name);
+         va->ok = GNUNET_YES;
+         va->expiration =
+           GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
+         matched = GNUNET_YES;
+       }        
+      if (va->ok != GNUNET_YES)
+        not_done++;
+      va = va->next;
+    }
+  if (GNUNET_NO == matched)
+    {
+      /* TODO: call statistics (unmatched PONG) */
+      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                  _
+                  ("Received `%s' message but have no record of a matching `%s' message. Ignoring.\n"),
+                  "PONG", "PING");
+    }
+  if (0 == not_done)
+    {
+#if DEBUG_TRANSPORT
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                 "All addresses validated, will now construct `%s' for `%4s'.\n",
+                 "HELLO",
+                 GNUNET_i2s (peer));
+#endif
+      pos->timeout.value = 0;
+      GNUNET_SCHEDULER_add_with_priority (sched,
+                                         GNUNET_SCHEDULER_PRIORITY_IDLE,
+                                         &cleanup_validation, NULL);
+    }
+  else
+    {
+#if DEBUG_TRANSPORT
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                 "Still waiting for %u additional `%s' messages before constructing `%s' for `%4s'.\n",
+                 not_done,
+                 "PONG",
+                 "HELLO",
+                 GNUNET_i2s (peer));
+#endif
+    }
 }
 
 
@@ -1680,7 +1677,6 @@ run_validation (void *cls,
   struct ValidationList *e = cls;
   struct TransportPlugin *tp;
   struct ValidationAddress *va;
-  struct ValidationChallengeMessage *vcm;
   struct GNUNET_PeerIdentity id;
 
   tp = find_transport (tname);
@@ -1703,25 +1699,14 @@ run_validation (void *cls,
              tname,
              GNUNET_i2s(&id));
 
-  va = GNUNET_malloc (sizeof (struct ValidationAddress) +
-                      sizeof (struct ValidationChallengeMessage) + addrlen);
+  va = GNUNET_malloc (sizeof (struct ValidationAddress) + addrlen);
   va->next = e->addresses;
   e->addresses = va;
-  vcm = (struct ValidationChallengeMessage *) &va[1];
-  va->msg = vcm;
   va->transport_name = GNUNET_strdup (tname);
   va->addr_len = addrlen;
-  vcm->header.size =
-    htons (sizeof (struct ValidationChallengeMessage) + addrlen);
-  vcm->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
-  vcm->purpose.size =
-    htonl (sizeof (struct ValidationChallengeMessage) + addrlen -
-           sizeof (struct GNUNET_MessageHeader));
-  vcm->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_HELLO);
-  vcm->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
-                                             (unsigned int) -1);
-  vcm->target = id;
-  memcpy (&vcm[1], addr, addrlen);
+  va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
+                                           (unsigned int) -1);
+  memcpy (&va[1], addr, addrlen);
   return GNUNET_OK;
 }
 
@@ -1734,12 +1719,14 @@ run_validation (void *cls,
 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, 
+                      uint32_t trust)
 {
   struct CheckHelloValidatedContext *chvc = cls;
   struct ValidationAddress *va;
   struct TransportPlugin *tp;
   int first_call;
+  struct GNUNET_PeerIdentity apeer;
 
   first_call = GNUNET_NO;
   if (chvc->e == NULL)
@@ -1770,35 +1757,41 @@ check_hello_validated (void *cls,
   if (h != NULL)
     return;                     /* wait for next call */
   /* finally, transmit validation attempts */
+  GNUNET_assert (GNUNET_OK ==
+                GNUNET_HELLO_get_id (chvc->hello,
+                                     &apeer));
+#if DEBUG_TRANSPORT
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Ready to validate addresses from `%s' message for peer `%4s'\n",
+             "HELLO", GNUNET_i2s (&apeer));
+#endif
   va = chvc->e->addresses;
   while (va != NULL)
     {
 #if DEBUG_TRANSPORT
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "Establishing `%s' connection to validate `%s' of `%4s' (sending our `%s')\n",
+                  "Establishing `%s' connection to validate `%s' address `%s' of `%4s'\n",
                   va->transport_name,
-                  "HELLO", GNUNET_i2s (&va->msg->target), "HELLO");
+                  "HELLO",
+                 GNUNET_a2s ((const struct sockaddr*) &va[1], 
+                             va->addr_len),
+                 GNUNET_i2s (&apeer));
 #endif
       tp = find_transport (va->transport_name);
       GNUNET_assert (tp != NULL);
-      if (NULL ==
-          tp->api->send_to (tp->api->cls,
-                            &va->msg->target,
-                            (const struct GNUNET_MessageHeader *) our_hello,
-                            &va->msg->header,
-                            HELLO_VERIFICATION_TIMEOUT,
-                            &va->msg[1], va->addr_len))
+      if (GNUNET_OK !=
+          tp->api->validate (tp->api->cls,
+                            &apeer,
+                            va->challenge,
+                            HELLO_VERIFICATION_TIMEOUT,
+                            &va[1],
+                            va->addr_len))
         va->ok = GNUNET_SYSERR;
       va = va->next;
     }
-  if (chvc->e->next == NULL)
-    GNUNET_SCHEDULER_add_delayed (sched,
-                                  GNUNET_NO,
-                                  GNUNET_SCHEDULER_PRIORITY_IDLE,
-                                  GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
-                                  GNUNET_TIME_absolute_get_remaining
-                                  (chvc->e->timeout), &cleanup_validation,
-                                  NULL);
+  GNUNET_SCHEDULER_add_delayed (sched,
+                               GNUNET_TIME_absolute_get_remaining (chvc->e->timeout), 
+                               &cleanup_validation, NULL);
   GNUNET_free (chvc);
 }
 
@@ -1884,204 +1877,42 @@ process_hello (struct TransportPlugin *plugin,
 
 
 /**
- * Handle PING-message.  If the plugin that gave us the message is
- * able to queue the PONG immediately, we only queue one PONG.
- * Otherwise we send at most TWO PONG messages, one via an unconfirmed
- * transport and one via a confirmed transport.  Both addresses are
- * selected randomly among those available.
- *
- * @param plugin plugin that gave us the message
- * @param sender claimed sender of the PING
- * @param plugin_context context that might be used to send response
- * @param message the actual message
- */
-static void
-process_ping (struct TransportPlugin *plugin,
-              const struct GNUNET_PeerIdentity *sender,
-              void *plugin_context,
-              const struct GNUNET_MessageHeader *message)
-{
-  const struct ValidationChallengeMessage *vcm;
-  struct ValidationChallengeResponse vcr;
-  uint16_t msize;
-  struct NeighbourList *n;
-
-#if DEBUG_TRANSPORT
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
-              "Processing PING\n");
-#endif
-  msize = ntohs (message->size);
-  if (msize < sizeof (struct ValidationChallengeMessage))
-    {
-      GNUNET_break_op (0);
-      return;
-    }
-  vcm = (const struct ValidationChallengeMessage *) message;
-  if (0 != memcmp (&vcm->target,
-                   &my_identity, sizeof (struct GNUNET_PeerIdentity)))
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                  _("Received `%s' message not destined for me!\n"), "PING");
-      /* TODO: call statistics */
-      return;
-    }
-  if ((ntohl (vcm->purpose.size) !=
-       msize - sizeof (struct GNUNET_MessageHeader))
-      || (ntohl (vcm->purpose.purpose) !=
-          GNUNET_SIGNATURE_PURPOSE_TRANSPORT_HELLO))
-    {
-      GNUNET_break_op (0);
-      return;
-    }
-  msize -= sizeof (struct ValidationChallengeMessage);
-  if (GNUNET_OK !=
-      plugin->api->address_suggested (plugin->api->cls, &vcm[1], msize))
-    {
-      GNUNET_break_op (0);
-      return;
-    }
-  vcr.header.size = htons (sizeof (struct ValidationChallengeResponse));
-  vcr.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
-  vcr.challenge = vcm->challenge;
-  vcr.sender = my_identity;
-  GNUNET_assert (GNUNET_OK ==
-                 GNUNET_CRYPTO_rsa_sign (my_private_key,
-                                         &vcm->purpose, &vcr.signature));
-#if EXTRA_CHECKS
-  GNUNET_assert (GNUNET_OK ==
-                 GNUNET_CRYPTO_rsa_verify
-                 (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_HELLO, &vcm->purpose,
-                  &vcr.signature, &my_public_key));
-#endif
-#if DEBUG_TRANSPORT
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
-              "Trying to transmit PONG using inbound connection\n");
-#endif
-  n = find_neighbour (sender);
-  if (n == NULL)
-    {
-      GNUNET_break (0);
-      return;
-    }
-  transmit_to_peer (NULL, &vcr.header, GNUNET_YES, n);
-}
-
-
-/**
- * Handle PONG-message.
- *
- * @param message the actual message
- */
-static void
-process_pong (struct TransportPlugin *plugin,
-              const struct GNUNET_MessageHeader *message)
-{
-  const struct ValidationChallengeResponse *vcr;
-  struct ValidationList *pos;
-  struct GNUNET_PeerIdentity peer;
-  struct ValidationAddress *va;
-  int all_done;
-  int matched;
-
-#if DEBUG_TRANSPORT
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
-              "Processing PONG\n");
-#endif
-  vcr = (const struct ValidationChallengeResponse *) message;
-  pos = pending_validations;
-  while (pos != NULL)
-    {
-      GNUNET_CRYPTO_hash (&pos->publicKey,
-                          sizeof (struct
-                                  GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
-                          &peer.hashPubKey);
-      if (0 ==
-          memcmp (&peer, &vcr->sender, sizeof (struct GNUNET_PeerIdentity)))
-        break;
-      pos = pos->next;
-    }
-  if (pos == NULL)
-    {
-      /* TODO: call statistics (unmatched PONG) */
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                  _
-                  ("Received `%s' message but have no record of a matching `%s' message. Ignoring.\n"),
-                  "PONG", "PING");
-      return;
-    }
-  all_done = GNUNET_YES;
-  matched = GNUNET_NO;
-  va = pos->addresses;
-  while (va != NULL)
-    {
-      if (va->msg->challenge == vcr->challenge)
-        {
-          if (GNUNET_OK !=
-              GNUNET_CRYPTO_rsa_verify
-              (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_HELLO, &va->msg->purpose,
-               &vcr->signature, &pos->publicKey))
-            {
-              /* this could rarely happen if we used the same
-                 challenge number for the peer for two different
-                 transports / addresses, but the likelihood is
-                 very small... */
-              GNUNET_break_op (0);
-            }
-          else
-            {
-#if DEBUG_TRANSPORT
-              GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                          "Confirmed validity of peer address.\n");
-#endif
-              va->ok = GNUNET_YES;
-              va->expiration =
-                GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
-              matched = GNUNET_YES;
-            }
-        }
-      if (va->ok != GNUNET_YES)
-        all_done = GNUNET_NO;
-      va = va->next;
-    }
-  if (GNUNET_NO == matched)
-    {
-      /* TODO: call statistics (unmatched PONG) */
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                  _
-                  ("Received `%s' message but have no record of a matching `%s' message. Ignoring.\n"),
-                  "PONG", "PING");
-    }
-  if (GNUNET_YES == all_done)
-    {
-      pos->timeout.value = 0;
-      GNUNET_SCHEDULER_add_delayed (sched,
-                                    GNUNET_NO,
-                                    GNUNET_SCHEDULER_PRIORITY_IDLE,
-                                    GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
-                                    GNUNET_TIME_UNIT_ZERO,
-                                    &cleanup_validation, NULL);
-    }
-}
-
-
-/**
- * The peer specified by the given neighbour has timed-out.  Update
- * our state and do the necessary notifications.  Also notifies
- * our clients that the neighbour is now officially gone.
+ * The peer specified by the given neighbour has timed-out or a plugin
+ * has disconnected.  We may either need to do nothing (other plugins
+ * still up), or trigger a full disconnect and clean up.  This
+ * function updates our state and do the necessary notifications.
+ * Also notifies our clients that the neighbour is now officially
+ * 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?
  */
 static void
-disconnect_neighbour (struct NeighbourList *n)
+disconnect_neighbour (struct NeighbourList *n,
+                     int check)
 {
   struct ReadyList *rpos;
   struct NeighbourList *npos;
   struct NeighbourList *nprev;
   struct MessageQueue *mq;
+  
+  if (GNUNET_YES == check)
+    {
+      rpos = n->plugins;
+      while (NULL != rpos)
+       {
+         if (GNUNET_YES == rpos->connected)
+           return; /* still connected */
+         rpos = rpos->next;
+       }
+    }
 
 #if DEBUG_TRANSPORT
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
-              "Disconnecting from neighbour\n");
+              "Disconnecting from `%4s'\n",
+             GNUNET_i2s(&n->id));
 #endif
   /* remove n from neighbours list */
   nprev = NULL;
@@ -2100,13 +1931,16 @@ disconnect_neighbour (struct NeighbourList *n)
   /* notify all clients about disconnect */
   notify_clients_disconnect (&n->id);
 
-  /* clean up all plugins, cancel connections & pending transmissions */
+  /* clean up all plugins, cancel connections and pending transmissions */
   while (NULL != (rpos = n->plugins))
     {
       n->plugins = rpos->next;
       GNUNET_assert (rpos->neighbour == n);
-      rpos->plugin->api->cancel (rpos->plugin->api->cls,
-                                 rpos->plugin_handle, rpos, &n->id);
+      if (GNUNET_YES == rpos->connected)
+       rpos->plugin->api->cancel (rpos->plugin->api->cls,
+                                  rpos->plugin_handle,
+                                  rpos,
+                                  &n->id);
       GNUNET_free (rpos);
     }
 
@@ -2117,7 +1951,9 @@ disconnect_neighbour (struct NeighbourList *n)
       GNUNET_assert (mq->neighbour == n);
       GNUNET_free (mq);
     }
-
+  if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
+    GNUNET_SCHEDULER_cancel (sched,
+                            n->timeout_task);
   /* finally, free n itself */
   GNUNET_free (n);
 }
@@ -2163,14 +1999,14 @@ neighbour_timeout_task (void *cls,
 
 #if DEBUG_TRANSPORT
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
-              "Neighbour has timed out!\n");
+              "Neighbour `%4s' has timed out!\n",
+             GNUNET_i2s(&n->id));
 #endif
-  n->timeout_task = GNUNET_SCHEDULER_NO_PREREQUISITE_TASK;
-  disconnect_neighbour (n);
+  n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+  disconnect_neighbour (n, GNUNET_NO);
 }
 
 
-
 /**
  * Create a fresh entry in our neighbour list for the given peer.
  * Will try to transmit our current HELLO to the new neighbour.  Also
@@ -2196,17 +2032,13 @@ setup_new_neighbour (const struct GNUNET_PeerIdentity *peer)
   n->id = *peer;
   n->last_quota_update = GNUNET_TIME_absolute_get ();
   n->peer_timeout =
-    GNUNET_TIME_relative_to_absolute (IDLE_CONNECTION_TIMEOUT);
-  n->quota_in = default_quota_in;
+    GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
+  n->quota_in = (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000);
   add_plugins (n);
-  n->hello_version_sent = our_hello_version;
   n->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
-                                                  GNUNET_NO,
-                                                  GNUNET_SCHEDULER_PRIORITY_IDLE,
-                                                  GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
-                                                  IDLE_CONNECTION_TIMEOUT,
+                                                  GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
                                                   &neighbour_timeout_task, n);
-  transmit_to_peer (NULL,
+  transmit_to_peer (NULL, 0,
                     (const struct GNUNET_MessageHeader *) our_hello,
                     GNUNET_YES, n);
   notify_clients_connect (peer, GNUNET_TIME_UNIT_FOREVER_REL);
@@ -2220,6 +2052,7 @@ setup_new_neighbour (const struct GNUNET_PeerIdentity *peer)
  * reducing the rate at which they read from the socket
  * and generally forward to our receive callback.
  *
+ * @param cls the "struct TransportPlugin *" we gave to the plugin
  * @param plugin_context value to pass to this plugin
  *        to respond to the given peer (use is optional,
  *        but may speed up processing)
@@ -2274,13 +2107,19 @@ plugin_env_receive (void *cls,
     }
   if (message == NULL)
     {
+#if DEBUG_TRANSPORT
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
+                 "Receive failed from `%4s', triggering disconnect\n",
+                 GNUNET_i2s(&n->id));
+#endif
+      /* TODO: call stats */
       if ((service_context != NULL) &&
           (service_context->plugin_handle == plugin_context))
         {
           service_context->connected = GNUNET_NO;
           service_context->plugin_handle = NULL;
         }
-      /* TODO: call stats */
+      disconnect_neighbour (n, GNUNET_YES);
       return NULL;
     }
 #if DEBUG_TRANSPORT
@@ -2297,7 +2136,7 @@ plugin_env_receive (void *cls,
           service_context->connect_attempts++;
         }
       service_context->timeout
-        = GNUNET_TIME_relative_to_absolute (IDLE_CONNECTION_TIMEOUT);
+        = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
       service_context->plugin_handle = plugin_context;
       service_context->latency = latency;
     }
@@ -2306,12 +2145,10 @@ plugin_env_receive (void *cls,
   n->last_received += msize;
   GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
   n->peer_timeout =
-    GNUNET_TIME_relative_to_absolute (IDLE_CONNECTION_TIMEOUT);
+    GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
   n->timeout_task =
-    GNUNET_SCHEDULER_add_delayed (sched, GNUNET_NO,
-                                  GNUNET_SCHEDULER_PRIORITY_IDLE,
-                                  GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
-                                  IDLE_CONNECTION_TIMEOUT,
+    GNUNET_SCHEDULER_add_delayed (sched, 
+                                  GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
                                   &neighbour_timeout_task, n);
   update_quota (n);
   if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
@@ -2322,7 +2159,8 @@ plugin_env_receive (void *cls,
                   _
                   ("Dropping incoming message due to repeated bandwidth quota violations.\n"));
       /* TODO: call stats */
-      GNUNET_assert (NULL != service_context->neighbour);
+      GNUNET_assert ( (service_context == NULL) ||
+                     (NULL != service_context->neighbour) );
       return service_context;
     }
   switch (ntohs (message->type))
@@ -2330,20 +2168,16 @@ plugin_env_receive (void *cls,
     case GNUNET_MESSAGE_TYPE_HELLO:
 #if DEBUG_TRANSPORT
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "Receiving `%s' message from other peer.\n", "HELLO");
+                  "Receiving `%s' message from `%4s'.\n", "HELLO",
+                 GNUNET_i2s(peer));
 #endif
       process_hello (plugin, message);
 #if DEBUG_TRANSPORT
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "Sending `%s' message to connecting peer.\n", "ACK");
+                  "Sending `%s' message to connecting peer `%4s'.\n", "ACK",
+                 GNUNET_i2s(peer));
 #endif
-      transmit_to_peer (NULL, &ack, GNUNET_YES, n);
-      break;
-    case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
-      process_ping (plugin, peer, plugin_context, message);
-      break;
-    case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
-      process_pong (plugin, message);
+      transmit_to_peer (NULL, 0, &ack, GNUNET_YES, n);
       break;
     case GNUNET_MESSAGE_TYPE_TRANSPORT_ACK:
       n->saw_ack = GNUNET_YES;
@@ -2351,8 +2185,9 @@ plugin_env_receive (void *cls,
     default:
 #if DEBUG_TRANSPORT
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "Received message of type %u from other peer, sending to all clients.\n",
-                  ntohs (message->type));
+                  "Received message of type %u from `%4s', sending to all clients.\n",
+                  ntohs (message->type),
+                 GNUNET_i2s(peer));
 #endif
       /* transmit message to all clients */
       im = GNUNET_malloc (sizeof (struct InboundMessage) + msize);
@@ -2370,7 +2205,8 @@ plugin_env_receive (void *cls,
         }
       GNUNET_free (im);
     }
-  GNUNET_assert (NULL != service_context->neighbour);
+  GNUNET_assert ( (service_context == NULL) ||
+                 (NULL != service_context->neighbour) );
   return service_context;
 }
 
@@ -2418,7 +2254,8 @@ handle_start (void *cls,
     {
 #if DEBUG_TRANSPORT
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "Sending our own HELLO to new client\n");
+                  "Sending our own `%s' to new client\n",
+                 "HELLO");
 #endif
       transmit_to_client (c,
                           (const struct GNUNET_MessageHeader *) our_hello,
@@ -2426,7 +2263,7 @@ handle_start (void *cls,
       /* tell new client about all existing connections */
       cim.header.size = htons (sizeof (struct ConnectInfoMessage));
       cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
-      cim.quota_out = htonl (default_quota_out);
+      cim.quota_out = htonl (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT / (60 * 1000));
       cim.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO);  /* FIXME? */
       im = GNUNET_malloc (sizeof (struct InboundMessage) +
                           sizeof (struct GNUNET_MessageHeader));
@@ -2530,7 +2367,7 @@ handle_send (void *cls,
               ntohs (obmm->size),
               ntohs (obmm->type), GNUNET_i2s (&obm->peer));
 #endif
-  transmit_to_peer (tc, obmm, GNUNET_NO, n);
+  transmit_to_peer (tc, ntohl(obm->priority), obmm, GNUNET_NO, n);
   GNUNET_SERVER_receive_done (client, GNUNET_OK);
 }
 
@@ -2597,11 +2434,20 @@ handle_try_connect (void *cls,
   tcm = (const struct TryConnectMessage *) message;
 #if DEBUG_TRANSPORT
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Received `%s' request from client asking to connect to `%4s'\n",
-              "TRY_CONNECT", GNUNET_i2s (&tcm->peer));
+              "Received `%s' request from client %p asking to connect to `%4s'\n",
+              "TRY_CONNECT",
+             client,
+             GNUNET_i2s (&tcm->peer));
 #endif
   if (NULL == find_neighbour (&tcm->peer))
     setup_new_neighbour (&tcm->peer);
+#if DEBUG_TRANSPORT
+  else
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+               "Client asked to connect to `%4s', but connection already exists\n",
+               "TRY_CONNECT", 
+               GNUNET_i2s (&tcm->peer));
+#endif    
   GNUNET_SERVER_receive_done (client, GNUNET_OK);
 }
 
@@ -2635,11 +2481,14 @@ create_environment (struct TransportPlugin *plug)
   plug->env.cfg = cfg;
   plug->env.sched = sched;
   plug->env.my_public_key = &my_public_key;
+  plug->env.my_private_key = my_private_key;
+  plug->env.my_identity = &my_identity;
   plug->env.cls = plug;
   plug->env.receive = &plugin_env_receive;
   plug->env.lookup = &plugin_env_lookup_address;
   plug->env.notify_address = &plugin_env_notify_address;
-  plug->env.default_quota_in = default_quota_in;
+  plug->env.notify_validation = &plugin_env_notify_validation;
+  plug->env.default_quota_in = (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000);
   plug->env.max_connections = max_connect_per_transport;
 }
 
@@ -2722,6 +2571,42 @@ client_disconnect_notification (void *cls,
 }
 
 
+/**
+ * Function called when the service shuts down.  Unloads our plugins.
+ *
+ * @param cls closure, unused
+ * @param tc task context (unused)
+ */
+static void
+unload_plugins (void *cls, 
+               const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct TransportPlugin *plug;
+  struct AddressList *al;
+
+#if DEBUG_TRANSPORT
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Transport service is unloading plugins...\n");
+#endif
+  while (NULL != (plug = plugins))
+    {
+      plugins = plug->next;
+      GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
+      GNUNET_free (plug->lib_name);
+      GNUNET_free (plug->short_name);
+      while (NULL != (al = plug->addresses))
+        {
+          plug->addresses = al->next;
+          GNUNET_free (al);
+        }
+      GNUNET_free (plug);
+    }
+  if (my_private_key != NULL)
+    GNUNET_CRYPTO_rsa_key_free (my_private_key);
+  GNUNET_free_non_null (our_hello);
+}
+
+
 /**
  * Initiate transport service.
  *
@@ -2733,13 +2618,12 @@ client_disconnect_notification (void *cls,
 static void
 run (void *cls,
      struct GNUNET_SCHEDULER_Handle *s,
-     struct GNUNET_SERVER_Handle *serv, struct GNUNET_CONFIGURATION_Handle *c)
+     struct GNUNET_SERVER_Handle *serv, 
+     const struct GNUNET_CONFIGURATION_Handle *c)
 {
   char *plugs;
   char *pos;
   int no_transports;
-  unsigned long long qin;
-  unsigned long long qout;
   unsigned long long tneigh;
   char *keyfile;
 
@@ -2747,16 +2631,6 @@ run (void *cls,
   cfg = c;
   /* parse configuration */
   if ((GNUNET_OK !=
-       GNUNET_CONFIGURATION_get_value_number (c,
-                                              "TRANSPORT",
-                                              "DEFAULT_QUOTA_IN",
-                                              &qin)) ||
-      (GNUNET_OK !=
-       GNUNET_CONFIGURATION_get_value_number (c,
-                                              "TRANSPORT",
-                                              "DEFAULT_QUOTA_OUT",
-                                              &qout)) ||
-      (GNUNET_OK !=
        GNUNET_CONFIGURATION_get_value_number (c,
                                               "TRANSPORT",
                                               "NEIGHBOUR_LIMIT",
@@ -2773,8 +2647,6 @@ run (void *cls,
       return;
     }
   max_connect_per_transport = (uint32_t) tneigh;
-  default_quota_in = (uint32_t) qin;
-  default_quota_out = (uint32_t) qout;
   my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
   GNUNET_free (keyfile);
   if (my_private_key == NULL)
@@ -2809,46 +2681,17 @@ run (void *cls,
         }
       GNUNET_free (plugs);
     }
+  GNUNET_SCHEDULER_add_delayed (sched,
+                                GNUNET_TIME_UNIT_FOREVER_REL,
+                                &unload_plugins, NULL);
   if (no_transports)
     refresh_hello ();
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
-  /* process client requests */
-  GNUNET_SERVER_add_handlers (server, handlers);
-}
-
-
-/**
- * Function called when the service shuts
- * down.  Unloads our plugins.
- *
- * @param cls closure
- * @param cfg configuration to use
- */
-static void
-unload_plugins (void *cls, struct GNUNET_CONFIGURATION_Handle *cfg)
-{
-  struct TransportPlugin *plug;
-  struct AddressList *al;
-
 #if DEBUG_TRANSPORT
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Transport service is unloading plugins...\n");
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+             _("Transport service ready.\n"));
 #endif
-  while (NULL != (plug = plugins))
-    {
-      plugins = plug->next;
-      GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
-      GNUNET_free (plug->lib_name);
-      GNUNET_free (plug->short_name);
-      while (NULL != (al = plug->addresses))
-        {
-          plug->addresses = al->next;
-          GNUNET_free (al);
-        }
-      GNUNET_free (plug);
-    }
-  if (my_private_key != NULL)
-    GNUNET_CRYPTO_rsa_key_free (my_private_key);
+  /* process client requests */
+  GNUNET_SERVER_add_handlers (server, handlers);
 }
 
 
@@ -2863,10 +2706,10 @@ int
 main (int argc, char *const *argv)
 {
   return (GNUNET_OK ==
-          GNUNET_SERVICE_run (argc,
-                              argv,
-                              "transport",
-                              &run, NULL, &unload_plugins, NULL)) ? 0 : 1;
+         GNUNET_SERVICE_run (argc,
+                             argv,
+                             "transport",
+                             &run, NULL)) ? 0 : 1;
 }
 
 /* end of gnunet-service-transport.c */