gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] r10295 - gnunet/src/transport


From: gnunet
Subject: [GNUnet-SVN] r10295 - gnunet/src/transport
Date: Mon, 15 Feb 2010 00:59:47 +0100

Author: grothoff
Date: 2010-02-15 00:59:47 +0100 (Mon, 15 Feb 2010)
New Revision: 10295

Modified:
   gnunet/src/transport/gnunet-service-transport.c
   gnunet/src/transport/plugin_transport.h
   gnunet/src/transport/plugin_transport_tcp.c
   gnunet/src/transport/plugin_transport_template.c
   gnunet/src/transport/plugin_transport_udp.c
   gnunet/src/transport/test_transport_api.c
   gnunet/src/transport/test_transport_api_tcp_peer1.conf
   gnunet/src/transport/test_transport_api_tcp_peer2.conf
Log:
towards better working transport code

Modified: gnunet/src/transport/gnunet-service-transport.c
===================================================================
--- gnunet/src/transport/gnunet-service-transport.c     2010-02-14 23:59:30 UTC 
(rev 10294)
+++ gnunet/src/transport/gnunet-service-transport.c     2010-02-14 23:59:47 UTC 
(rev 10295)
@@ -23,11 +23,15 @@
  * @brief low-level P2P messaging
  * @author Christian Grothoff
  *
- * TODO:
- * - remove AddressValidations, incorporate them into the PeerAddressLists
+ * NOTE:
+ * - This code uses 'GNUNET_a2s' for debug printing in many places,
+ *   which is technically wrong since it assumes we have IP+Port 
+ *   (v4/v6) addresses.  Once we add transports like http or smtp
+ *   this will have to be changed!
  */
 #include "platform.h"
 #include "gnunet_client_lib.h"
+#include "gnunet_container_lib.h"
 #include "gnunet_constants.h"
 #include "gnunet_getopt_lib.h"
 #include "gnunet_hello_lib.h"
@@ -59,6 +63,13 @@
 #define MAX_CONNECT_RETRY 3
 
 /**
+ * Limit on the number of ready-to-run tasks when validating 
+ * HELLOs.  If more tasks are ready to run, we will drop 
+ * HELLOs instead of validating them.
+ */
+#define MAX_HELLO_LOAD 4
+
+/**
  * How often must a peer violate bandwidth quotas before we start
  * to simply drop its messages?
  */
@@ -91,9 +102,9 @@
 #define PLUGIN_RETRY_FREQUENCY GNUNET_TIME_relative_multiply 
(GNUNET_TIME_UNIT_MINUTES, 15)
 
 /**
- * After how long do we expire an address in a HELLO
- * that we just validated?  This value is also used
- * for our own addresses when we create a HELLO.
+ * After how long do we expire an address in a HELLO that we just
+ * validated?  This value is also used for our own addresses when we
+ * create a HELLO.
  */
 #define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply 
(GNUNET_TIME_UNIT_HOURS, 12)
 
@@ -101,35 +112,19 @@
 /**
  * List of addresses of other peers
  */
-struct PeerAddressList
+struct ForeignAddressList
 {
   /**
    * This is a linked list.
    */
-  struct PeerAddressList *next;
+  struct ForeignAddressList *next;
 
-  /*
-   * Pointer to the validation associated with this
-   * address.  May be NULL if already validated!
-   */
-  struct ValidationAddress *validation;
-
   /**
-   * Which of our transport plugins does this entry
-   * belong to?
+   * Which ready list does this entry belong to.
    */
-  struct TransportPlugin *plugin;
+  struct ReadyList *ready_list;
 
   /**
-   * Neighbor this entry belongs to.
-   */
-  struct NeighborList *neighbor;
-
-  /*
-   * Ready list (transport) that this peer belongs to
-   */
-  struct ReadyList *ready_list;
-  /**
    * How long until we auto-expire this address (unless it is
    * re-confirmed by the transport)?
    */
@@ -141,9 +136,9 @@
   size_t addrlen;
 
   /**
-   * The address
+   * The address.
    */
-  char *addr;
+  const void *addr;
 
   /**
    * What was the last latency observed for this plugin
@@ -158,19 +153,18 @@
    * transport simply stalls writing to the stream but does not
    * formerly get a signal that the other peer died.
    */
+  /* FIXME: Do we need this? */
   struct GNUNET_TIME_Absolute timeout;
 
   /**
-   * Is this plugin currently connected?  The first time
-   * we transmit or send data to a peer via a particular
-   * plugin, we set this to GNUNET_YES.  If we later get
-   * an error (disconnect notification or transmission
-   * failure), we set it back to GNUNET_NO.  Each time the
-   * value is set to GNUNET_YES, we increment the
-   * "connect_attempts" counter.  If that one reaches a
-   * particular threshold, we consider the plugin to not
-   * be working properly at this time for the given peer
-   * and remove it from the eligible list.
+   * Is this plugin currently connected?  The first time we transmit
+   * or send data to a peer via a particular plugin, we set this to
+   * GNUNET_YES.  If we later get an error (disconnect notification or
+   * transmission failure), we set it back to GNUNET_NO.  Each time
+   * the value is set to GNUNET_YES, we increment the
+   * "connect_attempts" counter.  If that one reaches a particular
+   * threshold, we consider the address to not be working properly at
+   * this time and remove it from the eligible list.
    */
   int connected;
 
@@ -183,6 +177,11 @@
   int transmit_ready;
 
   /**
+   * Has this address been validated yet?
+   */
+  int validated;
+
+  /**
    * How often have we tried to connect using this plugin?
    */
   unsigned int connect_attempts;
@@ -191,21 +190,21 @@
 
 
 /**
- * Entry in linked list of network addresses.
+ * Entry in linked list of network addresses for ourselves.
  */
-struct AddressList
+struct OwnAddressList
 {
   /**
    * This is a linked list.
    */
-  struct AddressList *next;
+  struct OwnAddressList *next;
 
   /**
    * The address, actually a pointer to the end
    * of this struct.  Do not free!
    */
-  void *addr;
-
+  const void *addr;
+  
   /**
    * How long until we auto-expire this address (unless it is
    * re-confirmed by the transport)?
@@ -250,7 +249,7 @@
   /**
    * List of our known addresses for this transport.
    */
-  struct AddressList *addresses;
+  struct OwnAddressList *addresses;
 
   /**
    * Environment this transport service is using
@@ -263,7 +262,6 @@
    */
   GNUNET_SCHEDULER_TaskIdentifier address_update_task;
 
-
   /**
    * Set to GNUNET_YES if we need to scrap the existing
    * list of "addresses" and start fresh when we receive
@@ -291,9 +289,9 @@
 
   /**
    * The message(s) we want to transmit, GNUNET_MessageHeader(s)
-   * stuck together in memory.
+   * stuck together in memory.  Allocated at the end of this struct.
    */
-  char *message_buf;
+  const char *message_buf;
 
   /**
    * Size of the message buf
@@ -310,17 +308,12 @@
   /**
    * Using which specific address should we send this message?
    */
-  struct PeerAddressList *specific_peer;
+  struct ForeignAddressList *specific_address;
 
   /**
-   * Neighbor this entry belongs to.
-   */
-  /*struct NeighborList *neighbor;*/
-
-  /**
    * Peer ID of the Neighbor this entry belongs to.
    */
-  struct GNUNET_PeerIdentity *neighbor_id;
+  struct GNUNET_PeerIdentity neighbor_id;
 
   /**
    * Plugin that we used for the transmission.
@@ -363,15 +356,10 @@
   struct TransportPlugin *plugin;
 
   /**
-   * Neighbor this entry belongs to.
-   */
-  struct NeighborList *neighbor;
-
-  /**
    * Transport addresses, latency, and readiness for
    * this particular plugin.
    */
-  struct PeerAddressList *addresses;
+  struct ForeignAddressList *addresses;
 
   /**
    * Is this plugin ready to transmit to the specific target?
@@ -379,12 +367,15 @@
    * transmission is in progress, "transmit_ready" is set to
    * GNUNET_NO.
    */
+  // FIXME: is this dead?
   int plugin_transmit_ready;
 
   /**
-   * Are any of our PeerAddressList addresses still connected?
+   * Is the plugin represented by this entry currently connected to
+   * the respective peer?
    */
-  int connected; /* FIXME: dynamically check PeerAddressList addresses when 
asked to! */
+  int connected;
+
 };
 
 
@@ -435,12 +426,6 @@
   struct GNUNET_TIME_Absolute last_quota_update;
 
   /**
-   * At what time should we try to again add plugins to
-   * our ready list?
-   */
-  struct GNUNET_TIME_Absolute retry_plugins_time;
-
-  /**
    * 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
@@ -616,20 +601,16 @@
 
 
 /**
- * For each HELLO, we may have to validate multiple addresses;
- * each address gets its own request entry.
+ * Entry in map of all HELLOs awaiting validation.
  */
-struct ValidationAddress
+struct ValidationEntry
 {
-  /**
-   * This is a linked list.
-   */
-  struct ValidationAddress *next;
 
   /**
-   * What peer_address does this validation belong to?
+   * The address, actually a pointer to the end
+   * of this struct.  Do not free!
    */
-  struct PeerAddressList *peer_address;
+  const void *addr;
 
   /**
    * Name of the transport.
@@ -637,101 +618,78 @@
   char *transport_name;
 
   /**
-   * When should this validated address expire?
+   * The public key of the peer.
    */
-  struct GNUNET_TIME_Absolute expiration;
+  struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
 
   /**
+   * ID of task that will clean up this entry if we don't succeed
+   * with the validation first.
+   */
+  GNUNET_SCHEDULER_TaskIdentifier timeout_task;
+
+  /**
    * At what time did we send this validation?
    */
   struct GNUNET_TIME_Absolute send_time;
 
   /**
+   * Length of addr.
+   */
+  size_t addrlen;
+
+  /**
    * 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
-   * if we are waiting on a response.
-   */
-  int ok;
 };
 
 
 /**
- * Entry in linked list of all HELLOs awaiting validation.
+ * Context of currently active requests to peerinfo
+ * for validation of HELLOs.
  */
-struct ValidationList
+struct CheckHelloValidatedContext
 {
 
   /**
-   * This is a linked list.
+   * This is a doubly-linked list.
    */
-  struct ValidationList *next;
+  struct CheckHelloValidatedContext *next;
 
   /**
-   * Linked list with one entry per address from the HELLO
-   * that needs to be validated.
+   * This is a doubly-linked list.
    */
-  struct ValidationAddress *addresses;
+  struct CheckHelloValidatedContext *prev;
 
   /**
-   * The public key of the peer.
-   */
-  struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
-
-  /**
-   * When does this record time-out? (assuming the
-   * challenge goes unanswered)
-   */
-  struct GNUNET_TIME_Absolute timeout;
-
-};
-
-
-struct CheckHelloValidatedContext
-{
-  /**
-   * Plugin for which we are validating.
-   */
-  struct TransportPlugin *plugin;
-
-  /**
    * Hello that we are validating.
    */
-  struct GNUNET_HELLO_Message *hello;
+  const struct GNUNET_HELLO_Message *hello;
 
   /**
-   * Validation list being built.
-   */
-  struct ValidationList *e;
-
-  /**
    * Context for peerinfo iteration.
    * NULL after we are done processing peerinfo's information.
    */
   struct GNUNET_PEERINFO_IteratorContext *piter;
+  
+  /**
+   * Was a HELLO known for this peer to peerinfo?
+   */
+  int hello_known;
 
 };
 
 
-
 /**
- * HELLOs awaiting validation.
- */
-static struct ValidationList *pending_validations;
-
-/**
  * Our HELLO message.
  */
 static struct GNUNET_HELLO_Message *our_hello;
 
 /**
- * "version" of "our_hello".  Used to see if a given
- * neighbor has already been sent the latest version
- * of our HELLO message.
+ * "version" of "our_hello".  Used to see if a given neighbor has
+ * already been sent the latest version of our HELLO message.
  */
 static unsigned int our_hello_version;
 
@@ -786,6 +744,25 @@
 static uint32_t max_connect_per_transport;
 
 /**
+ * Head of linked list.
+ */
+static struct CheckHelloValidatedContext *chvc_head;
+
+/**
+ * Tail of linked list.
+ */
+static struct CheckHelloValidatedContext *chvc_tail;
+
+
+/**
+ * Map of PeerIdentities to 'struct ValidationEntry*'s (addresses
+ * of the given peer that we are currently validating).
+ */
+static struct GNUNET_CONTAINER_MultiHashMap *validation_map;
+
+
+
+/**
  * 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
@@ -800,15 +777,13 @@
  */
 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!
+ * 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 neighbor target peer for which to check the plugins
+ * @param neighbor target peer for which to transmit
  */
-static ssize_t try_transmission_to_peer (struct NeighborList *neighbor);
+static void try_transmission_to_peer (struct NeighborList *neighbor);
 
 
 /**
@@ -827,7 +802,6 @@
   while ((head != NULL) &&
         (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
     head = head->next;
-
   return head;
 }
 
@@ -891,10 +865,9 @@
 
 
 /**
- * Function called to notify a client about the socket
- * being ready to queue more data.  "buf" will be
- * NULL and "size" zero if the socket was closed for
- * writing in the meantime.
+ * Function called to notify a client about the socket being ready to
+ * queue more data.  "buf" will be NULL and "size" zero if the socket
+ * was closed for writing in the meantime.
  *
  * @param cls closure
  * @param size number of bytes available in buf
@@ -1017,36 +990,6 @@
 
 
 /**
- * Find alternative plugins for communication.
- *
- * @param neighbor for which neighbor should we try to find
- *        more plugins?
- */
-static void
-try_alternative_plugins (struct NeighborList *neighbor)
-{
-  struct ReadyList *rl;
-
-  if ((neighbor->plugins != NULL) &&
-      (neighbor->retry_plugins_time.value >
-       GNUNET_TIME_absolute_get ().value))
-    return;                     /* don't try right now */
-  neighbor->retry_plugins_time
-    = GNUNET_TIME_relative_to_absolute (PLUGIN_RETRY_FREQUENCY);
-
-  rl = neighbor->plugins;
-#if WTF /* FIXME: What is this supposed to do? */
-  while (rl != NULL)
-    {
-      if (rl->connect_attempts > 0)
-        rl->connect_attempts--; /* amnesty */
-      rl = rl->next;
-    }
-#endif
-}
-
-
-/**
  * Function called by the GNUNET_TRANSPORT_TransmitFunction
  * upon "completion" of a send request.  This tells the API
  * that it is now legal to send another message to the given
@@ -1071,7 +1014,7 @@
   struct NeighborList *n;
 
   GNUNET_assert (mq != NULL);
-  n = find_neighbor(mq->neighbor_id);
+  n = find_neighbor(&mq->neighbor_id);
   if (n == NULL) /* Neighbor must have been removed asynchronously! */
     return;
 
@@ -1082,7 +1025,7 @@
 
   if (result == GNUNET_OK)
     {
-      mq->specific_peer->timeout =
+      mq->specific_address->timeout =
         GNUNET_TIME_relative_to_absolute
         (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
     }
@@ -1091,7 +1034,7 @@
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                   "Transmission to peer `%s' failed, marking connection as 
down.\n",
                   GNUNET_i2s (target));
-      mq->specific_peer->connected = GNUNET_NO;
+      mq->specific_address->connected = GNUNET_NO;
     }
   if (!mq->internal_msg)
     {
@@ -1099,7 +1042,7 @@
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                   "Setting transmit_ready on transport!\n");
 #endif
-      mq->specific_peer->transmit_ready = GNUNET_YES;
+      mq->specific_address->transmit_ready = GNUNET_YES;
     }
 
   if (mq->client != NULL)
@@ -1113,8 +1056,6 @@
       send_ok_msg.peer = n->id;
       transmit_to_client (mq->client, &send_ok_msg.header, GNUNET_NO);
     }
-  GNUNET_free (mq->message_buf);
-  GNUNET_free (mq->neighbor_id);
   GNUNET_free (mq);
   /* one plugin just became ready again, try transmitting
      another message (if available) */
@@ -1125,29 +1066,36 @@
 }
 
 
-
-
-struct PeerAddressList *
+/**
+ * Find an address in any of the available transports for
+ * the given neighbor that would be good for message
+ * transmission.  This is essentially the transport selection
+ * routine.
+ *
+ * @param neighbor for whom to select an address
+ * @return selected address, NULL if we have none
+ */
+struct ForeignAddressList *
 find_ready_address(struct NeighborList *neighbor)
 {
   struct ReadyList *head = neighbor->plugins;
-  struct PeerAddressList *addresses;
+  struct ForeignAddressList *addresses;
   struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
-  struct PeerAddressList *best_address;
+  struct ForeignAddressList *best_address;
 
   best_address = NULL;
   while (head != NULL)
     {
       addresses = head->addresses;
-
       while (addresses != NULL)
         {
-          if ((addresses->timeout.value < now.value) && (addresses->connected 
== GNUNET_YES))
+          if ( (addresses->timeout.value < now.value) && 
+              (addresses->connected == GNUNET_YES) )
             {
 #if DEBUG_TRANSPORT
               GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                           "Marking long-time inactive connection to `%4s' as 
down.\n",
-                          GNUNET_i2s (&addresses->ready_list->neighbor->id));
+                          GNUNET_i2s (&neighbor->id));
 #endif
               addresses->connected = GNUNET_NO;
             }
@@ -1157,17 +1105,15 @@
       addresses = head->addresses;
       while (addresses != NULL)
         {
-          if ((addresses->connected == GNUNET_YES) &&
-              (addresses->transmit_ready == GNUNET_YES) &&
-              ((best_address == NULL) || (addresses->latency.value < 
best_address->latency.value)))
-            {
-#if DEBUG_TRANSPORT
-              GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                          "Found address with latency %llu (previous best was 
%llu), setting as best found yet!\n",
-                          addresses->latency.value, best_address == NULL ? 
-1LL : best_address->latency.value);
-#endif
-              best_address = addresses;
-            }
+          if ( ( (best_address == NULL) || 
+                (addresses->connected == GNUNET_YES) ||
+                (best_address->connected == GNUNET_NO) ) &&
+              (addresses->transmit_ready == GNUNET_YES) &&
+              ( (best_address == NULL) || 
+                (addresses->latency.value < best_address->latency.value)) )
+           best_address = addresses;            
+         /* FIXME: also give lower-latency addresses that are not
+            connected a chance some times... */
           addresses = addresses->next;
         }
       head = head->next;
@@ -1176,7 +1122,7 @@
   if (best_address != NULL)
     {
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "Best address found has latency of %llu!\n",
+                  "Best address found has latency of %llu ms.\n",
                   best_address->latency.value);
     }
 #endif
@@ -1184,62 +1130,61 @@
 
 }
 
+
 /**
- * Check the ready list for the given neighbor and
- * if a plugin is ready for transmission (and if we
- * have a message), do so!
+ * 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 neighbor target peer for which to transmit
  */
-static ssize_t
+static void
 try_transmission_to_peer (struct NeighborList *neighbor)
 {
   struct GNUNET_TIME_Relative min_latency;
   struct ReadyList *rl;
   struct MessageQueue *mq;
-  struct GNUNET_TIME_Absolute now;
 
   if (neighbor->messages == NULL)
-    return 0;                     /* nothing to do */
-  try_alternative_plugins (neighbor);
+    return;                     /* nothing to do */
   min_latency = GNUNET_TIME_UNIT_FOREVER_REL;
   rl = NULL;
   mq = neighbor->messages;
-  now = GNUNET_TIME_absolute_get ();
-
-  if (mq->specific_peer == NULL)
-    mq->specific_peer = find_ready_address(neighbor); /* Find first available 
(or best!) address to transmit to */
-
-  if (mq->specific_peer == NULL)
+  if (mq->specific_address == NULL)
+    mq->specific_address = find_ready_address(neighbor); 
+  if (mq->specific_address == NULL)
     {
 #if DEBUG_TRANSPORT
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "No plugin ready to transmit message\n");
+                  "No destination address available to transmit message of 
size %u to peer `%4s'\n",
+                 mq->message_buf_size,
+                 GNUNET_i2s (&mq->neighbor_id));
 #endif
-      return 0;                   /* nobody ready */
+      return;                   /* nobody ready */
     }
-
-  rl = mq->specific_peer->ready_list;
+  rl = mq->specific_address->ready_list;
   neighbor->messages = mq->next;
   mq->plugin = rl->plugin;
   if (!mq->internal_msg)
-    mq->specific_peer->transmit_ready = GNUNET_NO;
+    mq->specific_address->transmit_ready = GNUNET_NO;
 #if DEBUG_TRANSPORT
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Giving message of size %u for `%4s' to plugin `%s'\n",
+              "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
               mq->message_buf_size,
-              GNUNET_i2s (&neighbor->id), rl->plugin->short_name);
+              GNUNET_i2s (&neighbor->id), 
+             GNUNET_a2s (mq->specific_address->addr,
+                         mq->specific_address->addrlen),
+             rl->plugin->short_name);
 #endif
-
-  return rl->plugin->api->send (rl->plugin->api->cls,
-                         mq->neighbor_id,
-                         mq->message_buf,
-                         mq->message_buf_size,
-                         mq->priority,
-                         GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
-                         mq->specific_peer->addr,
-                         mq->specific_peer->addrlen,
-                         GNUNET_YES,
-                         &transmit_send_continuation, mq);
-
+  rl->plugin->api->send (rl->plugin->api->cls,
+                        &mq->neighbor_id,
+                        mq->message_buf,
+                        mq->message_buf_size,
+                        mq->priority,
+                        GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
+                        mq->specific_address->addr,
+                        mq->specific_address->addrlen,
+                        GNUNET_YES /* FIXME: sometimes, we want to be more 
tolerant here! */,
+                        &transmit_send_continuation, mq);
 }
 
 
@@ -1247,16 +1192,16 @@
  * Send the specified message to the specified peer.
  *
  * @param client source of the transmission request (can be NULL)
- * @param peer_address PeerAddressList where we should send this message
+ * @param peer_address ForeignAddressList where we should send this message
  * @param priority how important is the message
  * @param message_buf message(s) to send GNUNET_MessageHeader(s)
  * @param message_buf_size total size of all messages in message_buf
  * @param is_internal is this an internal message
  * @param neighbor handle to the neighbor for transmission
  */
-static ssize_t
+static void
 transmit_to_peer (struct TransportClient *client,
-                  struct PeerAddressList *peer_address,
+                  struct ForeignAddressList *peer_address,
                   unsigned int priority,
                   const char *message_buf,
                   size_t message_buf_size,
@@ -1264,7 +1209,6 @@
 {
   struct MessageQueue *mq;
   struct MessageQueue *mqe;
-  char *m;
 
   if (client != NULL)
     {
@@ -1277,40 +1221,46 @@
               /* client transmitted to same peer twice
                  before getting SendOk! */
               GNUNET_break (0);
-              return 0;
+              return;
             }
           mq = mq->next;
         }
     }
-  mq = GNUNET_malloc (sizeof (struct MessageQueue));
-  mq->specific_peer = peer_address;
+  mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
+  mq->specific_address = peer_address;
   mq->client = client;
-  m = GNUNET_malloc (message_buf_size);
-  memcpy (m, message_buf, message_buf_size);
-  mq->message_buf = m;
+  memcpy (&mq[1], message_buf, message_buf_size);
+  mq->message_buf = (const char*) &mq[1];
   mq->message_buf_size = message_buf_size;
-  mq->neighbor_id = GNUNET_malloc(sizeof (struct GNUNET_PeerIdentity));
-
-  memcpy(mq->neighbor_id, &neighbor->id, sizeof(struct GNUNET_PeerIdentity));
+  memcpy(&mq->neighbor_id, &neighbor->id, sizeof(struct GNUNET_PeerIdentity));
   mq->internal_msg = is_internal;
   mq->priority = priority;
 
-  /* find tail */
-  mqe = neighbor->messages;
-  if (mqe != NULL)
-    while (mqe->next != NULL)
-      mqe = mqe->next;
-  if (mqe == NULL)
+  if (is_internal)
     {
-      /* new head */
+      /* append at head */
+      mq->next = neighbor->messages;
       neighbor->messages = mq;
     }
   else
     {
-      /* append */
-      mqe->next = mq;
+      /* find tail */
+      mqe = neighbor->messages;
+      if (mqe != NULL)
+       while (mqe->next != NULL)
+         mqe = mqe->next;
+      if (mqe == NULL)
+       {
+         /* new head */
+         neighbor->messages = mq;
+       }
+      else
+       {
+         /* append */
+         mqe->next = mq;
+       }
     }
-  return try_transmission_to_peer (neighbor);
+  try_transmission_to_peer (neighbor);
 }
 
 
@@ -1320,7 +1270,7 @@
 struct GeneratorContext
 {
   struct TransportPlugin *plug_pos;
-  struct AddressList *addr_pos;
+  struct OwnAddressList *addr_pos;
   struct GNUNET_TIME_Absolute expiration;
 };
 
@@ -1393,10 +1343,11 @@
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
                   "Transmitting updated `%s' to neighbor `%4s'\n",
                   "HELLO", GNUNET_i2s (&npos->id));
-#endif // FIXME: just testing
-      //transmit_to_peer (NULL, NULL, 0,
-      //                  (const char *) our_hello, 
GNUNET_HELLO_size(our_hello),
-      //                  GNUNET_YES, npos);
+#endif
+      transmit_to_peer (NULL, NULL, 0,
+                        (const char *) our_hello, 
+                       GNUNET_HELLO_size(our_hello),
+                        GNUNET_NO, npos);
       npos = npos->next;
     }
 }
@@ -1428,9 +1379,9 @@
   struct GNUNET_TIME_Relative min_remaining;
   struct GNUNET_TIME_Relative remaining;
   struct GNUNET_TIME_Absolute now;
-  struct AddressList *pos;
-  struct AddressList *prev;
-  struct AddressList *next;
+  struct OwnAddressList *pos;
+  struct OwnAddressList *prev;
+  struct OwnAddressList *next;
   int expired;
 
   if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
@@ -1509,7 +1460,7 @@
                            struct GNUNET_TIME_Relative expires)
 {
   struct TransportPlugin *p = cls;
-  struct AddressList *al;
+  struct OwnAddressList *al;
   struct GNUNET_TIME_Absolute abex;
 
   abex = GNUNET_TIME_relative_to_absolute (expires);
@@ -1527,7 +1478,7 @@
       al = al->next;
     }
 
-  al = GNUNET_malloc (sizeof (struct AddressList) + addrlen);
+  al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
   al->addr = &al[1];
   al->next = p->addresses;
   p->addresses = al;
@@ -1585,109 +1536,209 @@
 
 
 /**
- * Copy any validated addresses to buf.
+ * Find a ForeignAddressList entry for the given neighbour
+ * that matches the given address and transport.
  *
- * @return 0 once all addresses have been
- *         returned
+ * @param neighbor which peer we care about
+ * @param tname name of the transport plugin
+ * @param addr binary address
+ * @param addrlen length of addr
+ * @return NULL if no such entry exists
  */
+static struct ForeignAddressList *
+find_peer_address(struct NeighborList *neighbor,
+                 const char *tname,
+                 const char *addr,
+                 size_t addrlen)
+{
+  struct ReadyList *head;
+  struct ForeignAddressList *address_head;
+
+  head = neighbor->plugins;
+  while (head != NULL)
+    {
+      if (0 == strcmp (tname, head->plugin->short_name))
+       break;
+      head = head->next;
+    }
+  if (head == NULL)
+    return NULL;
+
+  address_head = head->addresses;
+  while ( (address_head != NULL) &&
+         ( (address_head->addrlen != addrlen) ||
+           (memcmp(address_head->addr, addr, addrlen) != 0) ) )
+    address_head = address_head->next;
+  return address_head;
+}
+
+
+/**
+ * Get the peer address struct for the given neighbor and
+ * address.  If it doesn't yet exist, create it.
+ *
+ * @param neighbor which peer we care about
+ * @param tname name of the transport plugin
+ * @param addr binary address
+ * @param addrlen length of addr
+ * @return NULL if we do not have a transport plugin for 'tname'
+ */
+static struct ForeignAddressList *
+add_peer_address(struct NeighborList *neighbor,
+                const char *tname,
+                const char *addr, 
+                size_t addrlen)
+{
+  struct ReadyList *head;
+  struct ForeignAddressList *ret;
+
+  ret = find_peer_address (neighbor, tname, addr, addrlen);
+  if (ret != NULL)
+    return ret;
+  head = neighbor->plugins;
+  while (head != NULL)
+    {
+      if (0 == strcmp (tname, head->plugin->short_name))
+       break;
+      head = head->next;
+    }
+  if (head == NULL)
+    return NULL;
+  ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
+  ret->addr = (const char*) &ret[1];
+  memcpy (&ret[1], addr, addrlen);
+  ret->addrlen = addrlen;
+  ret->expires = GNUNET_TIME_relative_to_absolute
+    (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
+  ret->latency = GNUNET_TIME_relative_get_forever();
+  ret->transmit_ready = GNUNET_YES;
+  ret->timeout = GNUNET_TIME_relative_to_absolute
+    (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); 
+  ret->ready_list = head;
+  ret->next = head->addresses;
+  head->addresses = ret;
+  return ret;
+}
+
+
+/**
+ * Closure for 'add_validated_address'.
+ */
+struct AddValidatedAddressContext
+{
+  /**
+   * Entry that has been validated.
+   */
+  const struct ValidationEntry *ve;
+
+  /**
+   * Flag set after we have added the address so
+   * that we terminate the iteration next time.
+   */
+  int done;
+};
+
+
+/**
+ * Callback function used to fill a buffer of max bytes with a list of
+ * addresses in the format used by HELLOs.  Should use
+ * "GNUNET_HELLO_add_address" as a helper function.
+ *
+ * @param cls the 'struct AddValidatedAddressContext' with the validated 
address
+ * @param max maximum number of bytes that can be written to buf
+ * @param buf where to write the address information
+ * @return number of bytes written, 0 to signal the
+ *         end of the iteration.
+ */
 static size_t
-list_validated_addresses (void *cls, size_t max, void *buf)
+add_validated_address (void *cls,
+                      size_t max, void *buf)
 {
-  struct ValidationAddress **va = cls;
-  size_t ret;
+  struct AddValidatedAddressContext *avac = cls;
+  const struct ValidationEntry *ve = avac->ve;
 
-  while ((NULL != *va) && ((*va)->ok != GNUNET_YES))
-    *va = (*va)->next;
-  if (NULL == *va)
+  if (GNUNET_YES == avac->done)
     return 0;
-  ret = GNUNET_HELLO_add_address ((*va)->transport_name,
-                                  (*va)->expiration,
-                                  (*va)->peer_address->addr, 
(*va)->peer_address->addrlen, buf, max);
-  *va = (*va)->next;
-  return ret;
+  avac->done = GNUNET_YES;
+  return GNUNET_HELLO_add_address (ve->transport_name,
+                                  GNUNET_TIME_relative_to_absolute 
(HELLO_ADDRESS_EXPIRATION),
+                                  ve->addr,
+                                  ve->addrlen,
+                                  buf,
+                                  max);
 }
 
 
 /**
- * HELLO validation cleanup task.
+ * Iterator over hash map entries.  Checks if the given
+ * validation entry is for the same challenge as what
+ * is given in the PONG.
+ *
+ * @param cls the 'struct TransportPongMessage*'
+ * @param key peer identity 
+ * @param value value in the hash map ('struct ValidationEntry')
+ * @return GNUNET_YES if we should continue to
+ *         iterate (mismatch), GNUNET_NO if not (entry matched)
  */
-static void
-cleanup_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+static int
+check_pending_validation (void *cls,
+                         const GNUNET_HashCode * key,
+                         void *value)
 {
-  struct ValidationAddress *va;
-  struct ValidationList *pos;
-  struct ValidationList *prev;
-  struct GNUNET_TIME_Absolute now;
-  struct GNUNET_TIME_Absolute first;
+  const struct TransportPongMessage *pong = cls;
+  struct ValidationEntry *ve = value;
+  struct AddValidatedAddressContext avac;
+  unsigned int challenge = ntohl(pong->challenge);
   struct GNUNET_HELLO_Message *hello;
-  struct GNUNET_PeerIdentity pid;
+  struct GNUNET_PeerIdentity target;
   struct NeighborList *n;
+  struct ForeignAddressList *fal;
 
-  now = GNUNET_TIME_absolute_get ();
-  prev = NULL;
-  pos = pending_validations;
-  while (pos != NULL)
-    {
-      if (pos->timeout.value < now.value)
-        {
-          if (prev == NULL)
-            pending_validations = pos->next;
-          else
-            prev->next = pos->next;
-          va = pos->addresses;
-          hello = GNUNET_HELLO_create (&pos->publicKey,
-                                       &list_validated_addresses, &va);
-          GNUNET_CRYPTO_hash (&pos->publicKey,
-                              sizeof (struct
-                                      GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
-                              &pid.hashPubKey);
+  if (ve->challenge != challenge)
+    return GNUNET_YES;
+  
 #if DEBUG_TRANSPORT
-          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                      "Creating persistent `%s' message for peer `%4s' based 
on confirmed addresses.\n",
-                      "HELLO", GNUNET_i2s (&pid));
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Confirmed validity of address, peer `%4s' has address `%s' 
(%s).\n",
+             GNUNET_h2s (key),
+             GNUNET_a2s ((const struct sockaddr *) ve->addr,
+                         ve->addrlen),
+             ve->transport_name);
 #endif
-          GNUNET_PEERINFO_add_peer (cfg, sched, &pid, hello);
-          n = find_neighbor (&pid);
-          if (NULL != n)
-            {
-              try_transmission_to_peer (n);
-            }
-          GNUNET_free (hello);
-          while (NULL != (va = pos->addresses))
-            {
-              pos->addresses = va->next;
-              GNUNET_free (va->transport_name);
-              GNUNET_free (va);
-            }
-          GNUNET_free (pos);
-          if (prev == NULL)
-            pos = pending_validations;
-          else
-            pos = prev->next;
-          continue;
-        }
-      prev = pos;
-      pos = pos->next;
+  /* create the updated HELLO */
+  GNUNET_CRYPTO_hash (&ve->publicKey,
+                      sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
+                      &target.hashPubKey);
+  avac.done = GNUNET_NO;
+  avac.ve = ve;
+  hello = GNUNET_HELLO_create (&ve->publicKey,
+                              &add_validated_address,
+                              &avac);
+  GNUNET_PEERINFO_add_peer (cfg, sched,
+                           &target, 
+                           hello);
+  GNUNET_free (hello);
+  n = find_neighbor (&target);
+  if (n != NULL)
+    {
+      fal = add_peer_address (n, ve->transport_name, 
+                             ve->addr,
+                             ve->addrlen);
+      fal->expires = GNUNET_TIME_relative_to_absolute 
(HELLO_ADDRESS_EXPIRATION);
+      fal->validated = GNUNET_YES;
+      fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
     }
 
-  /* 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;
-        }
-      if (tc->reason != GNUNET_SCHEDULER_REASON_SHUTDOWN)
-        {
-          GNUNET_SCHEDULER_add_delayed (sched,
-                                        GNUNET_TIME_absolute_get_remaining
-                                        (first), &cleanup_validation, NULL);
-        }
-    }
+  /* clean up validation entry */
+  GNUNET_assert (GNUNET_YES ==
+                GNUNET_CONTAINER_multihashmap_remove (validation_map,
+                                                      key,
+                                                      ve));
+  GNUNET_SCHEDULER_cancel (sched,
+                          ve->timeout_task);
+  GNUNET_free (ve->transport_name);
+  GNUNET_free (ve);
+  return GNUNET_NO;
 }
 
 
@@ -1712,130 +1763,44 @@
              const char *sender_address,
              size_t sender_address_len)
 {
-  unsigned int not_done;
-  int matched;
-  struct ValidationList *pos;
-  struct ValidationAddress *va;
-  struct GNUNET_PeerIdentity id;
-  const struct TransportPongMessage *pong = (const struct TransportPongMessage 
*)message;
-  int count = 0;
-  unsigned int challenge = ntohl(pong->challenge);
-  pos = pending_validations;
-
-  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;
-      count++;
-    }
-  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' (out of %d). Ignoring.\n"),
-                  GNUNET_i2s (peer), count);
-      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->peer_address->addr,
-                                  va->peer_address->addrlen));
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Receiving `%s' message from `%4s'.\n", "PONG",
+             GNUNET_i2s (peer));
 #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"),
-                      GNUNET_a2s ((const struct sockaddr *) &pong[1],
-                                                           
ntohs(pong->addrlen)), va->transport_name);
-          va->ok = GNUNET_YES;
-          va->expiration =
-            GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
-          matched = GNUNET_YES;
-          va->peer_address->connected = GNUNET_YES;
-          va->peer_address->latency = 
GNUNET_TIME_absolute_get_difference(va->send_time, GNUNET_TIME_absolute_get());
-#if DEBUG_TRANSPORT
-          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                      "Confirmed validity of address, peer `%4s' has address 
`%s', latency of %llu\n",
-                      GNUNET_i2s (peer),
-                          GNUNET_a2s ((const struct sockaddr *) 
va->peer_address->addr,
-                          va->peer_address->addrlen), (unsigned long 
long)va->peer_address->latency.value);
-#endif
-          va->peer_address->transmit_ready = GNUNET_YES;
-          va->peer_address->expires = GNUNET_TIME_relative_to_absolute
-              (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
-        }
-      if (va->ok != GNUNET_YES)
-        not_done++;
-      va = va->next;
-    }
-  if (GNUNET_NO == matched)
+  if (GNUNET_SYSERR != 
+      GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
+                                                 &peer->hashPubKey,
+                                                 &check_pending_validation,
+                                                 (void*) message))
     {
-      /* 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
+      /* This is *expected* to happen a lot since we send
+        PONGs to *all* known addresses of the sender of
+        the PING, so most likely we get multiple PONGs
+        per PING, and all but the first PONG will end up
+        here. So really we should not print anything here
+        unless we want to be very, very verbose... */
+#if DEBUG_TRANSPORT > 1
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "All addresses validated, will now construct `%s' for 
`%4s'.\n",
-                  "HELLO", GNUNET_i2s (peer));
+                  "Received `%s' message from `%4s' but have no record of a 
matching `%s' message. Ignoring.\n",
+                  "PONG",
+                 GNUNET_i2s (peer),
+                 "PING");
 #endif
-      pos->timeout.value = 0;
-      GNUNET_SCHEDULER_add_with_priority (sched,
-                                          GNUNET_SCHEDULER_PRIORITY_IDLE,
-                                          &cleanup_validation, NULL);
+      return;
     }
-
+#if 0
+  /* FIXME: add given address to potential pool of our addresses
+     (for voting) */
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
+             _("Another peer saw us using the address `%s' via `%s'.\n"),
+             GNUNET_a2s ((const struct sockaddr *) &pong[1],
+                         ntohs(pong->addrlen)), 
+             va->transport_name);  
+#endif
 }
 
-/**
- * Add an entry for each of our transport plugins
- * (that are able to send) to the list of plugins
- * for this neighbor.
- *
- * @param neighbor to initialize
- */
-static void
-add_plugins (struct NeighborList *neighbor)
-{
-  struct TransportPlugin *tp;
-  struct ReadyList *rl;
 
-  neighbor->retry_plugins_time
-    = GNUNET_TIME_relative_to_absolute (PLUGIN_RETRY_FREQUENCY);
-  tp = plugins;
-  while (tp != NULL)
-    {
-      if (tp->api->send != NULL)
-        {
-          rl = GNUNET_malloc (sizeof (struct ReadyList));
-          rl->next = neighbor->plugins;
-          neighbor->plugins = rl;
-          rl->plugin = tp;
-          rl->neighbor = neighbor;
-          rl->addresses = NULL;
-        }
-      tp = tp->next;
-    }
-}
-
 static void
 neighbor_timeout_task (void *cls,
                         const struct GNUNET_SCHEDULER_TaskContext *tc)
@@ -1850,6 +1815,7 @@
   disconnect_neighbor (n, GNUNET_NO);
 }
 
+
 /**
  * Create a fresh entry in our neighbor list for the given peer.
  * Will try to transmit our current HELLO to the new neighbor.  Also
@@ -1862,6 +1828,8 @@
 setup_new_neighbor (const struct GNUNET_PeerIdentity *peer)
 {
   struct NeighborList *n;
+  struct TransportPlugin *tp;
+  struct ReadyList *rl;
 
   GNUNET_assert (our_hello != NULL);
   n = GNUNET_malloc (sizeof (struct NeighborList));
@@ -1873,77 +1841,124 @@
     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);
+  tp = plugins;
+  while (tp != NULL)
+    {
+      if (tp->api->send != NULL)
+        {
+          rl = GNUNET_malloc (sizeof (struct ReadyList));
+          rl->next = n->plugins;
+          n->plugins = rl;
+          rl->plugin = tp;
+          rl->addresses = NULL;
+        }
+      tp = tp->next;
+    }
   n->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
                                                   
GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
                                                   &neighbor_timeout_task, n);
   transmit_to_peer (NULL, NULL, 0,
                     (const char *) our_hello, GNUNET_HELLO_size(our_hello),
-                    GNUNET_YES, n);
+                    GNUNET_NO, n);
   notify_clients_connect (peer, GNUNET_TIME_UNIT_FOREVER_REL);
   return n;
 }
 
-static struct PeerAddressList *
-add_peer_address(struct NeighborList *neighbor, const char *addr, size_t 
addrlen)
+
+/**
+ * Closure for 'check_address_exists'.
+ */
+struct CheckAddressExistsClosure
 {
-  /* FIXME: should return a list of PeerAddressLists, support for multiple 
transports! */
-  struct ReadyList *head = neighbor->plugins;
-  struct PeerAddressList * new_address;
+  /**
+   * Address to check for.
+   */
+  const void *addr;
 
-  GNUNET_assert(addr != NULL);
+  /**
+   * Name of the transport.
+   */
+  const char *tname;
 
-  new_address = NULL;
-  while (head != NULL)
+  /**
+   * Length of addr.
+   */
+  size_t addrlen;
+
+  /**
+   * Set to GNUNET_YES if the address exists.
+   */
+  int exists;
+};
+
+
+/**
+ * Iterator over hash map entries.  Checks if the given
+ * validation entry is for the same address as what is given
+ * in the closure.
+ *
+ * @param cls the 'struct CheckAddressExistsClosure*'
+ * @param key current key code (ignored)
+ * @param value value in the hash map ('struct ValidationEntry')
+ * @return GNUNET_YES if we should continue to
+ *         iterate (mismatch), GNUNET_NO if not (entry matched)
+ */
+static int
+check_address_exists (void *cls,
+                     const GNUNET_HashCode * key,
+                     void *value)
+{
+  struct CheckAddressExistsClosure *caec = cls;
+  struct ValidationEntry *ve = value;
+  if ( (0 == strcmp (caec->tname,
+                    ve->transport_name)) &&
+       (caec->addrlen == ve->addrlen) &&
+       (0 == memcmp (caec->addr,
+                    ve->addr,
+                    caec->addrlen)) )
     {
-      new_address = GNUNET_malloc(sizeof(struct PeerAddressList));
-      new_address->addr = GNUNET_malloc(addrlen);
-      memcpy(new_address->addr, addr, addrlen);
-      new_address->addrlen = addrlen;
-      new_address->connect_attempts = 0;
-      new_address->connected = GNUNET_YES; /* Set connected to GNUNET_YES, 
assuming that we're good */
-      new_address->expires = GNUNET_TIME_relative_to_absolute
-          (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
-      new_address->latency = GNUNET_TIME_relative_get_forever();
-      new_address->neighbor = neighbor;
-      new_address->plugin = head->plugin;
-      new_address->transmit_ready = GNUNET_YES;
-      new_address->timeout = GNUNET_TIME_relative_to_absolute
-          (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); /* FIXME: Do we need 
this? */
-      new_address->ready_list = head;
-      new_address->next = head->addresses;
-      head->addresses = new_address;
-      head = head->next;
+      caec->exists = GNUNET_YES;
+      return GNUNET_NO;
     }
-
-  return new_address;
+  return GNUNET_YES;
 }
 
-static struct PeerAddressList *
-find_peer_address(struct NeighborList *neighbor, const char *addr, size_t 
addrlen)
+
+/**
+ * HELLO validation cleanup task (validation failed).
+ *
+ * @param cls the 'struct ValidationEntry' that failed
+ * @param tc scheduler context (unused)
+ */
+static void
+timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext 
*tc)
 {
-  struct ReadyList *head = neighbor->plugins;
-  struct PeerAddressList *address_head;
-  while (head != NULL)
-    {
-      address_head = head->addresses;
-      while ((address_head != NULL) &&
-              (address_head->addrlen != addrlen) &&
-              (memcmp(address_head->addr, addr, addrlen) != 0))
-        {
-          address_head = address_head->next;
-        }
-      if (address_head != NULL)
-        return address_head;
+  struct ValidationEntry *va = cls;
+  struct GNUNET_PeerIdentity pid;
 
-      head = head->next;
-    }
-  return NULL;
+  GNUNET_CRYPTO_hash (&va->publicKey,
+                     sizeof (struct
+                             GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
+                     &pid.hashPubKey);
+  GNUNET_CONTAINER_multihashmap_remove (validation_map,
+                                       &pid.hashPubKey,
+                                       va);
+  GNUNET_free (va->transport_name);
+  GNUNET_free (va);
 }
 
+
 /**
- * Append the given address to the list of entries
- * that need to be validated.
+ * Check if the given address is already being validated; if not,
+ * append the given address to the list of entries that are being be
+ * validated and initiate validation.
+ *
+ * @param cls closure ('struct CheckHelloValidatedContext *')
+ * @param tname name of the transport
+ * @param expiration expiration time
+ * @param addr the address
+ * @param addrlen length of the address
+ * @return GNUNET_OK (always)
  */
 static int
 run_validation (void *cls,
@@ -1951,14 +1966,15 @@
                 struct GNUNET_TIME_Absolute expiration,
                 const void *addr, size_t addrlen)
 {
-  struct ValidationList *e = cls;
+  struct CheckHelloValidatedContext *chvc = cls;
+  struct GNUNET_PeerIdentity id;
   struct TransportPlugin *tp;
-  struct ValidationAddress *va;
-  struct GNUNET_PeerIdentity id;
+  struct ValidationEntry *va;
   struct NeighborList *neighbor;
-  struct PeerAddressList *peer_address;
-  ssize_t sent;
-  struct TransportPingMessage *ping;
+  struct ForeignAddressList *peer_address;
+  struct TransportPingMessage ping;
+  struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
+  struct CheckAddressExistsClosure caec;
   char * message_buf;
   uint16_t hello_size;
   size_t tsize;
@@ -1973,164 +1989,194 @@
                   tname);
       return GNUNET_OK;
     }
-  GNUNET_CRYPTO_hash (&e->publicKey,
+  GNUNET_HELLO_get_key (chvc->hello, &pk);
+  GNUNET_CRYPTO_hash (&pk,
                       sizeof (struct
                               GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
                       &id.hashPubKey);
-#if DEBUG_TRANSPORT
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Scheduling validation of address `%s' via `%s' for `%4s'\n",
-              GNUNET_a2s (addr, addrlen), tname, GNUNET_i2s (&id));
+  caec.addr = addr;
+  caec.addrlen = addrlen;
+  caec.tname = tname;
+  caec.exists = GNUNET_NO;
+  GNUNET_CONTAINER_multihashmap_iterate (validation_map,
+                                        &check_address_exists,
+                                        &caec);
+  if (caec.exists == GNUNET_YES)
+    {
+      /* During validation attempts we will likely trigger the other
+        peer trying to validate our address which in turn will cause
+        it to send us its HELLO, so we expect to hit this case rather
+        frequently.  Only print something if we are very verbose. */
+#if DEBUG_TRANSPORT > 1
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                 "Validation of address `%s' via `%s' for peer `%4s' already 
in progress.\n",
+                 GNUNET_a2s (addr, addrlen), 
+                 tname, 
+                 GNUNET_i2s (&id));
 #endif
-  va = GNUNET_malloc (sizeof (struct ValidationAddress));
-  va->next = e->addresses;
-  e->addresses = va;
+      return GNUNET_OK;
+    } 
+  va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
   va->transport_name = GNUNET_strdup (tname);
   va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
                                             (unsigned int) -1);
   va->send_time = GNUNET_TIME_absolute_get();
-
-  neighbor = find_neighbor(&id);
-
+  va->addr = (const void*) &va[1];
+  memcpy (&va[1], addr, addrlen);
+  va->addrlen = addrlen;
+  GNUNET_HELLO_get_key (chvc->hello,
+                       &va->publicKey);
+  va->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
+                                                  HELLO_VERIFICATION_TIMEOUT,
+                                                  &timeout_hello_validation,
+                                                  va);  
+  GNUNET_CONTAINER_multihashmap_put (validation_map,
+                                    &id.hashPubKey,
+                                    va,
+                                    
GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
+  neighbor = find_neighbor(&id);  
   if (neighbor == NULL)
     neighbor = setup_new_neighbor(&id);
-
-  peer_address = find_peer_address(neighbor, addr, addrlen);
-  if (peer_address == NULL)
-    {
-      peer_address = add_peer_address(neighbor, addr, addrlen);
-    }
-
+  peer_address = add_peer_address(neighbor, tname, addr, addrlen);    
   GNUNET_assert(peer_address != NULL);
-
-  va->peer_address = peer_address; /* Back pointer FIXME: remove this 
nonsense! */
-  peer_address->validation = va;
-
   hello_size = GNUNET_HELLO_size(our_hello);
   tsize = sizeof(struct TransportPingMessage) + hello_size;
-
   message_buf = GNUNET_malloc(tsize);
-
-  ping = GNUNET_malloc(sizeof(struct TransportPingMessage));
-  ping->challenge = htonl(va->challenge);
-  ping->header.size = htons(sizeof(struct TransportPingMessage));
-  ping->header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
-  memcpy(&ping->target, &id, sizeof(struct GNUNET_PeerIdentity));
-
-#if DEBUG_TRANSPORT
-  GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, 
-            "`%s' message size is %u, ping size is %u, total size is %u\n", 
-            "HELLO",
-            hello_size, 
-            sizeof(struct TransportPingMessage), 
-            tsize);
-#endif
+  ping.challenge = htonl(va->challenge);
+  ping.header.size = htons(sizeof(struct TransportPingMessage));
+  ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
+  memcpy(&ping.target, &id, sizeof(struct GNUNET_PeerIdentity));
   memcpy(message_buf, our_hello, hello_size);
   memcpy(&message_buf[hello_size], 
-        ping, 
+        &ping, 
         sizeof(struct TransportPingMessage));
-
 #if DEBUG_TRANSPORT
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Sending `%s' message of size %u to address `%s' via `%s' for 
`%4s'\n",
-             "PING",
-             tsize, GNUNET_a2s (addr, addrlen), 
-             tname, GNUNET_i2s (&id));
+              "Performing validation of address `%s' via `%s' for peer `%4s' 
sending `%s' (%u bytes) and `%s' (%u bytes)\n",
+              GNUNET_a2s (addr, addrlen), 
+             tname, 
+             GNUNET_i2s (&id),
+             "HELLO", hello_size,
+             "PING", sizeof (struct TransportPingMessage));
 #endif
-  sent = transmit_to_peer(NULL, peer_address, 
-                         GNUNET_SCHEDULER_PRIORITY_DEFAULT,
-                         message_buf, tsize, GNUNET_NO, neighbor);
+  transmit_to_peer(NULL, peer_address, 
+                  GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+                  message_buf, tsize, 
+                  GNUNET_YES, neighbor);
+  GNUNET_free(message_buf);
+  return GNUNET_OK;
+}
 
+
+/**
+ * Add the given address to the list of foreign addresses
+ * available for the given peer (check for duplicates).
+ *
+ * @param cls the respective 'struct NeighborList' to update
+ * @param tname name of the transport
+ * @param expiration expiration time
+ * @param addr the address
+ * @param addrlen length of the address
+ * @return GNUNET_OK (always)
+ */
+static int
+add_to_foreign_address_list (void *cls,
+                            const char *tname,
+                            struct GNUNET_TIME_Absolute expiration,
+                            const void *addr, size_t addrlen)
+{
+  struct NeighborList *n = cls;
+  struct ForeignAddressList *fal;
+
+  fal = find_peer_address (n, tname, addr, addrlen);
+  if (fal == NULL)
+    {
 #if DEBUG_TRANSPORT
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
-             "Transport returned %d from send!\n", sent);
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                 "Adding address `%s' (%s) for peer `%4s' due to peerinfo 
data.\n",
+                 GNUNET_a2s (addr, addrlen),
+                 tname,
+                 GNUNET_i2s (&n->id));
 #endif
-
-  GNUNET_free(ping);
-  GNUNET_free(message_buf);
+      fal = add_peer_address (n, tname, addr, addrlen);
+    }
+  fal->expires = GNUNET_TIME_absolute_max (expiration,
+                                          fal->expires);
+  fal->validated = GNUNET_YES;
   return GNUNET_OK;
 }
 
 
 /**
  * Check if addresses in validated hello "h" overlap with
- * those in "chvc->hello" and update "chvc->hello" accordingly,
- * removing those addresses that have already been validated.
+ * those in "chvc->hello" and validate the rest.
+ *
+ * @param cls closure
+ * @param peer id of the peer, NULL for last call
+ * @param hello hello message for the peer (can be NULL)
+ * @param trust amount of trust we have in the peer (not used)
  */
 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;
-  int count;
-  struct GNUNET_PeerIdentity apeer;
+  struct GNUNET_HELLO_Message *plain_hello;
+  struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
+  struct GNUNET_PeerIdentity target;
+  struct NeighborList *n;
 
-  first_call = GNUNET_NO;
-  if (chvc->e == NULL)
+  if (peer == NULL)
     {
       chvc->piter = NULL;
-      first_call = GNUNET_YES;
-      chvc->e = GNUNET_malloc (sizeof (struct ValidationList));
-      GNUNET_assert (GNUNET_OK ==
-                     GNUNET_HELLO_get_key (h != NULL ? h : chvc->hello,
-                                           &chvc->e->publicKey));
-      chvc->e->timeout =
-        GNUNET_TIME_relative_to_absolute (HELLO_VERIFICATION_TIMEOUT);
-      chvc->e->next = pending_validations;
-      pending_validations = chvc->e;
-    }
-
-  if (h != NULL)
-    {
-      GNUNET_HELLO_iterate_new_addresses (chvc->hello,
-                                          h,
-                                          GNUNET_TIME_absolute_get (),
-                                          &run_validation, chvc->e);
-    }
-  else if (GNUNET_YES == first_call)
-    {
-      /* no existing HELLO, all addresses are new */
-      GNUNET_HELLO_iterate_addresses (chvc->hello,
-                                      GNUNET_NO, &run_validation, chvc->e);
-    }
-
-  if (h != NULL)
-    return;                     /* wait for next call */
-  /* finally, transmit validation attempts */
-  GNUNET_assert (GNUNET_OK == GNUNET_HELLO_get_id (chvc->hello, &apeer));
-
-  va = chvc->e->addresses;
-  count = 0;
-  while (va != NULL)
-    {
+      GNUNET_CONTAINER_DLL_remove (chvc_head,
+                                  chvc_tail,
+                                  chvc);
+      if (GNUNET_NO == chvc->hello_known)
+       {
+         /* notify PEERINFO about the peer now, so that we at least
+            have the public key if some other component needs it */
+         GNUNET_HELLO_get_key (chvc->hello, &pk);
+         GNUNET_CRYPTO_hash (&pk,
+                             sizeof (struct 
GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
+                             &target.hashPubKey);
+         plain_hello = GNUNET_HELLO_create (&pk,
+                                            NULL, 
+                                            NULL);
+         GNUNET_PEERINFO_add_peer (cfg, sched, &target, plain_hello);
+         GNUNET_free (plain_hello);
 #if DEBUG_TRANSPORT
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "Establishing `%s' connection to validate `%s' address `%s' 
of `%4s'\n",
-                  va->transport_name,
-                  "HELLO",
-                  GNUNET_a2s ((const struct sockaddr *) va->peer_address->addr,
-                              va->peer_address->addrlen), GNUNET_i2s (&apeer));
+         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                     "Peerinfo had no `%s' message for peer `%4s', full 
validation needed.\n",
+                     "HELLO",
+                     GNUNET_i2s (&target));
 #endif
-      tp = find_transport (va->transport_name);
-      GNUNET_assert (tp != NULL);
-      /* This validation should happen inside the transport, not from the 
plugin! */
-      va->ok = GNUNET_SYSERR;
-      va = va->next;
-      count++;
+         GNUNET_HELLO_iterate_addresses (chvc->hello,
+                                         GNUNET_NO, 
+                                         &run_validation, 
+                                         chvc);
+       }
+      GNUNET_free (chvc);
+      return;
     }
-
-  GNUNET_SCHEDULER_add_delayed (sched,
-                                GNUNET_TIME_absolute_get_remaining (chvc->
-                                                                    
e->timeout),
-                                &cleanup_validation, NULL);
-  GNUNET_free (chvc);
+  if (h == NULL)
+    return;
+  chvc->hello_known = GNUNET_YES;
+  n = find_neighbor (peer);
+  if (n != NULL)
+    GNUNET_HELLO_iterate_addresses (h,
+                                   GNUNET_NO,
+                                   &add_to_foreign_address_list,
+                                   n);
+  GNUNET_HELLO_iterate_new_addresses (chvc->hello,
+                                     h,
+                                     GNUNET_TIME_absolute_get (),
+                                     &run_validation, 
+                                     chvc);
 }
 
-
 /**
  * Process HELLO-message.
  *
@@ -2142,7 +2188,6 @@
 process_hello (struct TransportPlugin *plugin,
                const struct GNUNET_MessageHeader *message)
 {
-  struct ValidationList *e;
   uint16_t hsize;
   struct GNUNET_PeerIdentity target;
   const struct GNUNET_HELLO_Message *hello;
@@ -2157,7 +2202,8 @@
       return GNUNET_SYSERR;
     }
   /* first, check if load is too high */
-  if (GNUNET_OS_load_cpu_get (cfg) > 100)
+  if (GNUNET_SCHEDULER_get_load (sched,
+                                GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > 
MAX_HELLO_LOAD)
     {
       /* TODO: call to stats? */
       return GNUNET_OK;
@@ -2173,40 +2219,18 @@
                       &target.hashPubKey);
 #if DEBUG_TRANSPORT
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Processing `%s' message for `%4s' of size %d (hsize is %d)\n",
-              "HELLO", GNUNET_i2s (&target), GNUNET_HELLO_size(hello), hsize);
+              "Processing `%s' message for `%4s' of size %u\n",
+              "HELLO", 
+             GNUNET_i2s (&target), 
+             GNUNET_HELLO_size(hello));
 #endif
 
-#if DEBUG_TRANSPORT
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Notifying peerinfo about peer %s\n",
-              GNUNET_i2s (&target));
-#endif
-
-  /* check if a HELLO for this peer is already on the validation list */
-  e = pending_validations;
-  while (e != NULL)
-    {
-      if (0 == memcmp (&e->publicKey,
-                       &publicKey,
-                       sizeof (struct
-                               GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)))
-        {
-          /* 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
-          return GNUNET_OK;
-        }
-      e = e->next;
-    }
   chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
-  chvc->plugin = plugin;
-  chvc->hello = (struct GNUNET_HELLO_Message *) &chvc[1];
-  chvc->e = NULL;
-  memcpy (chvc->hello, hello, hsize);
+  chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
+  memcpy (&chvc[1], hello, hsize);
+  GNUNET_CONTAINER_DLL_insert (chvc_head,
+                              chvc_tail,
+                              chvc);
   /* finally, check if HELLO was previously validated
      (continuation will then schedule actual validation) */
   chvc->piter = GNUNET_PEERINFO_iterate (cfg,
@@ -2240,8 +2264,8 @@
   struct NeighborList *nprev;
   struct NeighborList *n;
   struct MessageQueue *mq;
-  struct PeerAddressList *peer_addresses;
-  struct PeerAddressList *peer_pos;
+  struct ForeignAddressList *peer_addresses;
+  struct ForeignAddressList *peer_pos;
 
   if (neighbors == NULL)
     return; /* We don't have any neighbors, so client has an already removed 
handle! */
@@ -2296,7 +2320,6 @@
   while (NULL != (rpos = n->plugins))
     {
       n->plugins = rpos->next;
-      GNUNET_assert (rpos->neighbor == n);
       if (GNUNET_YES == rpos->connected)
         rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
 
@@ -2304,7 +2327,6 @@
         {
           peer_pos = rpos->addresses;
           rpos->addresses = peer_pos->next;
-          GNUNET_free(peer_pos->addr);
           GNUNET_free(peer_pos);
         }
       GNUNET_free (rpos);
@@ -2314,8 +2336,9 @@
   while (NULL != (mq = n->messages))
     {
       n->messages = mq->next;
-      GNUNET_assert (0 == memcmp(mq->neighbor_id, &n->id, sizeof(struct 
GNUNET_PeerIdentity)));
-      GNUNET_free (mq->neighbor_id);
+      GNUNET_assert (0 == memcmp(&mq->neighbor_id, 
+                                &n->id,
+                                sizeof(struct GNUNET_PeerIdentity)));
       GNUNET_free (mq);
     }
   if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
@@ -2325,30 +2348,28 @@
 }
 
 
-/*
+/**
  * 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...
+ * in response to the peer by any means necessary. 
+ *
+ * FIXME: With something like TCP where a connection exists, we may
+ * want to send it that way.  But the current API does not seem to
+ * allow us to do so (can't tell this to the transport!)
  */
-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)
+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;
-  struct PeerAddressList *peer_address;
   uint16_t msize;
   struct NeighborList *n;
+  struct ReadyList *rl;
+  struct ForeignAddressList *fal;
 
-#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))
     {
@@ -2361,12 +2382,18 @@
                    sizeof (struct GNUNET_PeerIdentity)))
     {
       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                  _("Received `%s' message not destined for me!\n"), "PING");
+                  _("Received `%s' message not destined for me!\n"), 
+                 "PING");
       return GNUNET_SYSERR;
     }
-
+#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 -= sizeof (struct TransportPingMessage);
-
   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);
@@ -2377,8 +2404,9 @@
   pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_TCP_PING);
   pong->challenge = ping->challenge;
   pong->addrlen = htons(sender_address_len);
-
-  memcpy(&pong->signer, &my_public_key, sizeof(struct 
GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
+  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,
@@ -2387,23 +2415,28 @@
   n = find_neighbor(peer);
   if (n == NULL)
     n = setup_new_neighbor(peer);
-
-  peer_address = find_peer_address(n, sender_address, sender_address_len);
-  if (peer_address == NULL)
-    peer_address = add_peer_address(n, sender_address, sender_address_len);
-
-  peer_address->timeout = 
GNUNET_TIME_relative_to_absolute(GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
-
-  /* We don't use the peer_address because the address we received the message 
from may not
-   * be a reliable way to send it back!  We add it to the list which should 
queue up a separate
-   * ping to determine if the address is viable.
-   */
-  transmit_to_peer(NULL, NULL, TRANSPORT_DEFAULT_PRIORITY, (char *)pong, 
ntohs(pong->header.size), GNUNET_NO, n);
-
+  /* broadcast 'PONG' to all available addresses */
+  rl = n->plugins;
+  while (rl != NULL)
+    {
+      fal = rl->addresses;
+      while (fal != NULL)
+       {
+         transmit_to_peer(NULL, fal,
+                          TRANSPORT_DEFAULT_PRIORITY, 
+                          (const char *)pong, 
+                          ntohs(pong->header.size), 
+                          GNUNET_YES, 
+                          n);
+         fal = fal->next;
+       }
+      rl = rl->next;
+    }
   GNUNET_free(pong);
   return GNUNET_OK;
 }
 
+
 /**
  * Function called by the plugin for each received message.
  * Update data volumes, possibly notify plugins about
@@ -2432,7 +2465,7 @@
   struct TransportPlugin *plugin = cls;
   struct TransportClient *cpos;
   struct InboundMessage *im;
-  struct PeerAddressList *peer_address;
+  struct ForeignAddressList *peer_address;
   uint16_t msize;
   struct NeighborList *n;
 
@@ -2444,11 +2477,6 @@
       n = setup_new_neighbor (peer);
 
     }
-
-  peer_address = find_peer_address(n, sender_address, sender_address_len);
-  if (peer_address == NULL)
-    peer_address = add_peer_address(n, sender_address, sender_address_len);
-
   service_context = n->plugins;
   while ((service_context != NULL) && (plugin != service_context->plugin))
     service_context = service_context->next;
@@ -2466,19 +2494,18 @@
       disconnect_neighbor (n, GNUNET_YES);
       return;
     }
-#if DEBUG_TRANSPORT
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
-              "Processing message of type %u received by plugin...\n",
-              ntohs (message->type));
-#endif
+  peer_address = add_peer_address(n, 
+                                 plugin->short_name,
+                                 sender_address, 
+                                 sender_address_len);
   if (service_context != NULL)
     {
       if (service_context->connected == GNUNET_NO)
         {
-          /*service_context->connected = GNUNET_YES;*/
-          /* FIXME: What to do here?  Should we use these as well, to specify 
some Address
-           * in the AddressList should be available?
-           */
+          service_context->connected = GNUNET_YES;
+          /* FIXME: What to do here?  Should we use these as well, 
+            to specify some Address in the AddressList should be
+            available? */
           peer_address->transmit_ready = GNUNET_YES;
           peer_address->connect_attempts++;
         }
@@ -2507,41 +2534,23 @@
                   _
                   ("Dropping incoming message due to repeated bandwidth quota 
violations (total of %u).\n"), n->quota_violation_count);
       /* TODO: call stats */
-      GNUNET_assert ((service_context == NULL) ||
-                     (NULL != service_context->neighbor));
-
       return;
     }
   switch (ntohs (message->type))
     {
     case GNUNET_MESSAGE_TYPE_HELLO:
-#if DEBUG_TRANSPORT
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "Receiving `%s' message from `%4s'.\n", "HELLO",
-                  GNUNET_i2s (peer));
-#endif
       process_hello (plugin, message);
       break;
     case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
-#if DEBUG_TRANSPORT
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "Receiving `%s' message from `%4s'.\n", "PING",
-                  GNUNET_i2s (peer));
-#endif
       handle_ping(plugin, message, peer, sender_address, sender_address_len);
       break;
     case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
-#if DEBUG_TRANSPORT
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "Receiving `%s' message from `%4s'.\n", "PONG",
-                  GNUNET_i2s (peer));
-#endif
       handle_pong(plugin, message, peer, sender_address, sender_address_len);
       break;
     default:
 #if DEBUG_TRANSPORT
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "Received REAL MESSAGE type %u from `%4s', sending to all 
clients.\n",
+                  "Received message of type %u from `%4s', sending to all 
clients.\n",
                   ntohs (message->type), GNUNET_i2s (peer));
 #endif
       /* transmit message to all clients */
@@ -2560,8 +2569,6 @@
         }
       GNUNET_free (im);
     }
-  GNUNET_assert ((service_context == NULL) ||
-                 (NULL != service_context->neighbor));
 }
 
 
@@ -2725,7 +2732,8 @@
               ntohs (obmm->size),
               ntohs (obmm->type), GNUNET_i2s (&obm->peer));
 #endif
-  transmit_to_peer (tc, NULL, ntohl (obm->priority), (char *)obmm, ntohs 
(obmm->size), GNUNET_NO, n);
+  transmit_to_peer (tc, NULL, ntohl (obm->priority), (char *)obmm, 
+                   ntohs (obmm->size), GNUNET_NO, n);
   GNUNET_SERVER_receive_done (client, GNUNET_OK);
 }
 
@@ -2798,24 +2806,12 @@
               "TRY_CONNECT", client, GNUNET_i2s (&tcm->peer));
 #endif
   neighbor = find_neighbor(&tcm->peer);
-
   if (neighbor == NULL)
     setup_new_neighbor (&tcm->peer);
-  else
-    {
-#if DEBUG_TRANSPORT
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "Client asked to connect to `%4s', but connection already 
exists\n",
-                  "TRY_CONNECT", GNUNET_i2s (&tcm->peer));
-#endif
-      transmit_to_peer (NULL, NULL, 0,
-                        (const char *) our_hello, GNUNET_HELLO_size(our_hello),
-                        GNUNET_YES, neighbor);
-      notify_clients_connect (&tcm->peer, GNUNET_TIME_UNIT_FOREVER_REL);
-    }
   GNUNET_SERVER_receive_done (client, GNUNET_OK);
 }
 
+
 static void
 transmit_address_to_client (void *cls, const char *address)
 {
@@ -2832,6 +2828,7 @@
     GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
 }
 
+
 /**
  * Handle AddressLookup-message.
  *
@@ -3017,16 +3014,40 @@
 
 
 /**
- * Function called when the service shuts down.  Unloads our plugins.
+ * Iterator to free entries in the validation_map.
  *
+ * @param cls closure (unused)
+ * @param key current key code
+ * @param value value in the hash map (validation to abort)
+ * @return GNUNET_YES (always)
+ */
+static int 
+abort_validation (void *cls,
+                 const GNUNET_HashCode * key,
+                 void *value)
+{
+  struct ValidationEntry *va = value;
+
+  GNUNET_SCHEDULER_cancel (sched, va->timeout_task);
+  GNUNET_free (va->transport_name);
+  GNUNET_free (va);
+  return GNUNET_YES;
+}
+
+
+/**
+ * Function called when the service shuts down.  Unloads our plugins
+ * and cancels pending validations.
+ *
  * @param cls closure, unused
  * @param tc task context (unused)
  */
 static void
-unload_plugins (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
   struct TransportPlugin *plug;
-  struct AddressList *al;
+  struct OwnAddressList *al;
+  struct CheckHelloValidatedContext *chvc;
 
 #if DEBUG_TRANSPORT
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -3048,6 +3069,20 @@
   if (my_private_key != NULL)
     GNUNET_CRYPTO_rsa_key_free (my_private_key);
   GNUNET_free_non_null (our_hello);
+
+  /* free 'chvc' data structure */
+  while (NULL != (chvc = chvc_head))
+    {
+      chvc_head = chvc->next;
+      GNUNET_PEERINFO_iterate_cancel (chvc->piter);
+      GNUNET_free (chvc);
+    }
+  chvc_tail = NULL;
+
+  GNUNET_CONTAINER_multihashmap_iterate (validation_map,
+                                        &abort_validation,
+                                        NULL);
+  GNUNET_CONTAINER_multihashmap_destroy (validation_map);
 }
 
 
@@ -3073,6 +3108,7 @@
 
   sched = s;
   cfg = c;
+  validation_map = GNUNET_CONTAINER_multihashmap_create (64);
   /* parse configuration */
   if ((GNUNET_OK !=
        GNUNET_CONFIGURATION_get_value_number (c,
@@ -3127,7 +3163,7 @@
     }
   GNUNET_SCHEDULER_add_delayed (sched,
                                 GNUNET_TIME_UNIT_FOREVER_REL,
-                                &unload_plugins, NULL);
+                                &shutdown_task, NULL);
   if (no_transports)
     refresh_hello ();
 

Modified: gnunet/src/transport/plugin_transport.h
===================================================================
--- gnunet/src/transport/plugin_transport.h     2010-02-14 23:59:30 UTC (rev 
10294)
+++ gnunet/src/transport/plugin_transport.h     2010-02-14 23:59:47 UTC (rev 
10295)
@@ -197,7 +197,7 @@
   (*GNUNET_TRANSPORT_TransmitFunction) (void *cls,
                                         const struct GNUNET_PeerIdentity *
                                         target,
-                                        char *msgbuf,
+                                        const char *msgbuf,
                                         size_t msgbuf_size,
                                         uint32_t priority,
                                         struct GNUNET_TIME_Relative timeout,

Modified: gnunet/src/transport/plugin_transport_tcp.c
===================================================================
--- gnunet/src/transport/plugin_transport_tcp.c 2010-02-14 23:59:30 UTC (rev 
10294)
+++ gnunet/src/transport/plugin_transport_tcp.c 2010-02-14 23:59:47 UTC (rev 
10295)
@@ -416,7 +416,8 @@
                            &session->target, GNUNET_OK);
       GNUNET_free (pm);
     }
-  process_pending_messages (session);
+  if (session->client != NULL)
+    process_pending_messages (session);
 #if DEBUG_TCP
   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
                    "tcp", "Transmitting %u bytes\n", ret);
@@ -1112,22 +1113,18 @@
   session = find_session_by_client (plugin, client);
 
   if (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME == ntohs(message->type))
-  {
+    {
 #if DEBUG_TCP
-  GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
-                   "tcp", "Received a welcome, NOT sending to clients!\n");
+      GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
+                      "tcp", "Received a welcome, NOT sending to clients!\n");
 #endif
-    GNUNET_SERVER_receive_done (client, GNUNET_OK);
-    return; /* We don't want to propagate WELCOME messages up! */
-  }
-  else
-    {
+      GNUNET_SERVER_receive_done (client, GNUNET_OK);
+      return; /* We don't want to propagate WELCOME messages up! */
+    }    
 #if DEBUG_TCP
   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
                    "tcp", "Received DATA message, checking session!\n");
 #endif
-    }
-
   if ( (NULL == session) || (GNUNET_NO != session->expecting_welcome))
     {
       GNUNET_break_op (0);

Modified: gnunet/src/transport/plugin_transport_template.c
===================================================================
--- gnunet/src/transport/plugin_transport_template.c    2010-02-14 23:59:30 UTC 
(rev 10294)
+++ gnunet/src/transport/plugin_transport_template.c    2010-02-14 23:59:47 UTC 
(rev 10295)
@@ -148,7 +148,7 @@
 template_plugin_send (void *cls,
                       const struct GNUNET_PeerIdentity *
                       target,
-                      char *msgbuf,
+                      const char *msgbuf,
                       size_t msgbuf_size,
                       unsigned int priority,
                       struct GNUNET_TIME_Relative timeout,

Modified: gnunet/src/transport/plugin_transport_udp.c
===================================================================
--- gnunet/src/transport/plugin_transport_udp.c 2010-02-14 23:59:30 UTC (rev 
10294)
+++ gnunet/src/transport/plugin_transport_udp.c 2010-02-14 23:59:47 UTC (rev 
10295)
@@ -206,7 +206,7 @@
 static ssize_t
 udp_plugin_send (void *cls,
                  const struct GNUNET_PeerIdentity *target,
-                 char *msgbuf,
+                 const char *msgbuf,
                  size_t msgbuf_size,
                  unsigned int priority,
                  struct GNUNET_TIME_Relative timeout,

Modified: gnunet/src/transport/test_transport_api.c
===================================================================
--- gnunet/src/transport/test_transport_api.c   2010-02-14 23:59:30 UTC (rev 
10294)
+++ gnunet/src/transport/test_transport_api.c   2010-02-14 23:59:47 UTC (rev 
10295)
@@ -103,6 +103,7 @@
   GNUNET_CONFIGURATION_destroy (p->cfg);
 }
 
+
 static void
 end_badly ()
 {

Modified: gnunet/src/transport/test_transport_api_tcp_peer1.conf
===================================================================
--- gnunet/src/transport/test_transport_api_tcp_peer1.conf      2010-02-14 
23:59:30 UTC (rev 10294)
+++ gnunet/src/transport/test_transport_api_tcp_peer1.conf      2010-02-14 
23:59:47 UTC (rev 10295)
@@ -61,13 +61,14 @@
 
 [transport]
 PLUGINS = tcp
-DEBUG = NO
-#PREFIX = valgrind --leak-check=full --log-file=valgrind_tcp_peer1.log
+DEBUG = YES
+#PREFIX = xterm -T transport2 -e gdb --command=cmd --args
+#PREFIX = valgrind --leak-check=full
 ALLOW_SHUTDOWN = YES
 ACCEPT_FROM6 = ::1;
 ACCEPT_FROM = 127.0.0.1;
 NEIGHBOUR_LIMIT = 50
-BINARY = gnunet-service-transport
+BINARY = /home/grothoff/bin/gnunet-service-transport
 CONFIG = $DEFAULTCONFIG
 HOME = $SERVICEHOME
 HOSTNAME = localhost

Modified: gnunet/src/transport/test_transport_api_tcp_peer2.conf
===================================================================
--- gnunet/src/transport/test_transport_api_tcp_peer2.conf      2010-02-14 
23:59:30 UTC (rev 10294)
+++ gnunet/src/transport/test_transport_api_tcp_peer2.conf      2010-02-14 
23:59:47 UTC (rev 10295)
@@ -61,17 +61,19 @@
 
 [transport]
 PLUGINS = tcp
-DEBUG = NO
+DEBUG = YES
 PREFIX = 
 ALLOW_SHUTDOWN = YES
 ACCEPT_FROM6 = ::1;
 ACCEPT_FROM = 127.0.0.1;
 NEIGHBOUR_LIMIT = 50
-BINARY = gnunet-service-transport
+BINARY = /home/grothoff/bin/gnunet-service-transport
 CONFIG = $DEFAULTCONFIG
 HOME = $SERVICEHOME
 HOSTNAME = localhost
 PORT = 22365
+#PREFIX = xterm -T transport1 -e gdb --command=cmd --args
+#PREFIX = valgrind --leak-check=full
 
 [peerinfo]
 TRUST = $SERVICEHOME/data/credit/





reply via email to

[Prev in Thread] Current Thread [Next in Thread]