updates to peerinfo to use new nc API
[oweals/gnunet.git] / src / transport / gnunet-service-transport.c
index 2e5240e13876a19119179e17f284e37143a508a8..fe8b5043edac0f921a182254b9e926167f7ba8a3 100644 (file)
 
 /**
  * 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 long will we allow sending of a ping to be delayed?
+ */
+#define TRANSPORT_DEFAULT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
+
+#define TRANSPORT_DEFAULT_PRIORITY 4 /* Tired of remembering arbitrary priority names */
 
 /**
  * How often do we re-add (cheaper) plugins to our list of plugins
@@ -168,11 +180,11 @@ struct TransportPlugin
   int rebuild;
 };
 
-struct NeighbourList;
+struct NeighborList;
 
 /**
- * For each neighbour we keep a list of messages
- * that we still want to transmit to the neighbour.
+ * For each neighbor we keep a list of messages
+ * that we still want to transmit to the neighbor.
  */
 struct MessageQueue
 {
@@ -195,9 +207,9 @@ struct MessageQueue
   struct TransportClient *client;
 
   /**
-   * Neighbour this entry belongs to.
+   * Neighbor this entry belongs to.
    */
-  struct NeighbourList *neighbour;
+  struct NeighborList *neighbor;
 
   /**
    * Plugin that we used for the transmission.
@@ -218,12 +230,12 @@ struct MessageQueue
    * How important is the message?
    */
   unsigned int priority;
-  
+
 };
 
 
 /**
- * For a given Neighbour, which plugins are available
+ * For a given Neighbor, which plugins are available
  * to talk to this peer and what are their costs?
  */
 struct ReadyList
@@ -241,15 +253,9 @@ struct ReadyList
   struct TransportPlugin *plugin;
 
   /**
-   * Neighbour this entry belongs to.
+   * Neighbor this entry belongs to.
    */
-  struct NeighbourList *neighbour;
-
-  /**
-   * Opaque handle (specific to the plugin) for the
-   * connection to our target; can be NULL.
-   */
-  void *plugin_handle;
+  struct NeighborList *neighbor;
 
   /**
    * What was the last latency observed for this plugin
@@ -258,12 +264,11 @@ struct ReadyList
   struct GNUNET_TIME_Relative latency;
 
   /**
-   * If we did not successfully transmit a message to the
-   * given peer via this connection during the specified
-   * time, we should consider the connection to be dead.
-   * This is used in the case that a TCP transport simply
-   * stalls writing to the stream but does not formerly
-   * get a signal that the other peer died.
+   * If we did not successfully transmit a message to the given peer
+   * via this connection during the specified time, we should consider
+   * the connection to be dead.  This is used in the case that a TCP
+   * transport simply stalls writing to the stream but does not
+   * formerly get a signal that the other peer died.
    */
   struct GNUNET_TIME_Absolute timeout;
 
@@ -287,10 +292,10 @@ struct ReadyList
   unsigned int connect_attempts;
 
   /**
-   * Is this plugin ready to transmit to the specific
-   * target?  GNUNET_NO if not.  Initially, all plugins
-   * are marked ready.  If a transmission is in progress,
-   * "transmit_ready" is set to GNUNET_NO.
+   * Is this plugin ready to transmit to the specific target?
+   * GNUNET_NO if not.  Initially, all plugins are marked ready.  If a
+   * transmission is in progress, "transmit_ready" is set to
+   * GNUNET_NO.
    */
   int transmit_ready;
 
@@ -298,15 +303,15 @@ struct ReadyList
 
 
 /**
- * Entry in linked list of all of our current neighbours.
+ * Entry in linked list of all of our current neighbors.
  */
-struct NeighbourList
+struct NeighborList
 {
 
   /**
    * This is a linked list.
    */
-  struct NeighbourList *next;
+  struct NeighborList *next;
 
   /**
    * Which of our transports is connected to this peer
@@ -321,10 +326,20 @@ struct NeighbourList
   struct MessageQueue *messages;
 
   /**
-   * Identity of this neighbour.
+   * Identity of this neighbor.
    */
   struct GNUNET_PeerIdentity id;
 
+  /*
+   * Opaque addr of this peer, only known to the plugin
+   */
+  char *addr;
+
+  /*
+   * Size of addr
+   */
+  size_t addr_len;
+
   /**
    * ID of task scheduled to run when this peer is about to
    * time out (will free resources associated with the peer).
@@ -356,7 +371,7 @@ struct NeighbourList
   uint64_t last_received;
 
   /**
-   * Global quota for inbound traffic for the neighbour in bytes/ms.
+   * Global quota for inbound traffic for the neighbor in bytes/ms.
    */
   uint32_t quota_in;
 
@@ -369,15 +384,96 @@ struct NeighbourList
   unsigned int quota_violation_count;
 
   /**
-   * Have we seen an ACK from this neighbour in the past?
+   * Have we seen an ACK from this neighbor in the past?
    * (used to make up a fake ACK for clients connecting after
-   * the neighbour connected to us).
+   * the neighbor connected to us).
    */
   int saw_ack;
 
+  /* The latency we have seen for this particular address for
+   * this particular peer.  This latency may have been calculated
+   * over multiple transports.  This value reflects how long it took
+   * us to receive a response when SENDING via this particular
+   * transport/neighbor/address combination!
+   */
+  struct GNUNET_TIME_RelativeNBO latency;
+
+};
+
+/**
+ * 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 TransportPingMessage
+{
+
+  /**
+   * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
+   */
+  struct GNUNET_MessageHeader header;
+
+  /**
+   * 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.  The challenge is included in the
+ * confirmation to make matching of replies to requests possible.  The
+ * signature signs the original challenge number, our public key, the
+ * sender's address (so that the sender can check that the address we
+ * saw is plausible for him and possibly detect a MiM attack) and a
+ * timestamp (to limit replay).<p>
+ *
+ * This message is followed by the address of the
+ * client that we are observing (which is part of what
+ * is being signed).
+ */
+struct TransportPongMessage
+{
+
+  /**
+   * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
+   */
+  struct GNUNET_MessageHeader header;
+
+  /**
+   * For padding, always zero.
+   */
+  uint32_t reserved GNUNET_PACKED;
+
+  /**
+   * Signature.
+   */
+  struct GNUNET_CRYPTO_RsaSignature signature;
+
+  /**
+   * What are we signing and why?
+   */
+  struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
+
+  /**
+   * Random challenge number (in network byte order).
+   */
+  uint32_t challenge GNUNET_PACKED;
+
+  /**
+   * Who signed this message?
+   */
+  struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded signer;
+
+};
+
 /**
  * Linked list of messages to be transmitted to
  * the client.  Each entry is followed by the
@@ -519,7 +615,7 @@ static struct GNUNET_HELLO_Message *our_hello;
 
 /**
  * "version" of "our_hello".  Used to see if a given
- * neighbour has already been sent the latest version
+ * neighbor has already been sent the latest version
  * of our HELLO message.
  */
 static unsigned int our_hello_version;
@@ -547,7 +643,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.
@@ -565,28 +661,43 @@ static struct TransportPlugin *plugins;
 static struct GNUNET_SERVER_Handle *server;
 
 /**
- * All known neighbours and their HELLOs.
+ * All known neighbors and their HELLOs.
  */
-static struct NeighbourList *neighbours;
+static struct NeighborList *neighbors;
 
 /**
- * Number of neighbours we'd like to have.
+ * Number of neighbors we'd like to have.
  */
 static uint32_t max_connect_per_transport;
 
 
 /**
- * Find an entry in the neighbour list for a particular peer.
+ * Find an entry in the neighbor list for a particular peer.
+ * if sender_address is not specified (NULL) then return the
+ * first matching entry.  If sender_address is specified, then
+ * make sure that the address and address_len also matches.
  *
  * @return NULL if not found.
  */
-static struct NeighbourList *
-find_neighbour (const struct GNUNET_PeerIdentity *key)
+static struct NeighborList *
+find_neighbor (const struct GNUNET_PeerIdentity *key, const char *sender_address,
+    size_t sender_address_len)
 {
-  struct NeighbourList *head = neighbours;
-  while ((head != NULL) &&
-         (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
-    head = head->next;
+  struct NeighborList *head = neighbors;
+  if (sender_address == NULL)
+    {
+      while ((head != NULL) &&
+            (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
+        head = head->next;
+    }
+    else
+    {
+      while ((head != NULL) &&
+             (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))) &&
+             (sender_address_len != head->addr_len) &&
+             (0 != memcmp (sender_address, &head->addr, head->addr_len)))
+        head = head->next;
+    }
   return head;
 }
 
@@ -607,10 +718,10 @@ find_transport (const char *short_name)
 
 
 /**
- * Update the quota values for the given neighbour now.
+ * Update the quota values for the given neighbor now.
  */
 static void
-update_quota (struct NeighbourList *n)
+update_quota (struct NeighborList *n)
 {
   struct GNUNET_TIME_Relative delta;
   uint64_t allowed;
@@ -667,13 +778,13 @@ 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)
     {
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                 "Transmission to client failed, closing connection.\n");
+                  "Transmission to client failed, closing connection.\n");
       /* fatal error with client, free message queue! */
       while (NULL != (q = client->message_queue_head))
         {
@@ -692,6 +803,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;
@@ -700,9 +816,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,
@@ -730,7 +846,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))
     {
@@ -743,6 +859,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 */
@@ -771,22 +888,22 @@ transmit_to_client (struct TransportClient *client,
 /**
  * Find alternative plugins for communication.
  *
- * @param neighbour for which neighbour should we try to find
+ * @param neighbor for which neighbor should we try to find
  *        more plugins?
  */
 static void
-try_alternative_plugins (struct NeighbourList *neighbour)
+try_alternative_plugins (struct NeighborList *neighbor)
 {
   struct ReadyList *rl;
 
-  if ((neighbour->plugins != NULL) &&
-      (neighbour->retry_plugins_time.value >
+  if ((neighbor->plugins != NULL) &&
+      (neighbor->retry_plugins_time.value >
        GNUNET_TIME_absolute_get ().value))
     return;                     /* don't try right now */
-  neighbour->retry_plugins_time
+  neighbor->retry_plugins_time
     = GNUNET_TIME_relative_to_absolute (PLUGIN_RETRY_FREQUENCY);
 
-  rl = neighbour->plugins;
+  rl = neighbor->plugins;
   while (rl != NULL)
     {
       if (rl->connect_attempts > 0)
@@ -798,13 +915,29 @@ try_alternative_plugins (struct NeighbourList *neighbour)
 
 
 /**
- * Check the ready list for the given neighbour and
+ * The peer specified by the given neighbor 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 neighbor is now officially
+ * gone.
+ *
+ * @param n the neighbor 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_neighbor (struct NeighborList *n, int check);
+
+
+/**
+ * Check the ready list for the given neighbor and
  * if a plugin is ready for transmission (and if we
  * have a message), do so!
  *
- * @param neighbour target peer for which to check the plugins
+ * @param neighbor target peer for which to check the plugins
  */
-static void try_transmission_to_peer (struct NeighbourList *neighbour);
+static void try_transmission_to_peer (struct NeighborList *neighbor);
 
 
 /**
@@ -816,9 +949,6 @@ static void try_transmission_to_peer (struct NeighbourList *neighbour);
  * @param cls closure, identifies the entry on the
  *            message queue that was transmitted and the
  *            client responsible for queueing the message
- * @param rl identifies plugin used for the transmission for
- *           this neighbour; needs to be re-enabled for
- *           future transmissions
  * @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
@@ -826,42 +956,44 @@ static void try_transmission_to_peer (struct NeighbourList *neighbour);
  */
 static void
 transmit_send_continuation (void *cls,
-                            struct ReadyList *rl,
                             const struct GNUNET_PeerIdentity *target,
                             int result)
 {
   struct MessageQueue *mq = cls;
+  struct ReadyList *rl;
   struct SendOkMessage send_ok_msg;
-  struct NeighbourList *n;
+  struct NeighborList *n;
 
   GNUNET_assert (mq != NULL);
-  n = mq->neighbour;
+  n = mq->neighbor;
   GNUNET_assert (n != NULL);
   GNUNET_assert (0 ==
                  memcmp (&n->id, target,
                          sizeof (struct GNUNET_PeerIdentity)));
-  if (rl == NULL)
-    {
-      rl = n->plugins;
-      while ((rl != NULL) && (rl->plugin != mq->plugin))
-        rl = rl->next;
-      GNUNET_assert (rl != NULL);
-    }
+  rl = n->plugins;
+  while ((rl != NULL) && (rl->plugin != mq->plugin))
+    rl = rl->next;
+  GNUNET_assert (rl != NULL);
   if (result == GNUNET_OK)
     {
-      rl->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
+      rl->timeout =
+        GNUNET_TIME_relative_to_absolute
+        (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
     }
   else
     {
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                 "Transmission to peer `%s' failed, marking connection as down.\n",
-                 GNUNET_i2s(target));
+                  "Transmission to peer `%s' failed, marking connection as down.\n",
+                  GNUNET_i2s (target));
       rl->connected = GNUNET_NO;
     }
   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);
@@ -872,17 +1004,20 @@ 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);
+  if (result == GNUNET_OK)
+    try_transmission_to_peer (n);
+  else
+    disconnect_neighbor (n, GNUNET_YES);
 }
 
 
 /**
- * Check the ready list for the given neighbour and
+ * Check the ready list for the given neighbor and
  * if a plugin is ready for transmission (and if we
  * have a message), do so!
  */
 static void
-try_transmission_to_peer (struct NeighbourList *neighbour)
+try_transmission_to_peer (struct NeighborList *neighbor)
 {
   struct ReadyList *pos;
   struct GNUNET_TIME_Relative min_latency;
@@ -890,14 +1025,14 @@ try_transmission_to_peer (struct NeighbourList *neighbour)
   struct MessageQueue *mq;
   struct GNUNET_TIME_Absolute now;
 
-  if (neighbour->messages == NULL)
+  if (neighbor->messages == NULL)
     return;                     /* nothing to do */
-  try_alternative_plugins (neighbour);
+  try_alternative_plugins (neighbor);
   min_latency = GNUNET_TIME_UNIT_FOREVER_REL;
   rl = NULL;
-  mq = neighbour->messages;
+  mq = neighbor->messages;
   now = GNUNET_TIME_absolute_get ();
-  pos = neighbour->plugins;
+  pos = neighbor->plugins;
   while (pos != NULL)
     {
       /* set plugins that are inactive for a long time back to disconnected */
@@ -906,7 +1041,7 @@ try_transmission_to_peer (struct NeighbourList *neighbour)
 #if DEBUG_TRANSPORT
           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                       "Marking long-time inactive connection to `%4s' as down.\n",
-                      GNUNET_i2s (&neighbour->id));
+                      GNUNET_i2s (&neighbor->id));
 #endif
           pos->connected = GNUNET_NO;
         }
@@ -933,12 +1068,12 @@ 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);
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "Establishing fresh connection with `%4s' via plugin `%s'\n",
+                  GNUNET_i2s (&neighbor->id), rl->plugin->short_name);
 #endif
     }
-  neighbour->messages = mq->next;
+  neighbor->messages = mq->next;
   mq->plugin = rl->plugin;
   if (!mq->internal_msg)
     rl->transmit_ready = GNUNET_NO;
@@ -946,17 +1081,18 @@ try_transmission_to_peer (struct NeighbourList *neighbour)
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Giving message of type `%u' for `%4s' to plugin `%s'\n",
               ntohs (mq->message->type),
-              GNUNET_i2s (&neighbour->id), rl->plugin->short_name);
+              GNUNET_i2s (&neighbor->id), rl->plugin->short_name);
 #endif
-  rl->plugin_handle
-    = rl->plugin->api->send (rl->plugin->api->cls,
-                             rl->plugin_handle,
-                             rl,
-                             &neighbour->id,
-                            mq->priority,
-                             mq->message,
-                             GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
-                             &transmit_send_continuation, mq);
+
+  rl->plugin->api->send (rl->plugin->api->cls,
+                         &neighbor->id,
+                         mq->message,
+                         mq->priority,
+                         GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
+                         rl->neighbor->addr,
+                         rl->neighbor->addr_len,
+                         GNUNET_NO,
+                         &transmit_send_continuation, mq);
 }
 
 
@@ -967,13 +1103,13 @@ try_transmission_to_peer (struct NeighbourList *neighbour)
  * @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
+ * @param neighbor handle to the neighbor for transmission
  */
 static void
 transmit_to_peer (struct TransportClient *client,
-                 unsigned int priority,
+                  unsigned int priority,
                   const struct GNUNET_MessageHeader *msg,
-                  int is_internal, struct NeighbourList *neighbour)
+                  int is_internal, struct NeighborList *neighbor)
 {
   struct MessageQueue *mq;
   struct MessageQueue *mqe;
@@ -982,12 +1118,12 @@ transmit_to_peer (struct TransportClient *client,
 #if DEBUG_TRANSPORT
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               _("Sending message of type %u to peer `%4s'\n"),
-              ntohs (msg->type), GNUNET_i2s (&neighbour->id));
+              ntohs (msg->type), GNUNET_i2s (&neighbor->id));
 #endif
   if (client != NULL)
     {
       /* check for duplicate submission */
-      mq = neighbour->messages;
+      mq = neighbor->messages;
       while (NULL != mq)
         {
           if (mq->client == client)
@@ -1005,20 +1141,20 @@ transmit_to_peer (struct TransportClient *client,
   m = GNUNET_malloc (ntohs (msg->size));
   memcpy (m, msg, ntohs (msg->size));
   mq->message = m;
-  mq->neighbour = neighbour;
+  mq->neighbor = neighbor;
   mq->internal_msg = is_internal;
   mq->priority = priority;
 
   /* find tail */
-  mqe = neighbour->messages;
+  mqe = neighbor->messages;
   if (mqe != NULL)
     while (mqe->next != NULL)
       mqe = mqe->next;
   if (mqe == NULL)
     {
       /* new head */
-      neighbour->messages = mq;
-      try_transmission_to_peer (neighbour);
+      neighbor->messages = mq;
+      try_transmission_to_peer (neighbor);
     }
   else
     {
@@ -1028,6 +1164,9 @@ transmit_to_peer (struct TransportClient *client,
 }
 
 
+/**
+ * FIXME: document.
+ */
 struct GeneratorContext
 {
   struct TransportPlugin *plug_pos;
@@ -1036,6 +1175,9 @@ struct GeneratorContext
 };
 
 
+/**
+ * FIXME: document.
+ */
 static size_t
 address_generator (void *cls, size_t max, void *buf)
 {
@@ -1067,13 +1209,12 @@ refresh_hello ()
 {
   struct GNUNET_HELLO_Message *hello;
   struct TransportClient *cpos;
-  struct NeighbourList *npos;
+  struct NeighborList *npos;
   struct GeneratorContext gc;
 
 #if DEBUG_TRANSPORT
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
-              "Refreshing my `%s'\n",
-             "HELLO");
+              "Refreshing my `%s'\n", "HELLO");
 #endif
   gc.plug_pos = plugins;
   gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
@@ -1091,14 +1232,14 @@ refresh_hello ()
   GNUNET_free_non_null (our_hello);
   our_hello = hello;
   our_hello_version++;
-  npos = neighbours;
+  GNUNET_PEERINFO_add_peer (cfg, sched, &my_identity, our_hello);
+  npos = neighbors;
   while (npos != 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));
+                  "Transmitting updated `%s' to neighbor `%4s'\n",
+                  "HELLO", GNUNET_i2s (&npos->id));
 #endif
       transmit_to_peer (NULL, 0,
                         (const struct GNUNET_MessageHeader *) our_hello,
@@ -1139,9 +1280,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;
@@ -1174,9 +1315,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);
 
@@ -1193,7 +1331,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);
 }
 
@@ -1238,7 +1376,7 @@ plugin_env_notify_address (void *cls,
 #if DEBUG_TRANSPORT
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Plugin `%s' informs us about a new address `%s'\n", name,
-             GNUNET_a2s(addr, addrlen));
+              GNUNET_a2s (addr, addrlen));
 #endif
   al = GNUNET_malloc (sizeof (struct AddressList) + addrlen);
   al->addr = &al[1];
@@ -1251,74 +1389,6 @@ plugin_env_notify_address (void *cls,
 }
 
 
-struct LookupHelloContext
-{
-  GNUNET_TRANSPORT_AddressCallback iterator;
-
-  void *iterator_cls;
-};
-
-
-static int
-lookup_address_callback (void *cls,
-                         const char *tname,
-                         struct GNUNET_TIME_Absolute expiration,
-                         const void *addr, size_t addrlen)
-{
-  struct LookupHelloContext *lhc = cls;
-  lhc->iterator (lhc->iterator_cls, tname, addr, addrlen);
-  return GNUNET_OK;
-}
-
-
-static void
-lookup_hello_callback (void *cls,
-                       const struct GNUNET_PeerIdentity *peer,
-                       const struct GNUNET_HELLO_Message *h, uint32_t trust)
-{
-  struct LookupHelloContext *lhc = cls;
-
-  if (peer == NULL)
-    {
-      lhc->iterator (lhc->iterator_cls, NULL, NULL, 0);
-      GNUNET_free (lhc);
-      return;
-    }
-  if (h == NULL)
-    return;
-  GNUNET_HELLO_iterate_addresses (h,
-                                  GNUNET_NO, &lookup_address_callback, lhc);
-}
-
-
-/**
- * Function that allows a transport to query the known
- * network addresses for a given peer.
- *
- * @param cls closure
- * @param timeout after how long should we time out?
- * @param target which peer are we looking for?
- * @param iter function to call for each known address
- * @param iter_cls closure for iter
- */
-static void
-plugin_env_lookup_address (void *cls,
-                           struct GNUNET_TIME_Relative timeout,
-                           const struct GNUNET_PeerIdentity *target,
-                           GNUNET_TRANSPORT_AddressCallback iter,
-                           void *iter_cls)
-{
-  struct LookupHelloContext *lhc;
-
-  lhc = GNUNET_malloc (sizeof (struct LookupHelloContext));
-  lhc->iterator = iter;
-  lhc->iterator_cls = iter_cls;
-  GNUNET_PEERINFO_for_all (cfg,
-                           sched,
-                           target, 0, timeout, &lookup_hello_callback, &lhc);
-}
-
-
 /**
  * Notify all of our clients about a peer connecting.
  */
@@ -1336,7 +1406,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 (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT / (60*1000));
+  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;
@@ -1409,9 +1479,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;
+  struct NeighborList *n;
 
 #if DEBUG_TRANSPORT
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
@@ -1441,9 +1512,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);           
+          n = find_neighbor (&pid, NULL, 0);
+          if (NULL != n)
+            try_transmission_to_peer (n);
           GNUNET_free (hello);
           while (NULL != (va = pos->addresses))
             {
@@ -1457,27 +1528,43 @@ cleanup_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
           else
             pos = prev->next;
           continue;
-       }
+        }
       prev = pos;
       pos = pos->next;
     }
 
   /* finally, reschedule cleanup if needed; list is
      ordered by timeout, so we need the last element... */
-  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);
+  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);
+    }
 }
 
 
+static struct GNUNET_MessageHeader *
+createPingMessage (struct GNUNET_PeerIdentity * target, struct ValidationAddress *va)
+{
 
+  struct TransportPingMessage *ping;
+  ping = GNUNET_malloc(sizeof(struct TransportPingMessage));
+
+  ping->challenge = htonl(va->challenge);
+  ping->header.size = sizeof(struct TransportPingMessage);
+  ping->header.type = GNUNET_MESSAGE_TYPE_TRANSPORT_PING;
+  memcpy(&ping->target, target, sizeof(struct GNUNET_PeerIdentity));
+
+  return &ping->header;
+}
 
 /**
  * Function that will be called if we receive a validation
@@ -1495,18 +1582,19 @@ cleanup_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  *         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)
+handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
+             const struct GNUNET_PeerIdentity *peer,
+             const char *sender_address,
+             size_t sender_address_len)
 {
-  int all_done;
+  unsigned int not_done;
   int matched;
   struct ValidationList *pos;
   struct ValidationAddress *va;
   struct GNUNET_PeerIdentity id;
+  struct TransportPongMessage *pong = (struct TransportPongMessage *)message;
 
+  unsigned int challenge = ntohl(pong->challenge);
   pos = pending_validations;
   while (pos != NULL)
     {
@@ -1514,8 +1602,7 @@ plugin_env_notify_validation (void *cls,
                           sizeof (struct
                                   GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
                           &id.hashPubKey);
-      if (0 ==
-          memcmp (peer, &id, sizeof (struct GNUNET_PeerIdentity)))
+      if (0 == memcmp (peer, &id, sizeof (struct GNUNET_PeerIdentity)))
         break;
       pos = pos->next;
     }
@@ -1525,31 +1612,34 @@ plugin_env_notify_validation (void *cls,
       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
                   _
                   ("Received validation response but have no record of any validation request for `%4s'. Ignoring.\n"),
-                 GNUNET_i2s(peer));
+                  GNUNET_i2s (peer));
       return;
     }
-  all_done = GNUNET_YES;
+  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 peer address.\n");
+          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;
-       }        
+          GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
+                      _
+                      ("Another peer saw us using the address `%s' via `FIXME'. If this is not plausible, this address should be listed in the configuration as implausible to avoid MiM attacks.\n"),
+                      sender_address);
+          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;
+        not_done++;
       va = va->next;
     }
   if (GNUNET_NO == matched)
@@ -1560,15 +1650,25 @@ plugin_env_notify_validation (void *cls,
                   ("Received `%s' message but have no record of a matching `%s' message. Ignoring.\n"),
                   "PONG", "PING");
     }
-  if (GNUNET_YES == all_done)
+  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_delayed (sched,
-                                    GNUNET_NO,
-                                    GNUNET_SCHEDULER_PRIORITY_IDLE,
-                                    GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
-                                    GNUNET_TIME_UNIT_ZERO,
-                                    &cleanup_validation, NULL);
+      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
     }
 }
 
@@ -1590,6 +1690,12 @@ struct CheckHelloValidatedContext
    */
   struct ValidationList *e;
 
+  /**
+   * Context for peerinfo iteration.
+   * NULL after we are done processing peerinfo's information.
+   */
+  struct GNUNET_PEERINFO_IteratorContext *piter;
+
 };
 
 
@@ -1607,7 +1713,7 @@ run_validation (void *cls,
   struct TransportPlugin *tp;
   struct ValidationAddress *va;
   struct GNUNET_PeerIdentity id;
-
+  struct GNUNET_MessageHeader *pingMessage;
   tp = find_transport (tname);
   if (tp == NULL)
     {
@@ -1619,14 +1725,12 @@ run_validation (void *cls,
       return GNUNET_OK;
     }
   GNUNET_CRYPTO_hash (&e->publicKey,
-                     sizeof (struct
-                             GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
-                     &id.hashPubKey);
+                      sizeof (struct
+                              GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
+                      &id.hashPubKey);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Scheduling validation of address `%s' via `%s' for `%4s'\n",
-             GNUNET_a2s(addr, addrlen),
-             tname,
-             GNUNET_i2s(&id));
+              "Scheduling validation of address `%s' via `%s' for `%4s'\n",
+              GNUNET_a2s (addr, addrlen), tname, GNUNET_i2s (&id));
 
   va = GNUNET_malloc (sizeof (struct ValidationAddress) + addrlen);
   va->next = e->addresses;
@@ -1634,11 +1738,45 @@ run_validation (void *cls,
   va->transport_name = GNUNET_strdup (tname);
   va->addr_len = addrlen;
   va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
-                                           (unsigned int) -1);
+                                            (unsigned int) -1);
   memcpy (&va[1], addr, addrlen);
+
+  pingMessage = createPingMessage(&id, va);
+
+  tp->api->send(tp->api->cls, &id, pingMessage, GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+                TRANSPORT_DEFAULT_TIMEOUT, addr, addrlen, GNUNET_YES, NULL, NULL);
+
+  GNUNET_free(pingMessage);
+
   return GNUNET_OK;
 }
 
+/*
+ * @param cls handle to the plugin (for sending)
+ * @param target the peer identity of the peer we are sending to
+ * @param challenge the challenge number
+ * @param timeout how long to await validation?
+ * @param addr the address to validate
+ * @param addrlen the length of the address
+ *
+ * Perform address validation, which means sending a PING PONG to
+ * the address via the transport plugin.  If not validated, then
+ * do not count this as a good peer/address...
+ *
+ */
+static void
+validate_address (void *cls, struct ValidationAddress *va,
+                  const struct GNUNET_PeerIdentity *target,
+                  struct GNUNET_TIME_Relative timeout,
+                  const void *addr, size_t addrlen)
+{
+  /* struct Plugin *plugin = cls;
+  int challenge = va->challenge; */
+
+
+  return;
+}
+
 
 /**
  * Check if addresses in validated hello "h" overlap with
@@ -1648,8 +1786,7 @@ 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;
@@ -1660,6 +1797,7 @@ check_hello_validated (void *cls,
   first_call = GNUNET_NO;
   if (chvc->e == NULL)
     {
+      chvc->piter = NULL;
       first_call = GNUNET_YES;
       chvc->e = GNUNET_malloc (sizeof (struct ValidationList));
       GNUNET_assert (GNUNET_OK ==
@@ -1686,39 +1824,36 @@ 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));
+  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'\n",
+                  "Establishing `%s' connection to validate `%s' address `%s' of `%4s'\n",
                   va->transport_name,
                   "HELLO",
-                 GNUNET_i2s (&apeer));
+                  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 (GNUNET_OK !=
-          tp->api->validate (tp->api->cls,
-                            &apeer,
-                            va->challenge,
-                            HELLO_VERIFICATION_TIMEOUT,
-                            &va[1],
-                            va->addr_len))
-        va->ok = GNUNET_SYSERR;
+      /* This validation should happen inside the transport, not from the plugin! */
+      validate_address (tp->api->cls, va, &apeer,
+                        HELLO_VERIFICATION_TIMEOUT,
+                        &va[1], va->addr_len);
+      /* va->ok = GNUNET_SYSERR; will be set by validate_address! */
       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);
 }
 
@@ -1779,10 +1914,10 @@ process_hello (struct TransportPlugin *plugin,
         {
           /* TODO: call to stats? */
 #if DEBUG_TRANSPORT
-         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                     "`%s' message for peer `%4s' is already pending; ignoring new message\n",
-                     "HELLO", GNUNET_i2s (&target));
-#endif   
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                      "`%s' message for peer `%4s' is already pending; ignoring new message\n",
+                      "HELLO", GNUNET_i2s (&target));
+#endif
           return GNUNET_OK;
         }
       e = e->next;
@@ -1793,39 +1928,55 @@ process_hello (struct TransportPlugin *plugin,
   memcpy (chvc->hello, hello, hsize);
   /* finally, check if HELLO was previously validated
      (continuation will then schedule actual validation) */
-  GNUNET_PEERINFO_for_all (cfg,
-                           sched,
-                           &target,
-                           0,
-                           HELLO_VERIFICATION_TIMEOUT,
-                           &check_hello_validated, chvc);
+  chvc->piter = GNUNET_PEERINFO_iterate (cfg,
+                                         sched,
+                                         &target,
+                                         0,
+                                         HELLO_VERIFICATION_TIMEOUT,
+                                         &check_hello_validated, chvc);
   return GNUNET_OK;
 }
 
 
-
 /**
- * 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 neighbor 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 neighbor is now officially
+ * gone.
  *
- * @param n the neighbour list entry for the peer
+ * @param n the neighbor 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_neighbor (struct NeighborList *n, int check)
 {
   struct ReadyList *rpos;
-  struct NeighbourList *npos;
-  struct NeighbourList *nprev;
+  struct NeighborList *npos;
+  struct NeighborList *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 */
+  /* remove n from neighbors list */
   nprev = NULL;
-  npos = neighbours;
+  npos = neighbors;
   while ((npos != NULL) && (npos != n))
     {
       nprev = npos;
@@ -1833,20 +1984,20 @@ disconnect_neighbour (struct NeighbourList *n)
     }
   GNUNET_assert (npos != NULL);
   if (nprev == NULL)
-    neighbours = n->next;
+    neighbors = n->next;
   else
     nprev->next = n->next;
 
   /* 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);
+      GNUNET_assert (rpos->neighbor == n);
+      if (GNUNET_YES == rpos->connected)
+        rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
       GNUNET_free (rpos);
     }
 
@@ -1854,10 +2005,11 @@ disconnect_neighbour (struct NeighbourList *n)
   while (NULL != (mq = n->messages))
     {
       n->messages = mq->next;
-      GNUNET_assert (mq->neighbour == n);
+      GNUNET_assert (mq->neighbor == 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);
 }
@@ -1866,17 +2018,17 @@ disconnect_neighbour (struct NeighbourList *n)
 /**
  * Add an entry for each of our transport plugins
  * (that are able to send) to the list of plugins
- * for this neighbour.
+ * for this neighbor.
  *
- * @param neighbour to initialize
+ * @param neighbor to initialize
  */
 static void
-add_plugins (struct NeighbourList *neighbour)
+add_plugins (struct NeighborList *neighbor)
 {
   struct TransportPlugin *tp;
   struct ReadyList *rl;
 
-  neighbour->retry_plugins_time
+  neighbor->retry_plugins_time
     = GNUNET_TIME_relative_to_absolute (PLUGIN_RETRY_FREQUENCY);
   tp = plugins;
   while (tp != NULL)
@@ -1884,10 +2036,10 @@ add_plugins (struct NeighbourList *neighbour)
       if (tp->api->send != NULL)
         {
           rl = GNUNET_malloc (sizeof (struct ReadyList));
-          rl->next = neighbour->plugins;
-          neighbour->plugins = rl;
+          rl->next = neighbor->plugins;
+          neighbor->plugins = rl;
           rl->plugin = tp;
-          rl->neighbour = neighbour;
+          rl->neighbor = neighbor;
           rl->transmit_ready = GNUNET_YES;
         }
       tp = tp->next;
@@ -1896,55 +2048,52 @@ add_plugins (struct NeighbourList *neighbour)
 
 
 static void
-neighbour_timeout_task (void *cls,
+neighbor_timeout_task (void *cls,
                         const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
-  struct NeighbourList *n = cls;
+  struct NeighborList *n = cls;
 
 #if DEBUG_TRANSPORT
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
-              "Neighbour has timed out!\n");
+              "Neighbor `%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_neighbor (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
+ * Create a fresh entry in our neighbor list for the given peer.
+ * Will try to transmit our current HELLO to the new neighbor.  Also
  * notifies our clients about the new "connection".
  *
  * @param peer the peer for which we create the entry
- * @return the new neighbour list entry
+ * @return the new neighbor list entry
  */
-static struct NeighbourList *
-setup_new_neighbour (const struct GNUNET_PeerIdentity *peer)
+static struct NeighborList *
+setup_new_neighbor (const struct GNUNET_PeerIdentity *peer, const char *addr, size_t sender_address_len)
 {
-  struct NeighbourList *n;
+  struct NeighborList *n;
 
 #if DEBUG_TRANSPORT
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
-              "Setting up new neighbour `%4s', sending our HELLO to introduce ourselves\n",
+              "Setting up new neighbor `%4s', sending our HELLO to introduce ourselves\n",
               GNUNET_i2s (peer));
 #endif
   GNUNET_assert (our_hello != NULL);
-  n = GNUNET_malloc (sizeof (struct NeighbourList));
-  n->next = neighbours;
-  neighbours = n;
+  n = GNUNET_malloc (sizeof (struct NeighborList));
+  n->next = neighbors;
+  neighbors = n;
   n->id = *peer;
   n->last_quota_update = GNUNET_TIME_absolute_get ();
   n->peer_timeout =
-    GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
+    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->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
-                                                  GNUNET_NO,
-                                                  GNUNET_SCHEDULER_PRIORITY_IDLE,
-                                                  GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
                                                   GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
-                                                  &neighbour_timeout_task, n);
+                                                  &neighbor_timeout_task, n);
   transmit_to_peer (NULL, 0,
                     (const struct GNUNET_MessageHeader *) our_hello,
                     GNUNET_YES, n);
@@ -1952,6 +2101,85 @@ setup_new_neighbour (const struct GNUNET_PeerIdentity *peer)
   return n;
 }
 
+/*
+ * We have received a PING message from someone.  Need to send a PONG message
+ * in response to the peer by any means necessary.  Of course, with something
+ * like TCP where a connection exists, we may want to send it that way.  But
+ * we may not be able to make that distinction...
+ */
+static int handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
+                       const struct GNUNET_PeerIdentity *peer,
+                       const char *sender_address,
+                       size_t sender_address_len)
+{
+  struct TransportPlugin *plugin = cls;
+  struct TransportPingMessage *ping;
+  struct TransportPongMessage *pong;
+  uint16_t msize;
+
+  pong = GNUNET_malloc(sizeof(struct TransportPongMessage));
+
+#if DEBUG_TRANSPORT
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
+                "Processing `%s' from `%s'\n",
+               "PING", GNUNET_a2s ((const struct sockaddr *)sender_address, sender_address_len));
+#endif
+
+  msize = ntohs (message->size);
+  if (msize < sizeof (struct TransportPingMessage))
+    {
+      GNUNET_break_op (0);
+      return GNUNET_SYSERR;
+    }
+  ping = (struct TransportPingMessage *) message;
+  if (0 != memcmp (&ping->target,
+                   plugin->env.my_identity,
+                   sizeof (struct GNUNET_PeerIdentity)))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                  _("Received `%s' message not destined for me!\n"), "PING");
+      return GNUNET_SYSERR;
+    }
+
+  msize -= sizeof (struct TransportPingMessage);
+/*
+ * if (GNUNET_OK != tcp_plugin_address_suggested (plugin, &vcm[1], msize))
+    {
+      GNUNET_break_op (0);
+      GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+      return;
+    }
+
+  if (GNUNET_OK != GNUNET_SERVER_client_get_address (client, &addr, &addrlen))
+    {
+      GNUNET_break (0);
+      GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+      return;
+    }
+*/
+  pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len);
+  pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len);
+  pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
+  pong->purpose.size =
+    htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
+           sizeof (uint32_t) +
+           sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + sender_address_len);
+  pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_TCP_PING);
+  pong->challenge = ping->challenge;
+
+  memcpy(&pong->signer, &my_public_key, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
+  memcpy (&pong[1], sender_address, sender_address_len);
+  GNUNET_assert (GNUNET_OK ==
+                 GNUNET_CRYPTO_rsa_sign (my_private_key,
+                                         &pong->purpose, &pong->signature));
+
+  transmit_to_peer(NULL, TRANSPORT_DEFAULT_PRIORITY, &pong->header, GNUNET_NO, find_neighbor(peer, NULL, 0));
+  /* plugin->api->send(); */ /* We can't directly send back along received address, because
+                          the port we saw for the peer (for TCP especially) will not
+                          likely be the open port on the other side! */
+  GNUNET_free(pong);
+  return GNUNET_OK;
+}
 
 /**
  * Function called by the plugin for each received message.
@@ -1959,68 +2187,58 @@ 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 plugin_context value to pass to this plugin
- *        to respond to the given peer (use is optional,
- *        but may speed up processing)
- * @param service_context value passed to the transport-service
- *        to identify the neighbour; will be NULL on the first
- *        call for a given peer
- * @param latency estimated latency for communicating with the
- *             given peer
- * @param peer (claimed) identity of the other peer
+ * @param cls the "struct TransportPlugin *" we gave to the plugin
  * @param message the message, NULL if peer was disconnected
+ * @param distance the transport cost to this peer (not latency!)
+ * @param sender_address the address that the sender reported
+ *        (opaque to transport service)
+ * @param sender_address_len the length of the sender address
+ * @param peer (claimed) identity of the other peer
  * @return the new service_context that the plugin should use
  *         for future receive calls for messages from this
  *         particular peer
+ *
  */
-static struct ReadyList *
-plugin_env_receive (void *cls,
-                    void *plugin_context,
-                    struct ReadyList *service_context,
-                    struct GNUNET_TIME_Relative latency,
-                    const struct GNUNET_PeerIdentity *peer,
-                    const struct GNUNET_MessageHeader *message)
+static void
+plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
+                    const struct GNUNET_MessageHeader *message,
+                    unsigned int distance, const char *sender_address,
+                    size_t sender_address_len)
 {
   const struct GNUNET_MessageHeader ack = {
     htons (sizeof (struct GNUNET_MessageHeader)),
     htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ACK)
   };
+  struct ReadyList *service_context;
   struct TransportPlugin *plugin = cls;
   struct TransportClient *cpos;
   struct InboundMessage *im;
   uint16_t msize;
-  struct NeighbourList *n;
+  struct NeighborList *n;
 
-  if (service_context != NULL)
-    {
-      n = service_context->neighbour;
-      GNUNET_assert (n != NULL);
-    }
-  else
+  n = find_neighbor (peer, sender_address, sender_address_len);
+  if (n == NULL)
     {
-      n = find_neighbour (peer);
-      if (n == NULL)
-        {
-          if (message == NULL)
-            return NULL;        /* disconnect of peer already marked down */
-          n = setup_new_neighbour (peer);
-        }
-      service_context = n->plugins;
-      while ((service_context != NULL) && (plugin != service_context->plugin))
-        service_context = service_context->next;
-      GNUNET_assert ((plugin->api->send == NULL) ||
-                     (service_context != NULL));
+      if (message == NULL)
+        return;                 /* disconnect of peer already marked down */
+      n = setup_new_neighbor (peer, sender_address, sender_address_len);
     }
+  service_context = n->plugins;
+  while ((service_context != NULL) && (plugin != service_context->plugin))
+    service_context = service_context->next;
+  GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
   if (message == NULL)
     {
-      if ((service_context != NULL) &&
-          (service_context->plugin_handle == plugin_context))
-        {
-          service_context->connected = GNUNET_NO;
-          service_context->plugin_handle = 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 */
-      return NULL;
+      if (service_context != NULL)
+        service_context->connected = GNUNET_NO;
+      disconnect_neighbor (n, GNUNET_YES);
+      return;
     }
 #if DEBUG_TRANSPORT
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
@@ -2036,22 +2254,22 @@ plugin_env_receive (void *cls,
           service_context->connect_attempts++;
         }
       service_context->timeout
-        = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
-      service_context->plugin_handle = plugin_context;
-      service_context->latency = latency;
+        =
+        GNUNET_TIME_relative_to_absolute
+        (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
+      /* service_context->latency = latency; */ /* This value should be set by us! */
     }
   /* update traffic received amount ... */
   msize = ntohs (message->size);
   n->last_received += msize;
   GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
   n->peer_timeout =
-    GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_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,
+    GNUNET_SCHEDULER_add_delayed (sched,
                                   GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
-                                  &neighbour_timeout_task, n);
+                                  &neighbor_timeout_task, n);
   update_quota (n);
   if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
     {
@@ -2061,8 +2279,9 @@ plugin_env_receive (void *cls,
                   _
                   ("Dropping incoming message due to repeated bandwidth quota violations.\n"));
       /* TODO: call stats */
-      GNUNET_assert (NULL != service_context->neighbour);
-      return service_context;
+      GNUNET_assert ((service_context == NULL) ||
+                     (NULL != service_context->neighbor));
+      return;
     }
   switch (ntohs (message->type))
     {
@@ -2070,16 +2289,21 @@ plugin_env_receive (void *cls,
 #if DEBUG_TRANSPORT
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                   "Receiving `%s' message from `%4s'.\n", "HELLO",
-                 GNUNET_i2s(peer));
+                  GNUNET_i2s (peer));
 #endif
       process_hello (plugin, message);
 #if DEBUG_TRANSPORT
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                   "Sending `%s' message to connecting peer `%4s'.\n", "ACK",
-                 GNUNET_i2s(peer));
+                  GNUNET_i2s (peer));
 #endif
       transmit_to_peer (NULL, 0, &ack, GNUNET_YES, n);
       break;
+    case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
+      handle_ping(plugin, message, peer, sender_address, sender_address_len);
+    case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
+      handle_pong(plugin, message, peer, sender_address, sender_address_len);
+      //plugin_env_notify_validation();
     case GNUNET_MESSAGE_TYPE_TRANSPORT_ACK:
       n->saw_ack = GNUNET_YES;
       /* intentional fall-through! */
@@ -2087,14 +2311,13 @@ plugin_env_receive (void *cls,
 #if DEBUG_TRANSPORT
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                   "Received message of type %u from `%4s', sending to all clients.\n",
-                  ntohs (message->type),
-                 GNUNET_i2s(peer));
+                  ntohs (message->type), GNUNET_i2s (peer));
 #endif
       /* transmit message to all clients */
       im = GNUNET_malloc (sizeof (struct InboundMessage) + msize);
       im->header.size = htons (sizeof (struct InboundMessage) + msize);
       im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
-      im->latency = GNUNET_TIME_relative_hton (latency);
+      im->latency = n->latency;
       im->peer = *peer;
       memcpy (&im[1], message, msize);
 
@@ -2106,8 +2329,8 @@ plugin_env_receive (void *cls,
         }
       GNUNET_free (im);
     }
-  GNUNET_assert (NULL != service_context->neighbour);
-  return service_context;
+  GNUNET_assert ((service_context == NULL) ||
+                 (NULL != service_context->neighbor));
 }
 
 
@@ -2126,7 +2349,7 @@ handle_start (void *cls,
 {
   struct TransportClient *c;
   struct ConnectInfoMessage cim;
-  struct NeighbourList *n;
+  struct NeighborList *n;
   struct InboundMessage *im;
   struct GNUNET_MessageHeader *ack;
 
@@ -2154,7 +2377,7 @@ 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,
@@ -2162,7 +2385,8 @@ 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 (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT / (60 * 1000));
+      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));
@@ -2173,7 +2397,7 @@ handle_start (void *cls,
       ack = (struct GNUNET_MessageHeader *) &im[1];
       ack->size = htons (sizeof (struct GNUNET_MessageHeader));
       ack->type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ACK);
-      for (n = neighbours; n != NULL; n = n->next)
+      for (n = neighbors; n != NULL; n = n->next)
         {
           cim.id = n->id;
           transmit_to_client (c, &cim.header, GNUNET_NO);
@@ -2225,7 +2449,7 @@ handle_send (void *cls,
              const struct GNUNET_MessageHeader *message)
 {
   struct TransportClient *tc;
-  struct NeighbourList *n;
+  struct NeighborList *n;
   const struct OutboundMessage *obm;
   const struct GNUNET_MessageHeader *obmm;
   uint16_t size;
@@ -2253,9 +2477,9 @@ handle_send (void *cls,
       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
       return;
     }
-  n = find_neighbour (&obm->peer);
+  n = find_neighbor (&obm->peer, NULL, 0);
   if (n == NULL)
-    n = setup_new_neighbour (&obm->peer);
+    n = setup_new_neighbor (&obm->peer, NULL, 0);
   tc = clients;
   while ((tc != NULL) && (tc->client != client))
     tc = tc->next;
@@ -2266,7 +2490,7 @@ handle_send (void *cls,
               ntohs (obmm->size),
               ntohs (obmm->type), GNUNET_i2s (&obm->peer));
 #endif
-  transmit_to_peer (tc, ntohl(obm->priority), obmm, GNUNET_NO, n);
+  transmit_to_peer (tc, ntohl (obm->priority), obmm, GNUNET_NO, n);
   GNUNET_SERVER_receive_done (client, GNUNET_OK);
 }
 
@@ -2285,7 +2509,7 @@ handle_set_quota (void *cls,
 {
   const struct QuotaSetMessage *qsm =
     (const struct QuotaSetMessage *) message;
-  struct NeighbourList *n;
+  struct NeighborList *n;
   struct TransportPlugin *p;
   struct ReadyList *rl;
 
@@ -2294,7 +2518,7 @@ handle_set_quota (void *cls,
               "Received `%s' request from client for peer `%4s'\n",
               "SET_QUOTA", GNUNET_i2s (&qsm->peer));
 #endif
-  n = find_neighbour (&qsm->peer);
+  n = find_neighbor (&qsm->peer, NULL, 0);
   if (n == NULL)
     {
       GNUNET_SERVER_receive_done (client, GNUNET_OK);
@@ -2333,14 +2557,104 @@ 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_neighbor (&tcm->peer, NULL, 0))
+    setup_new_neighbor (&tcm->peer, NULL, 0); /* Can we set up a truly _new_ neighbor without
+                                        knowing its address?  Should we ask the plugin
+                                        for more information about this peer?  I don't
+                                        think we can...  Or set up new peer should only
+                                        happen when transport notifies us of an address,
+                                        and this setup should check for an address in
+                                        the existing list only */
+#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
-  if (NULL == find_neighbour (&tcm->peer))
-    setup_new_neighbour (&tcm->peer);
   GNUNET_SERVER_receive_done (client, GNUNET_OK);
 }
 
+static void
+transmit_address_to_client (void *cls, const char *address)
+{
+  struct GNUNET_SERVER_TransmitContext *tc = cls;
+  size_t slen;
+
+  if (NULL == address)
+    slen = 0;
+  else
+    slen = strlen (address) + 1;
+  GNUNET_SERVER_transmit_context_append (tc, address, slen,
+                                         GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
+  if (NULL == address)
+    GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
+}
+
+/**
+ * Handle AddressLookup-message.
+ *
+ * @param cls closure (always NULL)
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_address_lookup (void *cls,
+                       struct GNUNET_SERVER_Client *client,
+                       const struct GNUNET_MessageHeader *message)
+{
+  const struct AddressLookupMessage *alum;
+  struct TransportPlugin *lsPlugin;
+  const char *nameTransport;
+  const char *address;
+  uint16_t size;
+  struct GNUNET_SERVER_TransmitContext *tc;
+
+  size = ntohs (message->size);
+  if (size < sizeof (struct AddressLookupMessage))
+    {
+      GNUNET_break_op (0);
+      GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+      return;
+    }
+  alum = (const struct AddressLookupMessage *) message;
+  uint32_t addressLen = ntohl (alum->addrlen);
+  if (size <= sizeof (struct AddressLookupMessage) + addressLen)
+    {
+      GNUNET_break_op (0);
+      GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+      return;
+    }
+  address = (const char *) &alum[1];
+  nameTransport = (const char *) &address[addressLen];
+  if (nameTransport
+      [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
+    {
+      GNUNET_break_op (0);
+      GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+      return;
+    }
+  struct GNUNET_TIME_Absolute timeout =
+    GNUNET_TIME_absolute_ntoh (alum->timeout);
+  struct GNUNET_TIME_Relative rtimeout =
+    GNUNET_TIME_absolute_get_remaining (timeout);
+  lsPlugin = find_transport (nameTransport);
+  if (NULL == lsPlugin)
+    {
+      tc = GNUNET_SERVER_transmit_context_create (client);
+      GNUNET_SERVER_transmit_context_append (tc, NULL, 0,
+                                             GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
+      GNUNET_SERVER_transmit_context_run (tc, rtimeout);
+      return;
+    }
+  tc = GNUNET_SERVER_transmit_context_create (client);
+  lsPlugin->api->address_pretty_printer (cls, nameTransport,
+                                         address, addressLen, GNUNET_YES,
+                                         rtimeout,
+                                         &transmit_address_to_client, tc);
+}
 
 /**
  * List of handlers for the messages understood by this
@@ -2358,6 +2672,9 @@ static struct GNUNET_SERVER_MessageHandler handlers[] = {
   {&handle_try_connect, NULL,
    GNUNET_MESSAGE_TYPE_TRANSPORT_TRY_CONNECT,
    sizeof (struct TryConnectMessage)},
+  {&handle_address_lookup, NULL,
+   GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
+   0},
   {NULL, NULL, 0, 0}
 };
 
@@ -2370,15 +2687,12 @@ 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.notify_validation = &plugin_env_notify_validation;
-  plug->env.default_quota_in = (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000);
+  plug->env.default_quota_in =
+    (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000);
   plug->env.max_connections = max_connect_per_transport;
 }
 
@@ -2429,6 +2743,8 @@ client_disconnect_notification (void *cls,
   struct TransportClient *prev;
   struct ClientMessageQueueEntry *mqe;
 
+  if (client == NULL) 
+    return;
 #if DEBUG_TRANSPORT
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
               "Client disconnected, cleaning up.\n");
@@ -2461,6 +2777,41 @@ 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.
  *
@@ -2472,7 +2823,8 @@ 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;
@@ -2534,52 +2886,19 @@ run (void *cls,
         }
       GNUNET_free (plugs);
     }
+  GNUNET_SCHEDULER_add_delayed (sched,
+                                GNUNET_TIME_UNIT_FOREVER_REL,
+                                &unload_plugins, NULL);
   if (no_transports)
     refresh_hello ();
 #if DEBUG_TRANSPORT
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-             _("Transport service ready.\n"));
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
 #endif
   /* 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");
-#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);
-}
-
-
 /**
  * The main function for the transport service.
  *
@@ -2594,7 +2913,8 @@ main (int argc, char *const *argv)
           GNUNET_SERVICE_run (argc,
                               argv,
                               "transport",
-                              &run, NULL, &unload_plugins, NULL)) ? 0 : 1;
+                              GNUNET_SERVICE_OPTION_NONE,
+                              &run, NULL)) ? 0 : 1;
 }
 
 /* end of gnunet-service-transport.c */