gnunet-svn
[Top][All Lists]
Advanced

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

[GNUnet-SVN] r9874 - in GNUnet/src: applications/dv/module include


From: gnunet
Subject: [GNUnet-SVN] r9874 - in GNUnet/src: applications/dv/module include
Date: Wed, 23 Dec 2009 19:06:54 +0100

Author: grothoff
Date: 2009-12-23 19:06:53 +0100 (Wed, 23 Dec 2009)
New Revision: 9874

Modified:
   GNUnet/src/applications/dv/module/dv.c
   GNUnet/src/include/dv.h
Log:
cleaning up heap API and fixing implementation

Modified: GNUnet/src/applications/dv/module/dv.c
===================================================================
--- GNUnet/src/applications/dv/module/dv.c      2009-12-23 16:21:18 UTC (rev 
9873)
+++ GNUnet/src/applications/dv/module/dv.c      2009-12-23 18:06:53 UTC (rev 
9874)
@@ -1,21 +1,21 @@
 /*
- This file is part of GNUnet.
- (C) 2008 Christian Grothoff (and other contributing authors)
-
- GNUnet is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 2, or (at your
- option) any later version.
-
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNUnet; see the file COPYING.  If not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
+  This file is part of GNUnet.
+  (C) 2008, 2009 Christian Grothoff (and other contributing authors)
+  
+  GNUnet is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published
+  by the Free Software Foundation; either version 2, or (at your
+  option) any later version.
+  
+  GNUnet is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  General Public License for more details.
+  
+  You should have received a copy of the GNU General Public License
+  along with GNUnet; see the file COPYING.  If not, write to the
+  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+  Boston, MA 02111-1307, USA.
  */
 
 /**
@@ -33,6 +33,13 @@
 #include "gnunet_stats_service.h"
 #include "dv.h"
 
+/**
+ * Should DV support hiding a fraction of our directly connected
+ * peers?  This is good for better anonymity (network harder to
+ * analyze for attackers), but likely not so good for testing DV...
+ */
+#define SUPPORT_HIDING GNUNET_NO
+
 #define DEBUG_DV_MAINTAIN GNUNET_NO
 #define DEBUG_DV GNUNET_NO
 #define DEBUG_DV_FORWARD GNUNET_NO
@@ -55,43 +62,83 @@
 static int stat_dv_received_gossips;
 static int stat_dv_unknown_peer;
 
-/*
- * Struct to map neighbor_id to GNUNET_PeerIdentity
+
+/**
+ * Struct where neighbor information is stored.
  */
+struct DistantNeighbor *referees;
 
-struct NeighborID
+/**
+ * Struct where actual neighbor information is stored,
+ * referenced by min_heap and max_heap.  Freeing dealt
+ * with when items removed from hashmap.
+ */
+struct DirectNeighbor
 {
-  unsigned int neighbor_id;
+  /**
+   * Identity of neighbor.
+   */
   GNUNET_PeerIdentity identity;
+
+  /**
+   * Head of DLL of nodes that this direct neighbor referred to us.
+   */
+  struct DistantNeighbor *referee_head;
+
+  /**
+   * Tail of DLL of nodes that this direct neighbor referred to us.
+   */
+  struct DistantNeighbor *referee_tail;
+
+  /**
+   * Is this one of the direct neighbors that we are "hiding"
+   * from DV?
+   */
+  int hidden;
 };
 
 
-/*
+/**
  * Struct where actual neighbor information is stored,
  * referenced by min_heap and max_heap.  Freeing dealt
  * with when items removed from hashmap.
  */
-struct GNUNET_dv_neighbor
+struct DistantNeighbor
 {
-  /*
-   * Back-pointer location in min heap
+  /**
+   * We keep distant neighbor's of the same referrer in a DLL.
    */
+  struct DistantNeighbor *next;
+
+  /**
+   * We keep distant neighbor's of the same referrer in a DLL.
+   */
+  struct DistantNeighbor *prev;
+
+  /**
+   * Node in min heap
+   */
   struct GNUNET_CONTAINER_HeapNode *min_loc;
 
-  /*
-   * Back-pointer location in max heap
+  /**
+   * Node in max heap
    */
   struct GNUNET_CONTAINER_HeapNode *max_loc;
 
   /**
+   * Identity of referrer (next hop towards 'neighbor').
+   */
+  struct DirectNeighbor *referrer;
+
+  /**
    * Identity of neighbor.
    */
-  GNUNET_PeerIdentity neighbor;
+  GNUNET_PeerIdentity identity;
 
   /**
-   * Identity of referrer (where we got the information)
+   * Last time we received routing information from this peer
    */
-  GNUNET_PeerIdentity *referrer;
+  GNUNET_CronTime last_activity;
 
   /**
    * Cost to neighbor, used for actual distance vector computations
@@ -99,31 +146,48 @@
   unsigned int cost;
 
   /**
-   * Last time we received routing information from this peer
+   * Random identifier *we* use for this peer, to be used as shortcut
+   * instead of sending full peer id for each message
    */
-  GNUNET_CronTime last_activity;
+  unsigned int our_id;
 
-  /*
-   * Random identifier we use for this peer, to be used as shortcut
-   * instead of sending full peer id for each message
+  /**
+   * Random identifier the *referrer* uses for this peer.
    */
-  unsigned int neighbor_id;
+  unsigned int referrer_id;
+
+  /**
+   * Is this one of the direct neighbors that we are "hiding"
+   * from DV?
+   */
+  int hidden;
 };
 
 
-
-/*
+/**
  * Global construct
  */
 struct GNUNET_DV_Context
 {
   struct GNUNET_Mutex *dvMutex;
+
+  /**
+   * Map of PeerIdentifiers to 'struct GNUNET_dv_neighbor*'s for all
+   * directly connected peers.
+   */
   struct GNUNET_MultiHashMap *direct_neighbors;
 
+  /**
+   * Map of PeerIdentifiers to 'struct GNUNET_dv_neighbor*'s for 
+   * peers connected via DV (extended neighborhood).  Does ALSO
+   * include any peers that are in 'direct_neighbors'; for those
+   * peers, the cost will be zero and the referrer all zeros.
+   */
   struct GNUNET_MultiHashMap *extended_neighbors;
+
   /**
    * We use the min heap (min refers to cost) to prefer
-   * gossipping about peers with small costs.
+   * gossipping about peers with small costs.  
    */
   struct GNUNET_CONTAINER_Heap *neighbor_min_heap;
 
@@ -133,50 +197,28 @@
    * connection if we have too many.
    */
   struct GNUNET_CONTAINER_Heap *neighbor_max_heap;
-  struct NeighborID *neighbor_id_array;
+
   unsigned long long fisheye_depth;
+
   unsigned long long max_table_size;
+
   unsigned int send_interval;
+
   unsigned int neighbor_id_loc;
-  unsigned short closing;
-};
 
-struct callbackWrapper
-{
-  GNUNET_NodeIteratorCallback method;
-  void *arg;
-  int cnt;
+  int closing;
 };
 
 static char shortID[5];
-static struct GNUNET_DV_Context *ctx;
-static struct GNUNET_ThreadHandle *sendingThread;
-static GNUNET_CoreAPIForPlugins *coreAPI;
 
-#if DEBUG_PEERS
-static int
-printPeer (const GNUNET_HashCode * key, void *value, void *cls)
-{
-  GNUNET_EncName enc;
-  GNUNET_hash_to_enc (key, &enc);
-  GNUNET_GE_LOG (coreAPI->ectx,
-                 GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER |
-                 GNUNET_GE_BULK, "\tPeer: %s", (char *) &enc);
-  return 1;
-}
-#endif
+static struct GNUNET_DV_Context ctx;
 
+static struct GNUNET_ThreadHandle *sendingThread;
 
-static int
-free_neighbor (const GNUNET_HashCode * key, void *value, void *cls)
-{
-  struct GNUNET_dv_neighbor * neighbor = value;
-  GNUNET_free_non_null(neighbor->referrer);
-  GNUNET_free (neighbor);
-  return GNUNET_YES;
-}
+static GNUNET_CoreAPIForPlugins *coreAPI;
 
-/*
+
+/**
  * Update the statistics about dv routing
  */
 static void
@@ -185,60 +227,43 @@
   if (stats == NULL)
     return;
   stats->set (stat_dv_total_peers,
-              GNUNET_multi_hash_map_size (ctx->extended_neighbors));
-#if DEBUG_PEERS
-  GNUNET_GE_LOG (coreAPI->ectx,
-                 GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER |
-                 GNUNET_GE_BULK, "%s: Known Peers\n", &shortID);
-  GNUNET_multi_hash_map_iterate (ctx->extended_neighbors, &printPeer, NULL);
-
-#endif
+              GNUNET_multi_hash_map_size (ctx.extended_neighbors));
 }
 
-/*
- * Deletes a neighbor from the max and min heaps and
- * from the extended neighbor hash map.  Does not delete
- * from the directly connected neighbor list, because
- * we like to keep those around.
- */
-static int
-delete_neighbor (struct GNUNET_dv_neighbor *neighbor)
-{
-  GNUNET_CONTAINER_heap_remove_node (ctx->neighbor_max_heap, 
-                                    neighbor->max_loc);
-  GNUNET_CONTAINER_heap_remove_node (ctx->neighbor_min_heap,
-                                    neighbor->min_loc);
-  GNUNET_multi_hash_map_remove_all (ctx->extended_neighbors,
-                                    &neighbor->neighbor.hashPubKey);
-  GNUNET_free_non_null (neighbor->referrer);
-  GNUNET_free (neighbor);
-  update_stats ();
-  return GNUNET_OK;
-}
 
-/*
- * A callback for iterating over all known nodes.
- */
-static int
-connection_iterate_callback (void *cls,
-                            struct GNUNET_CONTAINER_HeapNode *node,
-                            void *element,
-                            GNUNET_CONTAINER_HeapCostType cost)
+/**
+ * Free a DistantNeighbor node, including removing it
+ * from the referer's list.
+ */ 
+static void
+distant_neighbor_free (struct DistantNeighbor *referee)
 {
-  struct GNUNET_dv_neighbor *neighbor = element;
-  struct callbackWrapper *wrap = cls;
-  wrap->method (&neighbor->neighbor, wrap->arg);
-  wrap->cnt++;
-  return GNUNET_OK;
+  struct DirectNeighbor *referrer;
+
+  referrer = referee->referrer;
+  if (referrer != NULL)
+    {
+      GNUNET_DLL_remove (referrer->referee_head,
+                        referrer->referee_tail,
+                        referee);    
+    }
+  GNUNET_CONTAINER_heap_remove_node (ctx.neighbor_max_heap, 
+                                    referee->max_loc);
+  GNUNET_CONTAINER_heap_remove_node (ctx.neighbor_min_heap,
+                                    referee->min_loc);
+  GNUNET_multi_hash_map_remove_all (ctx.extended_neighbors,
+                                    &referee->identity.hashPubKey);
+  GNUNET_free (referee);                             
 }
 
 
-/*
+/**
  * A callback for deleting expired nodes from heaps...
  *
- * neighbor - the peer we may delete
- * root - the root of the heap
- * cls - unused
+ * @param cls unused
+ * @param node peer we may delete
+ * @param element 'DistantNeighbor' struct of that peer
+ * @param cost known communication cost
  */
 static int
 delete_expired_callback (void *cls,
@@ -246,486 +271,316 @@
                         void *element,
                         GNUNET_CONTAINER_HeapCostType cost)
 {
-  struct GNUNET_dv_neighbor *neighbor = element;
+  struct DistantNeighbor *neighbor = element;
   GNUNET_CronTime now;
 
+  if (cost == 0)
+    return GNUNET_OK; /* never delete direct neighbors */
   now = GNUNET_get_time ();
-  /*
-   * Why do we check if it is a direct neighbor? delete_neighbor
-   * only deletes from the extended list anyways...
-   */
-  if ((GNUNET_NO ==
-       GNUNET_multi_hash_map_contains (ctx->direct_neighbors,
-                                       &neighbor->neighbor.hashPubKey))
-      && (now - neighbor->last_activity > GNUNET_DV_PEER_EXPIRATION_TIME))
-    {
-#if DEBUG_DV_MAINTAIN
-      GNUNET_EncName encToDel;
-      GNUNET_hash_to_enc (&neighbor->neighbor->hashPubKey, &encToDel);
-      GNUNET_GE_LOG (coreAPI->ectx,
-                     GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER |
-                     GNUNET_GE_BULK,
-                     "%s: Entering delete_expired_callback, now is %llu, 
last_activity is %llu\nDifference is %llu, Max is %llu\nNode to remove is %s\n",
-                     &shortID, now, neighbor->last_activity,
-                     now - neighbor->last_activity,
-                     GNUNET_DV_PEER_EXPIRATION_TIME, (char *) &encToDel);
-#endif
-      delete_neighbor (neighbor);
-    }
+  if (now - neighbor->last_activity > GNUNET_DV_PEER_EXPIRATION_TIME)
+    distant_neighbor_free (neighbor);  /* FIXME: this changes 
'neighbor_max_heap' while we iterate over it! */
   return GNUNET_OK;
 }
 
+
 /**
  * Cron job to maintain dv routing table.
  */
 static void
 maintain_dv_job (void *unused)
 {
-  GNUNET_mutex_lock (ctx->dvMutex);
-  GNUNET_CONTAINER_heap_iterate (ctx->neighbor_max_heap,
+  GNUNET_mutex_lock (ctx.dvMutex);
+  GNUNET_CONTAINER_heap_iterate (ctx.neighbor_max_heap,
                                  &delete_expired_callback, NULL);
-  GNUNET_mutex_unlock (ctx->dvMutex);
+  GNUNET_mutex_unlock (ctx.dvMutex);
 }
 
+
 /**
  * Checks whether the given peer is known to us.
  *
  * @return GNUNET_YES if known, GNUNET_NO if not
  */
-int
+static int
 GNUNET_DV_have_peer (const GNUNET_PeerIdentity * peer)
 {
   int ret;
 
-  GNUNET_mutex_lock (ctx->dvMutex);
-  ret = GNUNET_multi_hash_map_contains (ctx->extended_neighbors,
+  GNUNET_mutex_lock (ctx.dvMutex);
+  ret = GNUNET_multi_hash_map_contains (ctx.extended_neighbors,
                                         &peer->hashPubKey);
-  GNUNET_mutex_unlock (ctx->dvMutex);
+  GNUNET_mutex_unlock (ctx.dvMutex);
   return ret;
 }
 
+
+struct IteratePeersWrapper
+{
+  GNUNET_NodeIteratorCallback method;
+  void *arg;
+  int cnt;
+};
+
+
 /**
+ * A callback for iterating over all known nodes.
+ */
+static int
+connection_iterate_callback (void *cls,
+                            struct GNUNET_CONTAINER_HeapNode *node,
+                            void *element,
+                            GNUNET_CONTAINER_HeapCostType cost)
+{
+  struct IteratePeersWrapper *wrap = cls;
+  struct DistantNeighbor *neighbor = element;
+
+  wrap->method (&neighbor->identity, wrap->arg);
+  wrap->cnt++;
+  return GNUNET_OK;
+}
+
+
+/**
  * Calls a given method for each dv connected host.
  *
  * @param method method to call for each connected peer
  * @param arg second argument to method
  * @return number of connected nodes
  */
-int
+static int
 GNUNET_DV_connection_iterate_peers (GNUNET_NodeIteratorCallback method,
                                     void *arg)
 {
-  struct callbackWrapper wrap;
+  struct IteratePeersWrapper wrap;
 
   wrap.method = method;
   wrap.arg = arg;
   wrap.cnt = 0;
-  GNUNET_mutex_lock (ctx->dvMutex);
-  GNUNET_CONTAINER_heap_iterate (ctx->neighbor_max_heap,
+  GNUNET_mutex_lock (ctx.dvMutex);
+  GNUNET_CONTAINER_heap_iterate (ctx.neighbor_max_heap,
                                 &connection_iterate_callback, &wrap);
-  GNUNET_mutex_unlock (ctx->dvMutex);
+  GNUNET_mutex_unlock (ctx.dvMutex);
   return wrap.cnt;
 }
 
 
-static unsigned int
-get_peer_id (const GNUNET_PeerIdentity * peer)
-{
-  struct GNUNET_dv_neighbor *neighbor;
-#if DEBUG_DV_FORWARD
-  GNUNET_EncName enc;
-  GNUNET_EncName encMe;
-#endif
-
-  if (GNUNET_YES ==
-      GNUNET_multi_hash_map_contains (ctx->extended_neighbors,
-                                      &peer->hashPubKey))
-    {
-      neighbor =
-        GNUNET_multi_hash_map_get (ctx->extended_neighbors,
-                                   &peer->hashPubKey);
-      return neighbor->neighbor_id;
-    }
-#if DEBUG_DV_FORWARD
-  GNUNET_hash_to_enc (&coreAPI->my_identity->hashPubKey, &encMe);
-  GNUNET_hash_to_enc (&peer->hashPubKey, &enc);
-  GNUNET_GE_LOG (coreAPI->ectx,
-                 GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER |
-                 GNUNET_GE_BULK,
-                 "%s: I AM:\n%s\nCould not find peer:\n%s\n\n",
-                 &shortID, (char *) &encMe, (char *) &enc);
-#endif
-  if (stats != NULL)
-    stats->change (stat_dv_unknown_peer, 1);
-  return GNUNET_SYSERR;
-}
-
-
-/*
+/**
  * Low level sending of a DV message
  */
 static int
-send_message (const GNUNET_PeerIdentity * recipient,
-              const GNUNET_PeerIdentity * original_sender,
-              const GNUNET_MessageHeader * message,
-              unsigned int importance, unsigned int maxdelay)
+send_message (const GNUNET_PeerIdentity *recipient,
+              const GNUNET_PeerIdentity *sender,
+              const GNUNET_MessageHeader *message,
+              unsigned int importance, 
+             unsigned int maxdelay)
 {
   p2p_dv_MESSAGE_Data *toSend;
   unsigned int msg_size;
   unsigned int cost;
   unsigned int recipient_id;
-  unsigned int original_sender_id;
-  struct GNUNET_dv_neighbor *neighbor;
-#if DEBUG_DV_FORWARD
-  GNUNET_EncName encVia;
-  GNUNET_EncName encRecipient;
-  GNUNET_EncName encMe;
+  unsigned int sender_id;
+  struct DistantNeighbor *target; 
+  struct DistantNeighbor *source; 
 
-  GNUNET_GE_LOG (coreAPI->ectx,
-                 GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER |
-                 GNUNET_GE_BULK, "%s: Entered send_message!\n", &shortID);
-#endif
   msg_size = ntohs (message->size) + sizeof (p2p_dv_MESSAGE_Data);
   if (msg_size > GNUNET_MAX_BUFFER_SIZE - 8)
     return GNUNET_SYSERR;
-  GNUNET_mutex_lock (ctx->dvMutex);
 
-  if (GNUNET_YES ==
-      GNUNET_multi_hash_map_contains (ctx->direct_neighbors,
-                                      &recipient->hashPubKey))
+  GNUNET_mutex_lock (ctx.dvMutex);
+  target = GNUNET_multi_hash_map_get (ctx.extended_neighbors,
+                                     &recipient->hashPubKey);
+  if (target == NULL)
     {
-      recipient_id = 0;
+      /* target unknown to us, drop! */
+      GNUNET_mutex_unlock (ctx.dvMutex);
+      return GNUNET_SYSERR;
     }
-  else
-    {
-      recipient_id = get_peer_id (recipient);
-    }
+  recipient_id = target->referrer_id;
 
-  if (memcmp
-      (&coreAPI->my_identity->hashPubKey, &original_sender->hashPubKey,
-       sizeof (GNUNET_HashCode)) == 0)
+  source = GNUNET_multi_hash_map_get (ctx.extended_neighbors,
+                                     &sender->hashPubKey);
+  if (source == NULL)
     {
-#if DEBUG_DV_FORWARD
-      GNUNET_GE_LOG (coreAPI->ectx,
-                     GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER |
-                     GNUNET_GE_BULK,
-                     "%s: In send_message, origin and me are the same!\n",
-                     &shortID);
-#endif
-      original_sender_id = 0;
+      if (0 != (memcmp (coreAPI->my_identity,
+                       sender,
+                       sizeof(GNUNET_PeerIdentity))))
+       {
+         /* sender unknown to us, drop! */
+         GNUNET_mutex_unlock (ctx.dvMutex);
+         return GNUNET_SYSERR;
+       }
+      sender_id = 0; /* 0 == us */
     }
   else
     {
-      original_sender_id = get_peer_id (original_sender);
+      /* find out the number that we use when we gossip about
+        the sender */
+      sender_id = source->our_id;
     }
 
-  if ((GNUNET_SYSERR == recipient_id) ||
-      (GNUNET_SYSERR == original_sender_id))
-    {
-      GNUNET_mutex_unlock (ctx->dvMutex);
-      if (original_sender_id == GNUNET_SYSERR)
-        {
-#if DEBUG_DV_FORWARD
-          GNUNET_GE_LOG (coreAPI->ectx,
-                         GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER
-                         | GNUNET_GE_BULK, "%s: Original sender unknown\n",
-                         &shortID);
-#endif
-        }
-      else if (recipient_id == GNUNET_SYSERR)
-        {
-#if DEBUG_DV_FORWARD
-          GNUNET_GE_LOG (coreAPI->ectx,
-                         GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER
-                         | GNUNET_GE_BULK, "%s: Recipient unknown\n",
-                         &shortID);
-#endif
-        }
-      return GNUNET_SYSERR;
-    }
-
-#if DEBUG_DV_FORWARD
-  GNUNET_GE_LOG (coreAPI->ectx,
-                 GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER |
-                 GNUNET_GE_BULK,
-                 "%s: In send message, sender id is %d, recipient id is %d\n",
-                 &shortID, original_sender_id, recipient_id);
-#endif
-
-  neighbor =
-    GNUNET_multi_hash_map_get (ctx->extended_neighbors,
-                               &recipient->hashPubKey);
-  GNUNET_GE_ASSERT (NULL, neighbor != NULL);
-  cost = neighbor->cost;
   toSend = GNUNET_malloc (msg_size);
   toSend->header.size = htons (msg_size);
   toSend->header.type = htons (GNUNET_P2P_PROTO_DV_DATA_MESSAGE);
-  toSend->sender = htonl (original_sender_id);
+  toSend->sender = htonl (sender_id);
   toSend->recipient = htonl (recipient_id);
   memcpy (&toSend[1], message, ntohs (message->size));
-#if DEBUG_DV_FORWARD
-  GNUNET_hash_to_enc (&original_sender->hashPubKey, &encMe);
-  GNUNET_hash_to_enc (&recipient->hashPubKey, &encRecipient);
-  GNUNET_GE_LOG (coreAPI->ectx,
-                 GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER |
-                 GNUNET_GE_BULK, "%s: Cost to intended peer is %d\n",
-                 &shortID, neighbor->cost);
-  if (neighbor->referrer != NULL)
-    {
-      GNUNET_hash_to_enc (&neighbor->referrer->hashPubKey, &encVia);
-      GNUNET_GE_LOG (coreAPI->ectx,
-                     GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER
-                     | GNUNET_GE_BULK,
-                     "%s: Original Sender:\n%s\nMessage intended 
for:\n%s\nSending via:\n%s\n\n",
-                     &shortID, (char *) &encMe, (char *) &encRecipient,
-                     (char *) &encVia);
-    }
-  else
-    {
-      GNUNET_GE_LOG (coreAPI->ectx,
-                     GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER
-                     | GNUNET_GE_BULK,
-                     "%s: Original Sender:\n%s\nMessage intended 
for:\n%s\nSending Direct.\n",
-                     &shortID, (char *) &encMe, (char *) &encRecipient);
-    }
-#endif
-  coreAPI->ciphertext_send ((neighbor->referrer != NULL)
-                            ? neighbor->referrer
-                            : &neighbor->neighbor,
-                            &toSend->header, importance, maxdelay);
+  coreAPI->ciphertext_send (&target->referrer->identity,
+                           &toSend->header, 
+                           importance,
+                           maxdelay);
   if (stats != NULL)
     stats->change (stat_dv_actual_sent_messages, 1);
   GNUNET_free (toSend);
-  GNUNET_mutex_unlock (ctx->dvMutex);
+  cost = target->cost;
+  GNUNET_mutex_unlock (ctx.dvMutex);
   return (int) cost;
 }
 
 
-/*
- * Forward a received message that was not intended
- * for us.
- *
- * @param message message being forwarded
+struct FindDestinationContext
+{
+  unsigned int tid;
+  struct DistantNeighbor *dest;
+};
+
+
+/**
+ * We've been given a target ID based on the random numbers that
+ * we assigned to our DV-neighborhood.  Find the entry for the
+ * respective neighbor.
  */
 static int
-forward_message (const p2p_dv_MESSAGE_Data * message,
-                 const GNUNET_PeerIdentity * sender)
+find_destination (void *cls,
+                 struct GNUNET_CONTAINER_HeapNode *node,
+                 void *element,
+                 GNUNET_CONTAINER_HeapCostType cost)
 {
-#if DEBUG_DV_FORWARD
-  GNUNET_EncName encMe;
-  GNUNET_EncName encRecipient;
-  GNUNET_EncName encOrigin;
-#endif
-  GNUNET_PeerIdentity recipient;
-  int ret;
-  int i;
-  const GNUNET_MessageHeader *packed_message =
-    (const GNUNET_MessageHeader *) &message[1];
+  struct FindDestinationContext *fdc = cls;
+  struct DistantNeighbor *dn = element;
 
-  if ((ntohs (message->header.size) < sizeof (p2p_dv_MESSAGE_Data))
-      || (ntohs (message->header.size) !=
-          (sizeof (p2p_dv_MESSAGE_Data) + ntohs (packed_message->size))))
-    {
-#if DEBUG_DV_FORWARD
-      GNUNET_GE_LOG (coreAPI->ectx,
-                     GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER |
-                     GNUNET_GE_BULK,
-                     "%s: Got bad message size.  Expected at least %d, got %d, 
packed message size %d\n",
-                     &shortID, sizeof (p2p_dv_MESSAGE_Data),
-                     ntohs (message->header.size),
-                     ntohs (packed_message->size));
-#endif
-      return GNUNET_SYSERR;
-    }
-
-  GNUNET_mutex_lock (ctx->dvMutex);
-  ret = GNUNET_SYSERR;
-  for (i = 0; i < ctx->max_table_size * 2; i++)
-    {
-      if (ntohl (message->recipient) == ctx->neighbor_id_array[i].neighbor_id)
-        {
-          memcpy (&recipient, &ctx->neighbor_id_array[i].identity,
-                  sizeof (GNUNET_PeerIdentity));
-          ret = GNUNET_OK;
-          break;
-        }
-    }
-  GNUNET_mutex_unlock (ctx->dvMutex);
-  if (ret == GNUNET_SYSERR)
-    return GNUNET_SYSERR;
-
-#if DEBUG_DV_FORWARD
-  GNUNET_hash_to_enc (&coreAPI->my_identity->hashPubKey, &encMe);
-  GNUNET_hash_to_enc (&recipient.hashPubKey, &encRecipient);
-  GNUNET_hash_to_enc (&sender->hashPubKey, &encOrigin);
-
-  GNUNET_GE_LOG (coreAPI->ectx,
-                 GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER |
-                 GNUNET_GE_BULK,
-                 "%s: Received message for:\n%s\nI am:\n%s\nOriginal 
Sender:\n%s\n",
-                 &shortID, (char *) &encRecipient, (char *) &encMe,
-                 (char *) &encOrigin);
-#endif
-  return send_message (&recipient,
-                       sender, packed_message, DV_PRIORITY, DV_DELAY);
+  if (fdc->tid != dn->our_id)
+    return GNUNET_YES;
+  fdc->dest = dn;
+  return GNUNET_NO;
 }
 
-/*
+
+/**
  * Handle a DATA message receipt, if recipient matches our identity
  * message is for this peer, otherwise check if we know of the
  * intended recipient and send onwards
  */
 static int
-p2pHandleDVDataMessage (const GNUNET_PeerIdentity * sender,
-                        const GNUNET_MessageHeader * message)
+p2pHandleDVDataMessage (const GNUNET_PeerIdentity *sender,
+                        const GNUNET_MessageHeader *message)
 {
-#if DEBUG_DV_FORWARD
-  GNUNET_EncName encMe;
-  GNUNET_EncName encSender;
-  GNUNET_EncName encOrigin;
-  unsigned int message_length;
-#endif
   const p2p_dv_MESSAGE_Data *incoming = (const p2p_dv_MESSAGE_Data *) message;
   const GNUNET_MessageHeader *packed_message
     = (const GNUNET_MessageHeader *) &incoming[1];
+  struct DirectNeighbor *dn;
+  struct DistantNeighbor *pos;
+  unsigned int sid;
+  unsigned int tid;
   GNUNET_PeerIdentity original_sender;
+  GNUNET_PeerIdentity destination;
+  struct FindDestinationContext fdc;
   int ret;
-  int i;
 
-#if DEBUG_DV_FORWARD
-  GNUNET_hash_to_enc (&sender->hashPubKey, &encSender);
-  GNUNET_GE_LOG (coreAPI->ectx,
-                 GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER |
-                 GNUNET_GE_BULK,
-                 "%s: Received data message:\nImmediate sender:\n%s\nOriginal 
Sender ID:\n%d\nDestination ID:%d\n",
-                 &shortID, (char *) &encSender, ntohl (incoming->sender),
-                 ntohl (incoming->recipient));
-
-#endif
-  ret = GNUNET_OK;
-
-#if DEBUG_DV
-  GNUNET_GE_LOG (coreAPI->ectx,
-                 GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER |
-                 GNUNET_GE_BULK,
-                 "%s: Received data message:\nOriginal Sender 
ID:\n%d\nDestination ID:%d, type: %d\n",
-                 &shortID, ntohl (incoming->sender),
-                 ntohl (incoming->recipient), ntohs (packed_message->type));
-#endif
-
-  if ((ntohs (incoming->header.size) < sizeof (p2p_dv_MESSAGE_Data))
-      || (ntohs (incoming->header.size) !=
-          (sizeof (p2p_dv_MESSAGE_Data) + ntohs (packed_message->size))))
+  if ( (ntohs (incoming->header.size)  < sizeof (p2p_dv_MESSAGE_Data) + sizeof 
(GNUNET_MessageHeader)) || 
+       (ntohs (incoming->header.size) != (sizeof (p2p_dv_MESSAGE_Data) + ntohs 
(packed_message->size))) )
     {
-#if DEBUG_DV_FORWARD
-      GNUNET_GE_LOG (coreAPI->ectx,
-                     GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER |
-                     GNUNET_GE_BULK,
-                     "%s: Got bad message size.  Expected at least %d, got %d, 
packed message size %d\n",
-                     &shortID, sizeof (p2p_dv_MESSAGE_Data),
-                     ntohs (incoming->header.size),
-                     ntohs (packed_message->size));
-#endif
+      GNUNET_GE_BREAK(NULL, 0);
       return GNUNET_SYSERR;
     }
-
-#if DEBUG_DV
-  message_length =
-    ntohs (incoming->header.size) - sizeof (p2p_dv_MESSAGE_Data);
-  GNUNET_GE_LOG (coreAPI->ectx,
-                 GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER |
-                 GNUNET_GE_BULK,
-                 "%s: Guessing packed message size %d, actual packed message 
size %d\n",
-                 &shortID, message_length, ntohs (packed_message->size));
-#endif
   if (stats != NULL)
     stats->change (stat_dv_received_messages, 1);
 
-  GNUNET_mutex_lock (ctx->dvMutex);
-  if (ntohl (incoming->sender) == 0)
+  GNUNET_mutex_lock (ctx.dvMutex);
+  dn = GNUNET_multi_hash_map_get (ctx.extended_neighbors,
+                                 &sender->hashPubKey);
+  sid = ntohl(incoming->sender);
+  pos = dn->referee_head;
+  while ( (NULL != pos) &&
+         (pos->referrer_id != sid))
+    pos = pos->next;
+  if (pos == NULL)
     {
-      memcpy (&original_sender, sender, sizeof (GNUNET_PeerIdentity));
+      /* unknown sender */
+      GNUNET_mutex_unlock (ctx.dvMutex);
+      if (stats != NULL)
+       stats->change (stat_dv_unknown_peer, 1);
+      return GNUNET_OK;
     }
-  else
+  original_sender = pos->identity;
+  tid = ntohl (incoming->recipient);
+  if (tid == 0)
     {
-      ret = GNUNET_SYSERR;
-      for (i = 0; i < ctx->max_table_size * 2; i++)
-        {
-          if (ntohl (incoming->sender) ==
-              ctx->neighbor_id_array[i].neighbor_id)
-            {
-              memcpy (&original_sender, &ctx->neighbor_id_array[i].identity,
-                      sizeof (GNUNET_PeerIdentity));
-              ret = GNUNET_OK;
-              break;
-            }
-        }
-      if (ret == GNUNET_SYSERR)
-        {
-          GNUNET_mutex_unlock (ctx->dvMutex);
-#if DEBUG_DV_FORWARD
-          GNUNET_hash_to_enc (&coreAPI->my_identity->hashPubKey, &encMe);
-          GNUNET_hash_to_enc (&sender->hashPubKey, &encSender);
-          GNUNET_GE_LOG (coreAPI->ectx,
-                         GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER
-                         | GNUNET_GE_BULK,
-                         "%s: Received message:\nI am:\n%s\nImmediate 
sender:\n%s\nOriginal Sender UNKNOWN\n",
-                         &shortID, (char *) &encMe, (char *) &encSender);
-
-#endif
-          if (stats != NULL)
-            stats->change (stat_dv_unknown_peer, 1);
-          return GNUNET_SYSERR;
-        }
-    }
-  GNUNET_mutex_unlock (ctx->dvMutex);
-
-  if (ntohl (incoming->recipient) == 0)
-    {
+      /* 0 == us */
+      GNUNET_mutex_unlock (ctx.dvMutex); 
       coreAPI->loopback_send (&original_sender,
                               (const char *) packed_message,
-                              ntohs (packed_message->size), GNUNET_YES, NULL);
-#if DEBUG_DV_FORWARD
-      GNUNET_hash_to_enc (&coreAPI->my_identity->hashPubKey, &encMe);
-      GNUNET_hash_to_enc (&sender->hashPubKey, &encSender);
-      GNUNET_hash_to_enc (&original_sender.hashPubKey, &encOrigin);
-      GNUNET_GE_LOG (coreAPI->ectx,
-                     GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER
-                     | GNUNET_GE_BULK,
-                     "%s: Received message for me:\nI am:\n%s\nImmediate 
sender:\n%s\nOriginal Sender:\n%s\n",
-                     &shortID, (char *) &encMe, (char *) &encSender,
-                     (char *) &encOrigin);
-#endif
+                              ntohs (packed_message->size), 
+                             GNUNET_YES, 
+                             NULL);
+      return GNUNET_OK;
     }
-  else
+
+  /* FIXME: this is the *only* per-request operation we have in DV
+     that is O(n) in relation to the number of connected peers; a
+     hash-table lookup could easily solve this (minor performance
+     issue) */
+  fdc.tid = tid;
+  fdc.dest = NULL;
+  GNUNET_CONTAINER_heap_iterate (ctx.neighbor_max_heap,
+                                &find_destination,
+                                &fdc);
+  if (fdc.dest == NULL)
     {
-      ret = forward_message (incoming, &original_sender);
       if (stats != NULL)
-        {
-          if (ret != GNUNET_SYSERR)
-            stats->change (stat_dv_forwarded_messages, 1);
-          else
-            stats->change (stat_dv_failed_forwards, 1);
-        }
+       stats->change (stat_dv_failed_forwards, 1);
+      GNUNET_mutex_unlock (ctx.dvMutex);  
+      return GNUNET_OK;
     }
-  return ret;
+  destination = fdc.dest->identity;
+  GNUNET_mutex_unlock (ctx.dvMutex); 
+  if (0 == memcmp (&destination,
+                  sender,
+                  sizeof (GNUNET_PeerIdentity)))
+    {
+      /* FIXME: create stat: routing loop-discard! */
+      return GNUNET_OK;
+    }
+  ret = send_message (&destination,
+                     &original_sender,
+                     packed_message,
+                     DV_PRIORITY,
+                     DV_DELAY);
+  if (stats != NULL)
+    {
+      if (ret != GNUNET_SYSERR)
+       stats->change (stat_dv_forwarded_messages, 1);
+      else
+       stats->change (stat_dv_failed_forwards, 1);
+    }      
+  return GNUNET_OK;
 }
 
-/*
- * Build and send a fresh message from this peer to a
- * peer in the fisheye neighborhood.  Returns GNUNET_OK
- * provided all goes well, GNUNET_NO if recipient is not
- * in the neighborhood, and GNUNET_SYSERR if some other
- * problem happens
+
+/**
+ * Build and send a fresh message from this peer to a peer in the
+ * fisheye neighborhood.  Returns GNUNET_OK provided all goes well,
+ * GNUNET_NO if recipient is not in the neighborhood, and
+ * GNUNET_SYSERR if some other problem happens
  *
- * @recipient for which peer is this message intended
- * @message message being sent
- * return cost of sent message, GNUNET_SYSERR on error
+ * @param recipient for which peer is this message intended
+ * @param message message being sent
+ * @return cost of sent message, GNUNET_SYSERR on error
  */
 int
-GNUNET_DV_send_message (const GNUNET_PeerIdentity * recipient,
-                        const GNUNET_MessageHeader * message,
-                        unsigned int importance, unsigned int maxdelay)
+GNUNET_DV_send_message (const GNUNET_PeerIdentity *recipient,
+                        const GNUNET_MessageHeader *message,
+                        unsigned int importance, 
+                       unsigned int maxdelay)
 {
   if (stats != NULL)
     stats->change (stat_dv_sent_messages, 1);
@@ -754,222 +609,159 @@
                                                      GNUNET_CronTime *
                                                      last_seen)
 {
+  struct DistantNeighbor *dn;
   unsigned int ret;
+
   ret = GNUNET_SYSERR;
-  GNUNET_mutex_lock (ctx->dvMutex);
-  if (GNUNET_YES == GNUNET_multi_hash_map_contains (ctx->extended_neighbors,
-                                                    &node->hashPubKey))
+  GNUNET_mutex_lock (ctx.dvMutex);
+  dn = GNUNET_multi_hash_map_get (ctx.extended_neighbors,
+                                 &node->hashPubKey);
+  if (dn != NULL)
     {
       ret = GNUNET_OK;
       if (bpm != NULL)
-        *bpm = 0;               /* FIXME */
-      if (last_seen != NULL)
-        *last_seen = 0;         /* FIXME */
+       {
+         coreAPI->p2p_connection_status_check (&dn->referrer->identity,
+                                               bpm,
+                                               last_seen);
+       }
+      if ( (dn->cost > 0) &&
+          (last_seen != NULL) )
+        *last_seen = dn->last_activity;
     }
-  GNUNET_mutex_unlock (ctx->dvMutex);
+  GNUNET_mutex_unlock (ctx.dvMutex);
   return ret;
 }
 
-/*
- * Adds a peer to the temporary mapping between neighbor_id's and
- * GNUNET_PeerIdentity's
- */
-static int
-addToNeighborMap (unsigned int neighbor_id,
-                  const GNUNET_PeerIdentity * identity)
-{
 
-  if (ctx->neighbor_id_loc == ctx->max_table_size * 2)
-    {
-      ctx->neighbor_id_loc = 0;
-    }
-
-  ctx->neighbor_id_array[ctx->neighbor_id_loc].neighbor_id = neighbor_id;
-  memcpy (&ctx->neighbor_id_array[ctx->neighbor_id_loc].identity, identity,
-          sizeof (GNUNET_PeerIdentity));
-  ctx->neighbor_id_loc++;
-  return GNUNET_OK;
-}
-
-
-/*
+/**
  * Handles when a peer is either added due to being newly connected
  * or having been gossiped about, also called when a cost for a neighbor
  * needs to be updated.
  *
- * @param neighbor identity of the peer whose info is being added/updated
+ * @param peer identity of the peer whose info is being added/updated
+ * @param peer_id id to use when sending to 'peer'
  * @param referrer if this is a gossiped peer, who did we hear it from?
- * @param cost the cost to this peer (the actual important part!)
- *
+ * @param cost the cost of communicating with this peer via 'referrer'
  */
-static int
-addUpdateNeighbor (const GNUNET_PeerIdentity * peer, unsigned int neighbor_id,
-                   const GNUNET_PeerIdentity * referrer, unsigned int cost)
+static void
+addUpdateNeighbor (const GNUNET_PeerIdentity *peer, 
+                  unsigned int referrer_peer_id,
+                   struct DirectNeighbor *referrer, 
+                  unsigned int cost)
 {
-  struct GNUNET_dv_neighbor *neighbor;
+  struct DistantNeighbor *neighbor;
+  struct DistantNeighbor *max;
   GNUNET_CronTime now;
-#if DEBUG_DV
-  GNUNET_EncName encPeer;
-  GNUNET_EncName encReferrer;
-  GNUNET_GE_LOG (coreAPI->ectx,
-                 GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER |
-                 GNUNET_GE_BULK, "%s: Entering addUpdateNeighbor\n",
-                 &shortID);
+  unsigned int our_id;
 
-  GNUNET_hash_to_enc (&peer->hashPubKey, &encPeer);
-  if (referrer == NULL)
-    GNUNET_GE_LOG (coreAPI->ectx,
-                   GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER |
-                   GNUNET_GE_BULK, "%s: Adding/Updating Node %s\n",
-                   &shortID, (char *) &encPeer);
-  else
-    {
-      GNUNET_hash_to_enc (&referrer->hashPubKey, &encReferrer);
-      GNUNET_GE_LOG (coreAPI->ectx,
-                     GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER |
-                     GNUNET_GE_BULK,
-                     "%s: Adding/Updating Node %s, Learned about from %s\n",
-                     &shortID, (char *) &encPeer, (char *) &encReferrer);
-    }
-#endif
   now = GNUNET_get_time ();
-  GNUNET_mutex_lock (ctx->dvMutex);
-  if (cost > ctx->fisheye_depth)
+  our_id = GNUNET_random_u32 (GNUNET_RANDOM_QUALITY_WEAK, RAND_MAX - 1) + 1;
+  GNUNET_mutex_lock (ctx.dvMutex);
+  neighbor = GNUNET_multi_hash_map_get (ctx.extended_neighbors,
+                                       &peer->hashPubKey);  
+  if (neighbor == NULL)
     {
-      /* too expensive */
-#if DEBUG_DV_MAINTAIN
-      GNUNET_GE_LOG (coreAPI->ectx,
-                     GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER |
-                     GNUNET_GE_BULK,
-                     "Node cost %d too high, not adding this peer!\n", cost);
-#endif
-      if ((GNUNET_YES ==
-           GNUNET_multi_hash_map_contains (ctx->extended_neighbors,
-                                           &peer->hashPubKey))
-          && (GNUNET_NO ==
-              GNUNET_multi_hash_map_contains (ctx->direct_neighbors,
-                                              &peer->hashPubKey)))
+      /* new neighbor! */      
+      if (cost > ctx.fisheye_depth) 
+       {
+         /* too costly */
+         GNUNET_mutex_unlock (ctx.dvMutex);
+         return;
+       }
+      if (ctx.max_table_size >=
+          GNUNET_multi_hash_map_size (ctx.extended_neighbors))
         {
-          neighbor =
-            GNUNET_multi_hash_map_get (ctx->extended_neighbors,
-                                       &peer->hashPubKey);
-          if (((neighbor->referrer == NULL) && (referrer == NULL)) ||
-              (((neighbor->referrer != NULL) && (referrer != NULL))
-               &&
-               (memcmp
-                (neighbor->referrer, referrer,
-                 sizeof (GNUNET_PeerIdentity)) == 0)))
-            {
-              delete_neighbor (neighbor);
-            }
+         /* remove most expensive entry */
+         max = GNUNET_CONTAINER_heap_peek (ctx.neighbor_max_heap);
+         if (cost > max->cost)
+           {
+             /* new entry most expensive, don't create */
+             GNUNET_mutex_unlock (ctx.dvMutex);
+             return;
+           }
+         if (max->cost > 0)
+           {
+             /* only free if this is not a direct connection;
+                we could theoretically have more direct
+                connections than DV entries allowed total! */
+             distant_neighbor_free (max);
+           }
         }
-      GNUNET_mutex_unlock (ctx->dvMutex);
-      return GNUNET_NO;
-    }
-  if (GNUNET_NO ==
-      GNUNET_multi_hash_map_contains (ctx->extended_neighbors,
-                                      &peer->hashPubKey))
-    {
-      /* new neighbor */
-      if (ctx->max_table_size <=
-          GNUNET_multi_hash_map_size (ctx->extended_neighbors))
-        {
-          /* don't care, have plenty */
-          /* FIXME: might want to consider cost here! */
-          GNUNET_mutex_unlock (ctx->dvMutex);
-          return GNUNET_OK;
-        }
-      neighbor = GNUNET_malloc (sizeof (struct GNUNET_dv_neighbor));
-      neighbor->cost = cost;
-      neighbor->last_activity = now;
-      neighbor->neighbor_id = neighbor_id;
-      memcpy (&neighbor->neighbor, peer, sizeof (GNUNET_PeerIdentity));
-      addToNeighborMap (neighbor_id, peer);
 
-      if (referrer == NULL)
-        neighbor->referrer = NULL;
-      else
-        {
-          neighbor->referrer = GNUNET_malloc (sizeof (GNUNET_PeerIdentity));
-          memcpy (neighbor->referrer, referrer, sizeof (GNUNET_PeerIdentity));
-        }
-
-      GNUNET_multi_hash_map_put (ctx->extended_neighbors,
-                                 &peer->hashPubKey, neighbor,
-                                 GNUNET_MultiHashMapOption_REPLACE);
-
-      neighbor->max_loc = GNUNET_CONTAINER_heap_insert 
(ctx->neighbor_max_heap, neighbor, cost);
-      neighbor->min_loc = GNUNET_CONTAINER_heap_insert 
(ctx->neighbor_min_heap, neighbor, cost);
+      neighbor = GNUNET_malloc (sizeof (struct DistantNeighbor));
+      GNUNET_DLL_insert (referrer->referee_head,
+                        referrer->referee_tail,
+                        neighbor);
+      neighbor->max_loc = GNUNET_CONTAINER_heap_insert (ctx.neighbor_max_heap, 
+                                                       neighbor,
+                                                       cost);
+      neighbor->min_loc = GNUNET_CONTAINER_heap_insert (ctx.neighbor_min_heap,
+                                                       neighbor,
+                                                       cost);
+      neighbor->referrer = referrer;      
+      memcpy (&neighbor->identity, peer, sizeof (GNUNET_PeerIdentity));
+      neighbor->last_activity = now;
+      neighbor->cost = cost;
+      neighbor->referrer_id = referrer_peer_id;
+      neighbor->our_id = our_id;
+      neighbor->hidden = (cost == 0) ? (GNUNET_random_u32 
(GNUNET_RANDOM_QUALITY_WEAK,
+                                                          4) == 0) : 
GNUNET_NO;      
+      GNUNET_multi_hash_map_put (ctx.extended_neighbors,
+                                 &peer->hashPubKey, 
+                                neighbor,
+                                 GNUNET_MultiHashMapOption_UNIQUE_ONLY);
       if (stats != NULL)
         stats->change (stat_dv_total_peers, 1);
-      GNUNET_mutex_unlock (ctx->dvMutex);
-      return GNUNET_OK;
+      GNUNET_mutex_unlock (ctx.dvMutex);
+      return;
     }
-  neighbor =
-    GNUNET_multi_hash_map_get (ctx->extended_neighbors, &peer->hashPubKey);
 
-  if ((((neighbor->referrer == NULL) && (referrer == NULL)) ||
-       (((neighbor->referrer != NULL) && (referrer != NULL))
-        &&
-        (memcmp
-         (neighbor->referrer, referrer, sizeof (GNUNET_PeerIdentity)) == 0))))
+  /* update existing entry! */
+  if (neighbor->referrer == referrer)
     {
-      /* same path as the one we already have */
+      /* same referrer, cost change! */
+      GNUNET_CONTAINER_heap_update_cost (ctx.neighbor_max_heap, 
+                                        neighbor->max_loc,
+                                        cost);
+      GNUNET_CONTAINER_heap_update_cost (ctx.neighbor_min_heap,
+                                        neighbor->min_loc,
+                                        cost);
       neighbor->last_activity = now;
-      if (neighbor->cost != cost)
-        {
-          /* update cost */
-          neighbor->cost = cost;
-          GNUNET_CONTAINER_heap_update_cost (ctx->neighbor_max_heap, 
-                                            neighbor->max_loc,
-                                             cost);
-          GNUNET_CONTAINER_heap_update_cost (ctx->neighbor_min_heap,
-                                            neighbor->min_loc,
-                                             cost);
-        }
-      GNUNET_mutex_unlock (ctx->dvMutex);
-      return GNUNET_OK;
+      neighbor->cost = cost;
+      GNUNET_mutex_unlock (ctx.dvMutex);
+      return;      
     }
+
   if (neighbor->cost <= cost)
     {
-      /* alternative, costlier path found, ignore */
-      GNUNET_mutex_unlock (ctx->dvMutex);
-      return GNUNET_OK;
+      /* more costly than existing alternative */
+      GNUNET_mutex_unlock (ctx.dvMutex);
+      return;
     }
-  /* alternative, cheaper path found, replace */
-  delete_neighbor (neighbor);
-  neighbor = GNUNET_malloc (sizeof (struct GNUNET_dv_neighbor));
-  neighbor->cost = cost;
-  neighbor->last_activity = now;
-  neighbor->neighbor_id = neighbor_id;
-  memcpy (&neighbor->neighbor, peer, sizeof (GNUNET_PeerIdentity));
-  addToNeighborMap (neighbor_id, peer);
 
-  if (referrer == NULL)
-    neighbor->referrer = NULL;
-  else
-    {
-      neighbor->referrer = GNUNET_malloc (sizeof (GNUNET_PeerIdentity));
-      memcpy (neighbor->referrer, referrer, sizeof (GNUNET_PeerIdentity));
-    }
-
-  GNUNET_multi_hash_map_put (ctx->extended_neighbors,
-                             &peer->hashPubKey, neighbor,
-                             GNUNET_MultiHashMapOption_REPLACE);
-
-  neighbor->max_loc = GNUNET_CONTAINER_heap_insert (ctx->neighbor_max_heap, 
neighbor, cost);
-  neighbor->min_loc = GNUNET_CONTAINER_heap_insert (ctx->neighbor_min_heap, 
neighbor, cost);
-#if DEBUG_DV
-  GNUNET_GE_LOG (coreAPI->ectx,
-                 GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER |
-                 GNUNET_GE_BULK, "%s: Exiting addUpdateNeighbor\n", &shortID);
-#endif
-  GNUNET_mutex_unlock (ctx->dvMutex);
-  return GNUNET_OK;
+  /* better path! */
+  GNUNET_DLL_remove (neighbor->referrer->referee_head,
+                    neighbor->referrer->referee_tail,
+                    neighbor);
+  neighbor->referrer = referrer;
+  GNUNET_DLL_insert (referrer->referee_head,
+                    referrer->referee_tail,
+                    neighbor);
+  GNUNET_CONTAINER_heap_update_cost (ctx.neighbor_max_heap, 
+                                    neighbor->max_loc,
+                                    cost);
+  GNUNET_CONTAINER_heap_update_cost (ctx.neighbor_min_heap,
+                                    neighbor->min_loc,
+                                    cost);
+  neighbor->referrer_id = referrer_peer_id;
+  neighbor->last_activity = now;
+  neighbor->cost = cost;
+  GNUNET_mutex_unlock (ctx.dvMutex);
 }
 
 
-/*
+/**
  * Handles a gossip message from another peer.  Basically
  * just check the message size, cast to the correct type
  * and call addUpdateNeighbor to do the real work.
@@ -978,12 +770,8 @@
 p2pHandleDVNeighborMessage (const GNUNET_PeerIdentity * sender,
                             const GNUNET_MessageHeader * message)
 {
-  int ret = GNUNET_OK;
   const p2p_dv_MESSAGE_NeighborInfo *nmsg;
-#if DEBUG_DV
-  GNUNET_EncName from;
-  GNUNET_EncName about;
-#endif
+  struct DirectNeighbor *neighbor;
 
   if (ntohs (message->size) < sizeof (p2p_dv_MESSAGE_NeighborInfo))
     {
@@ -991,295 +779,113 @@
       return GNUNET_SYSERR;     /* invalid message */
     }
   nmsg = (const p2p_dv_MESSAGE_NeighborInfo *) message;
-
-  ret =
-    addUpdateNeighbor (&nmsg->neighbor, ntohl (nmsg->neighbor_id), sender,
-                       ntohl (nmsg->cost) + 1);
   if (stats != NULL)
     stats->change (stat_dv_received_gossips, 1);
+  neighbor = GNUNET_multi_hash_map_get (ctx.direct_neighbors,
+                                       &sender->hashPubKey);
+  GNUNET_GE_ASSERT (NULL, neighbor != NULL);
+  addUpdateNeighbor (&nmsg->neighbor, 
+                    ntohl (nmsg->neighbor_id), 
+                    neighbor,
+                    ntohl (nmsg->cost) + 1);
 
-#if DEBUG_DV_MAINTAIN
-  if (GNUNET_OK != ret)
-    GNUNET_GE_LOG (coreAPI->ectx,
-                   GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER,
-                   _("%s: Problem adding/updating neighbor in `%s'\n"),
-                   &shortID, "dv");
-#endif
-
-#if DEBUG_DV
-  GNUNET_hash_to_enc (&sender->hashPubKey, &from);
-  GNUNET_hash_to_enc (&nmsg->neighbor.hashPubKey, &about);
-  GNUNET_GE_LOG (coreAPI->ectx,
-                 GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER |
-                 GNUNET_GE_BULK,
-                 "%s: Received info about peer %s from directly connected peer 
%s\n",
-                 &shortID, (char *) &about, (char *) &from);
-#endif
-  return ret;
+  return GNUNET_OK;
 }
 
-/*
+
+/**
  * Handles a peer connect notification, indicating a peer should
  * be added to the direct neighbor table.
  *
- * @param peer - ident of the connected peer
- * @param unused - unused closure arg
+ * @param peer identity of the connected peer
+ * @param unused unused closure arg
  */
 static void
-peer_connect_handler (const GNUNET_PeerIdentity * peer, void *unused)
+peer_connect_handler (const GNUNET_PeerIdentity * peer,
+                     void *unused)
 {
-#if DEBUG_DV
-  GNUNET_GE_LOG (coreAPI->ectx,
-                 GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER |
-                 GNUNET_GE_BULK, "%s: Entering peer_connect_handler:\n",
-                 &shortID);
+  struct DirectNeighbor *neighbor;
 
-#endif
-  struct GNUNET_dv_neighbor *neighbor;
-  unsigned int cost = GNUNET_DV_LEAST_COST;
-
-  GNUNET_mutex_lock (ctx->dvMutex);
-  if (GNUNET_YES !=
-      GNUNET_multi_hash_map_contains (ctx->direct_neighbors,
-                                      &peer->hashPubKey))
-    {
-      neighbor = GNUNET_malloc (sizeof (struct GNUNET_dv_neighbor));
-      neighbor->cost = cost;
-      neighbor->last_activity = GNUNET_get_time ();
-      neighbor->neighbor_id =
-        GNUNET_random_u32 (GNUNET_RANDOM_QUALITY_WEAK, RAND_MAX - 1) + 1;
-      memcpy (&neighbor->neighbor, peer, sizeof (GNUNET_PeerIdentity));
-      neighbor->referrer = NULL;
-      GNUNET_multi_hash_map_put (ctx->direct_neighbors, &peer->hashPubKey,
-                                 neighbor, GNUNET_MultiHashMapOption_REPLACE);
-    }
-  else
-    {
-      neighbor =
-        GNUNET_multi_hash_map_get (ctx->direct_neighbors, &peer->hashPubKey);
-
-      if (neighbor->cost != cost)
-        {
-          neighbor->last_activity = GNUNET_get_time ();
-          neighbor->cost = cost;
-        }
-
-    }
-  GNUNET_mutex_unlock (ctx->dvMutex);
-  addUpdateNeighbor (peer, neighbor->neighbor_id, NULL, cost);
+  GNUNET_mutex_lock (ctx.dvMutex);
+  neighbor = GNUNET_malloc (sizeof (struct DirectNeighbor));
+  memcpy (&neighbor->identity, peer, sizeof (GNUNET_PeerIdentity));
+  GNUNET_multi_hash_map_put (ctx.direct_neighbors, 
+                            &peer->hashPubKey,
+                            neighbor, 
+                            GNUNET_MultiHashMapOption_UNIQUE);
+  GNUNET_mutex_unlock (ctx.dvMutex);
+  addUpdateNeighbor (peer, 
+                    0,
+                    neighbor,
+                    0);
 }
 
 
-/*
- * A callback for deleting matching nodes from heaps...
- *
- * @param element a neighbor - the peer we may delete
- * @param root the root of the heap
- * @param cls the peer identity to compare neighbor's identity to
- */
-static int
-delete_callback (void *cls,
-                struct GNUNET_CONTAINER_HeapNode *node,
-                void *element,
-                GNUNET_CONTAINER_HeapCostType cost)
-{
-  struct GNUNET_dv_neighbor *neighbor = element;
-  GNUNET_PeerIdentity *toMatch = cls;
-#if DEBUG_DV
-  GNUNET_EncName encNeighbor;
-  GNUNET_EncName encReferrer;
-  GNUNET_EncName encToMatch;
-
-  GNUNET_hash_to_enc (&neighbor->neighbor->hashPubKey, &encNeighbor);
-  GNUNET_hash_to_enc (&toMatch->hashPubKey, &encToMatch);
-  if (neighbor->referrer != NULL)
-    {
-      GNUNET_hash_to_enc (&neighbor->referrer->hashPubKey, &encReferrer);
-      fprintf (stderr, "Checking for node\n%s to match\n%s or\n%s\n",
-               (char *) &encToMatch, (char *) &encNeighbor,
-               (char *) &encReferrer);
-    }
-  fprintf (stderr, "Checking for node %s to match %s\n", (char *) &encToMatch,
-           (char *) &encNeighbor);
-#endif
-
-  if ( ( (neighbor->referrer == NULL) &&
-        (0 == memcmp (&neighbor->neighbor,
-                      toMatch,
-                      sizeof (GNUNET_PeerIdentity))) ) ||
-       ( (neighbor->referrer != NULL) &&
-        (0 == memcmp (neighbor->referrer, toMatch,
-                      sizeof
-                      (GNUNET_PeerIdentity))) ) )
-    {
-      /* FIXME: we might want to have some way to notify the rest of
-         our DV-neigborhood about this disconnect as well... */
-      delete_neighbor (neighbor);
-      /* we must not continue iterating at this point since
-         'delete_neighbor' modified the tree and hence internal
-         invariants of the iterator were likely broken!
-         Besides, each neighbor should only appear once anyway... */
-
-      /* Why should each neighbor appear only once??? We are talking about
-       * deleting any nodes that the disconnected node has referred to us!
-       * While the disconnected node itself appears only once, those it has
-       * told us about may abound...  If we don't remove them, we are going
-       * to try sending data to peers whose direct connection is gone.
-       *
-       * Also, the way that the heap removal works (for a min or max heap)
-       * the iterator doesn't move because the last node is switched with
-       * the node being removed, so we don't break the iteration unless
-       * the heap is empty but then we still should be okay (we just stop
-       * iterating).
-       */
-      return GNUNET_NO;
-    }
-  return GNUNET_YES;
-}
-
-/*
+/**
  * Handles the receipt of a peer disconnect notification, removing
  * the direct neighbor from the direct list and any referenced
  * neighbors as well.
  *
- * @param peer - the peer that has disconnected from us
+ * @param peer the peer that has disconnected from us
  */
 static void
-peer_disconnect_handler (const GNUNET_PeerIdentity * peer, void *unused)
+peer_disconnect_handler (const GNUNET_PeerIdentity * peer,
+                        void *unused)
 {
-  struct GNUNET_dv_neighbor *neighbor;
+  struct DirectNeighbor *neighbor;
 
-#if DEBUG_DV
-  GNUNET_EncName myself;
-  GNUNET_GE_LOG (coreAPI->ectx,
-                 GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER |
-                 GNUNET_GE_BULK, "%s: Entering peer_disconnect_handler\n",
-                 &shortID);
-  GNUNET_hash_to_enc (&peer->hashPubKey, &myself);
-  GNUNET_GE_LOG (coreAPI->ectx,
-                 GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER |
-                 GNUNET_GE_BULK, "%s: disconnected peer: %s\n", &shortID,
-                 (char *) &myself);
-#endif
-
-  GNUNET_mutex_lock (ctx->dvMutex);
-
-  if (GNUNET_YES ==
-      GNUNET_multi_hash_map_contains (ctx->direct_neighbors,
-                                      &peer->hashPubKey))
-    {
-      neighbor =
-        GNUNET_multi_hash_map_get (ctx->direct_neighbors, &peer->hashPubKey);
-      if (neighbor != NULL)
-        {
-          GNUNET_multi_hash_map_remove_all (ctx->direct_neighbors,
-                                            &peer->hashPubKey);
-          GNUNET_CONTAINER_heap_iterate (ctx->neighbor_max_heap,
-                                         &delete_callback, (void *) peer);
-          /* delete_callback will free 'neighbor' (and members) */
-
-          /* no, it won't.  It will free the neighbor and members contained
-           * in the ctx->extended_neighbors set but not those in the
-           * ctx->direct_neighbors set.
-           */
-        }
-    }
-  GNUNET_mutex_unlock (ctx->dvMutex);
-#if DEBUG_DV
-  GNUNET_GE_LOG (coreAPI->ectx,
-                 GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER |
-                 GNUNET_GE_BULK, "%s: Exiting peer_disconnect_handler\n",
-                 &shortID);
-#endif
-  return;
+  GNUNET_mutex_lock (ctx.dvMutex);
+  neighbor =
+    GNUNET_multi_hash_map_get (ctx.direct_neighbors, &peer->hashPubKey);
+  GNUNET_GE_ASSERT (NULL, neighbor != NULL);
+  while (NULL != (referee = neighbor->referees))
+    distant_neighbor_free (referee);
+  GNUNET_multi_hash_map_remove (ctx.direct_neighbors,
+                               &peer->hashPubKey,
+                               neighbor);
+  GNUNET_free (neighbor);
+  GNUNET_mutex_unlock (ctx.dvMutex);
+  update_stats ();
 }
 
-/*
- * Chooses a neighbor at random to gossip peer information
- * to
- */
-static struct GNUNET_dv_neighbor *
-chooseToNeighbor ()
-{
-  if (GNUNET_multi_hash_map_size (ctx->direct_neighbors) == 0)
-    return NULL;
 
-  return (struct GNUNET_dv_neighbor *)
-    GNUNET_multi_hash_map_get_random (ctx->direct_neighbors);
-}
 
-/*
- * Chooses a neighbor to send information about
- * by walking through the neighbor heap
+/**
+ * Method which changes how often peer sends neighbor information to
+ * other peers.  Basically, if we know how many peers we have and want
+ * to gossip all of them to all of our direct neighbors we will need
+ * to send them such that they will all reach their destinations
+ * within the timeout frequency.  We assume all peers share our
+ * timeout frequency so it's a simple calculation.  May need
+ * revisiting if we want to specify a maximum or minimum value for
+ * this interval.
  */
-static struct GNUNET_dv_neighbor *
-chooseAboutNeighbor ()
-{
-  unsigned int heap_size;
-  heap_size = GNUNET_CONTAINER_heap_get_size (ctx->neighbor_min_heap);
-  if (heap_size == 0)
-    return NULL;
-
-#if DEBUG_DV
-  GNUNET_GE_LOG (coreAPI->ectx,
-                 GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER |
-                 GNUNET_GE_BULK, "%s: Min heap size %d\n",
-                 &shortID, heap_size);
-#endif
-
-  return GNUNET_CONTAINER_heap_walk_get_next (ctx->neighbor_min_heap);
-
-}
-
-/*
- * Method which changes how often peer sends neighbor information
- * to other peers.  Basically, if we know how many peers we have
- * and want to gossip all of them to all of our direct neighbors
- * we will need to send them such that they will all reach their
- * destinations within the timeout frequency.  We assume all
- * peers share our timeout frequency so it's a simple calculation.
- * May need revisiting if we want to specify a maximum or minimum
- * value for this interval.
- */
 static void
 updateSendInterval ()
 {
   unsigned int direct_neighbors;
   unsigned int total_neighbors;
   unsigned int total_messages;
-#if DEBUG_DV
-  unsigned int old_interval;
-#endif
-  direct_neighbors = GNUNET_multi_hash_map_size (ctx->direct_neighbors);
-  total_neighbors = GNUNET_multi_hash_map_size (ctx->extended_neighbors);
 
+  direct_neighbors = GNUNET_multi_hash_map_size (ctx.direct_neighbors);
+  total_neighbors = GNUNET_multi_hash_map_size (ctx.extended_neighbors);
   if (direct_neighbors == 0)
-    return;
-
+    {
+      ctx.send_interval = GNUNET_DV_DEFAULT_SEND_INTERVAL;
+      return;
+    }
   total_messages = direct_neighbors * total_neighbors;
-#if DEBUG_DV
-  old_interval = ctx->send_interval;
-#endif
-
-  ctx->send_interval =
+  ctx.send_interval =
     (unsigned int) ((GNUNET_DV_PEER_EXPIRATION_TIME / total_messages) / 2);
-  if (ctx->send_interval > GNUNET_DV_MAX_SEND_INTERVAL)
-    ctx->send_interval = GNUNET_DV_MAX_SEND_INTERVAL;
-
-#if DEBUG_DV
-  GNUNET_GE_LOG (coreAPI->ectx,
-                 GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER
-                 | GNUNET_GE_BULK,
-                 "%s: Updated send_interval. Was %llu, now is %llu\n",
-                 &shortID, old_interval, ctx->send_interval);
-#endif
+  if (ctx.send_interval > GNUNET_DV_MAX_SEND_INTERVAL)
+    ctx.send_interval = GNUNET_DV_MAX_SEND_INTERVAL;
 }
 
-/*
- * Thread which chooses a peer to gossip about and
- * a peer to gossip to, then constructs the message
- * and sends it out.  Will run until done_module_dv
- * is called.
+
+/**
+ * Thread which chooses a peer to gossip about and a peer to gossip
+ * to, then constructs the message and sends it out.  Will run until
+ * done_module_dv is called.
  */
 static void *
 neighbor_send_thread (void *rcls)
@@ -1292,27 +898,34 @@
   GNUNET_EncName encPeerAbout;
   GNUNET_EncName encPeerTo;
 #endif
-  struct GNUNET_dv_neighbor *about;
-  struct GNUNET_dv_neighbor *to;
+  struct DistantNeighbor *about;
+  struct DirectNeighbor *to;
   unsigned int count;
   p2p_dv_MESSAGE_NeighborInfo message;
 
   message.header.size = htons (sizeof (p2p_dv_MESSAGE_NeighborInfo));
   message.header.type = htons (GNUNET_P2P_PROTO_DV_NEIGHBOR_MESSAGE);
   count = 0;
-  while (!ctx->closing)
+  while (!ctx.closing)
     {
-      if (0 == (++count % 20))
+      GNUNET_thread_sleep (ctx.send_interval);
+      if (ctx.closing)
+       break;
+      if (0 == (count++ % 20))
         updateSendInterval ();
 
-      GNUNET_mutex_lock (ctx->dvMutex);
-      about = chooseAboutNeighbor ();
-      to = chooseToNeighbor ();
-
-      if ((about != NULL) && (to != NULL)
-          && (memcmp (&about->neighbor, 
-                     &to->neighbor, sizeof (GNUNET_HashCode))
-              != 0))
+      GNUNET_mutex_lock (ctx.dvMutex);
+      about = GNUNET_CONTAINER_heap_walk_get_next (ctx.neighbor_min_heap);
+      to = GNUNET_multi_hash_map_get_random (ctx.direct_neighbors);
+       
+      if ( (about != NULL) && 
+          (to != about->referrer /* split horizon */) &&
+#if SUPPORT_HIDING
+          (about->hidden == GNUNET_NO) &&
+#endif
+          (to != NULL) &&
+          (0 != memcmp (&about->identifier, 
+                        &to->identifier, sizeof (PeerIdentity))) )
         {
 #if DEBUG_DV
           GNUNET_hash_to_enc (&about->neighbor->hashPubKey, &encPeerAbout);
@@ -1321,7 +934,8 @@
                          GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER
                          | GNUNET_GE_BULK,
                          "%s: Sending info about peer %s to directly connected 
peer %s\n",
-                         &shortID, (char *) &encPeerAbout,
+                         &shortID, 
+                        (char *) &encPeerAbout,
                          (char *) &encPeerTo);
 #endif
           message.cost = htonl (about->cost);
@@ -1329,19 +943,18 @@
           memcpy (&message.neighbor, 
                  &about->neighbor,
                   sizeof (GNUNET_PeerIdentity));
-          coreAPI->ciphertext_send (&to->neighbor, &message.header,
+          coreAPI->ciphertext_send (&to->identity, &message.header,
                                     GNUNET_DV_DHT_GOSSIP_PRIORITY,
-                                    ctx->send_interval);
+                                    ctx.send_interval);
           if (stats != NULL)
             stats->change (stat_dv_sent_gossips, 1);
         }
-      GNUNET_mutex_unlock (ctx->dvMutex);
-      GNUNET_thread_sleep (ctx->send_interval);
+      GNUNET_mutex_unlock (ctx.dvMutex);
     }
   return NULL;
 }
 
-/*
+/**
  * Initializes and provides the fisheye DV service
  *
  * @param capi the core API
@@ -1350,7 +963,6 @@
 GNUNET_DV_ServiceAPI *
 provide_module_dv (GNUNET_CoreAPIForPlugins * capi)
 {
-  int ok = GNUNET_OK;
   unsigned long long max_hosts;
   GNUNET_EncName encMe;
   static GNUNET_DV_ServiceAPI api;
@@ -1358,8 +970,7 @@
 
   api.dv_send = &GNUNET_DV_send_message;
   api.dv_connections_iterate = &GNUNET_DV_connection_iterate_peers;
-  api.p2p_connection_status_check =
-    &GNUNET_DV_connection_get_bandwidth_assigned_to_peer;
+  api.p2p_connection_status_check = 
&GNUNET_DV_connection_get_bandwidth_assigned_to_peer;
   api.have_peer = &GNUNET_DV_have_peer;
 
   stats = capi->service_request ("stats");
@@ -1383,13 +994,12 @@
       stat_dv_unknown_peer =
         stats->create (gettext_noop ("# dv messages of unknown peers"));
     }
+  memset (&ctx, 0, sizeof(ctx));
+  ctx.neighbor_min_heap = GNUNET_CONTAINER_heap_create 
(GNUNET_CONTAINER_HEAP_ORDER_MIN);
+  ctx.neighbor_max_heap = GNUNET_CONTAINER_heap_create 
(GNUNET_CONTAINER_HEAP_ORDER_MAX);
+  ctx.send_interval = GNUNET_DV_DEFAULT_SEND_INTERVAL;
+  ctx.dvMutex = capi->global_lock_get ();
 
-  ctx = GNUNET_malloc (sizeof (struct GNUNET_DV_Context));
-  ctx->neighbor_min_heap = GNUNET_CONTAINER_heap_create 
(GNUNET_CONTAINER_HEAP_ORDER_MIN);
-  ctx->neighbor_max_heap = GNUNET_CONTAINER_heap_create 
(GNUNET_CONTAINER_HEAP_ORDER_MAX);
-  ctx->send_interval = GNUNET_DV_DEFAULT_SEND_INTERVAL;
-  ctx->dvMutex = capi->global_lock_get ();
-
   coreAPI = capi;
   GNUNET_hash_to_enc (&coreAPI->my_identity->hashPubKey, &encMe);
   strncpy ((char *) &shortID, (char *) &encMe, 4);
@@ -1406,23 +1016,12 @@
   GNUNET_GC_get_configuration_value_number (coreAPI->cfg,
                                             "DV",
                                             "FISHEYEDEPTH",
-                                            0, -1, 3, &ctx->fisheye_depth);
+                                            0, -1, 3, &ctx.fisheye_depth);
 
   GNUNET_GC_get_configuration_value_number (coreAPI->cfg,
                                             "DV",
                                             "TABLESIZE",
-                                            0, -1, 100, &ctx->max_table_size);
-
-  ctx->neighbor_id_array =
-    GNUNET_malloc (sizeof (struct NeighborID) * ctx->max_table_size * 2);
-  for (i = 0; i < ctx->max_table_size * 2; i++)
-    {
-      ctx->neighbor_id_array[i].neighbor_id = 0;
-      memset (&ctx->neighbor_id_array[i].identity, 0,
-              sizeof (GNUNET_PeerIdentity));
-    }
-  ctx->neighbor_id_loc = 0;
-
+                                            0, -1, 100, &ctx.max_table_size);
   GNUNET_GC_get_configuration_value_number (coreAPI->cfg,
                                             "gnunetd", "connection-max-hosts",
                                             1, -1, 50, &max_hosts);
@@ -1432,55 +1031,64 @@
                                                                    capi->ectx,
                                                                    "ABOUT",
                                                                    "dv",
-                                                                   _
-                                                                   ("enables 
distance vector type routing (wip)")));
+                                                                   _("enables 
distance vector routing")));
 
-
-  ctx->direct_neighbors = GNUNET_multi_hash_map_create (max_hosts);
-  if (ctx->direct_neighbors == NULL)
-    {
-      ok = GNUNET_SYSERR;
-    }
-
-  ctx->extended_neighbors =
-    GNUNET_multi_hash_map_create (ctx->max_table_size * 3);
-  if (ctx->extended_neighbors == NULL)
-    {
-      ok = GNUNET_SYSERR;
-    }
-
-  if (GNUNET_SYSERR ==
-      coreAPI->peer_disconnect_notification_register
-      (&peer_disconnect_handler, NULL))
-    ok = GNUNET_SYSERR;
-
-  if (GNUNET_SYSERR ==
-      coreAPI->peer_connect_notification_register (&peer_connect_handler,
-                                                   NULL))
-    ok = GNUNET_SYSERR;
-
-  if (GNUNET_SYSERR ==
-      coreAPI->p2p_ciphertext_handler_register
-      (GNUNET_P2P_PROTO_DV_NEIGHBOR_MESSAGE, &p2pHandleDVNeighborMessage))
-    ok = GNUNET_SYSERR;
-
-  if (GNUNET_SYSERR ==
-      coreAPI->p2p_ciphertext_handler_register
-      (GNUNET_P2P_PROTO_DV_DATA_MESSAGE, &p2pHandleDVDataMessage))
-    ok = GNUNET_SYSERR;
-
-  /* FIXME: do something with 'ok' */
+  ctx.direct_neighbors = GNUNET_multi_hash_map_create (max_hosts);
+  ctx.extended_neighbors =
+    GNUNET_multi_hash_map_create (ctx.max_table_size * 3);
+  coreAPI->peer_disconnect_notification_register
+    (&peer_disconnect_handler, NULL);
+  coreAPI->peer_connect_notification_register (&peer_connect_handler,
+                                              NULL);
+  coreAPI->p2p_ciphertext_handler_register
+    (GNUNET_P2P_PROTO_DV_NEIGHBOR_MESSAGE, &p2pHandleDVNeighborMessage);
+  coreAPI->p2p_ciphertext_handler_register
+    (GNUNET_P2P_PROTO_DV_DATA_MESSAGE, &p2pHandleDVDataMessage);
   sendingThread =
     GNUNET_thread_create (&neighbor_send_thread, &coreAPI, 1024 * 1);
-
   GNUNET_cron_add_job (coreAPI->cron, &maintain_dv_job,
                        GNUNET_DV_MAINTAIN_FREQUENCY,
                        GNUNET_DV_MAINTAIN_FREQUENCY, NULL);
-
   return &api;
 }
 
-/*
+
+/**
+ * Deletes a distant neighbor from the max and min heaps and from the
+ * extended neighbor hash map.
+ */
+static int
+distant_neighbor_free_iterator (const GNUNET_HashCode *key,
+                               void *value,
+                               void *cls)
+{
+  
+  struct DistantNeighbor *neighbor = value;
+  distant_neighbor_free (neighbor);
+  return GNUNET_YES;
+}
+
+
+/**
+ * Deletes a direct neighbor from the min heap and from the
+ * direct neighbor hash map.
+ */
+static void
+direct_neighbor_free_iterator (const GNUNET_HashCode * key,
+                              void *value, 
+                              void *cls)
+{
+  struct DirectNeighbor * neighbor = value;
+  GNUNET_GE_ASSERT (NULL, neighbor->referee_head == NULL);
+  GNUNET_GE_ASSERT (NULL, neighbor->referee_tail == NULL);
+  GNUNET_multi_hash_map_remove (ctx.direct_neighbors,
+                               key);
+  GNUNET_free (neighbor);
+  return GNUNET_YES;
+}
+
+
+/**
  * Shuts down and cleans up the DV module
  */
 void
@@ -1488,26 +1096,27 @@
 {
   void *unused;
 
-  ctx->closing = 1;
+  ctx.closing = 1;
   GNUNET_thread_stop_sleep (sendingThread);
   GNUNET_thread_join (sendingThread, &unused);
 
   coreAPI->p2p_ciphertext_handler_unregister
     (GNUNET_P2P_PROTO_DV_NEIGHBOR_MESSAGE, &p2pHandleDVNeighborMessage);
-
+  coreAPI->p2p_ciphertext_handler_unregister
+    (GNUNET_P2P_PROTO_DV_DATA_MESSAGE, &p2pHandleDVDataMessage);
   coreAPI->peer_disconnect_notification_unregister (&peer_disconnect_handler,
                                                     NULL);
-  coreAPI->peer_disconnect_notification_unregister (&peer_connect_handler,
-                                                    NULL);
+  coreAPI->peer_connect_notification_unregister (&peer_connect_handler,
+                                                NULL);
+  update_stats ();
   GNUNET_cron_del_job (coreAPI->cron, &maintain_dv_job,
                        GNUNET_DV_MAINTAIN_FREQUENCY, NULL);
-  GNUNET_multi_hash_map_iterate (ctx->direct_neighbors, &free_neighbor, NULL);
-  GNUNET_multi_hash_map_iterate (ctx->extended_neighbors, &free_neighbor, 
NULL);
-  GNUNET_multi_hash_map_destroy (ctx->direct_neighbors);
-  GNUNET_multi_hash_map_destroy (ctx->extended_neighbors);
-  GNUNET_CONTAINER_heap_destroy (ctx->neighbor_max_heap);
-  GNUNET_CONTAINER_heap_destroy (ctx->neighbor_min_heap);
-  GNUNET_free (ctx->neighbor_id_array);
+  GNUNET_multi_hash_map_iterate (ctx.extended_neighbors, 
&distant_neighbor_free_iterator, NULL);
+  GNUNET_multi_hash_map_iterate (ctx.direct_neighbors, 
&direct_neighbor_free_iterator, NULL);
+  GNUNET_multi_hash_map_destroy (ctx.extended_neighbors);
+  GNUNET_multi_hash_map_destroy (ctx.direct_neighbors);
+  GNUNET_CONTAINER_heap_destroy (ctx.neighbor_max_heap);
+  GNUNET_CONTAINER_heap_destroy (ctx.neighbor_min_heap);
   coreAPI->service_release (stats);
   stats = NULL;
   coreAPI = NULL;

Modified: GNUnet/src/include/dv.h
===================================================================
--- GNUnet/src/include/dv.h     2009-12-23 16:21:18 UTC (rev 9873)
+++ GNUnet/src/include/dv.h     2009-12-23 18:06:53 UTC (rev 9874)
@@ -70,10 +70,10 @@
    */
   GNUNET_PeerIdentity neighbor;
 
-  /*
+  /**
    * Neighbor ID to use when sending to this peer
    */
-  unsigned int neighbor_id;
+  unsigned int neighbor_id GNUNET_PACKED;
 
 } p2p_dv_MESSAGE_NeighborInfo;
 
@@ -84,25 +84,19 @@
 {
   GNUNET_MessageHeader header;
 
-  /**
-   * Identity of peer that sent the message
 
-  GNUNET_PeerIdentity sender GNUNET_PACKED;
-  */
   /**
-   * Identity of neighbor this message is going to
-
-  GNUNET_PeerIdentity recipient GNUNET_PACKED;
+   * Identity of peer that ultimately sent the message.
+   * Should be looked up in the set of 'neighbor_id's of
+   * the referring peer.
    */
-
-  /**
-   * Identity of peer that sent the message
-   */
   unsigned int sender GNUNET_PACKED;
 
   /**
-   * Identity of neighbor this message is going to
-  */
+   * Identity of neighbor this message is going to.  Should
+   * be looked up in the set of our own identifiers for
+   * neighbors!
+   */
   unsigned int recipient GNUNET_PACKED;
 
 } p2p_dv_MESSAGE_Data;





reply via email to

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