retry faster
[oweals/gnunet.git] / src / topology / gnunet-daemon-topology.c
index 789efcd6e835d986c31e6ab51c7124908cd70324..08b1ba1c3c0effb852fa29cbd34b8880afc645ca 100644 (file)
@@ -4,7 +4,7 @@
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
 
      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
+     by the Free Software Foundation; either version 3, or (at your
      option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
      option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
@@ -26,6 +26,7 @@
 
 #include <stdlib.h>
 #include "platform.h"
 
 #include <stdlib.h>
 #include "platform.h"
+#include "gnunet_constants.h"
 #include "gnunet_core_service.h"
 #include "gnunet_protocols.h"
 #include "gnunet_peerinfo_service.h"
 #include "gnunet_core_service.h"
 #include "gnunet_protocols.h"
 #include "gnunet_peerinfo_service.h"
  * For how long do we blacklist a peer after a failed connection
  * attempt?
  */
  * For how long do we blacklist a peer after a failed connection
  * attempt?
  */
-#define BLACKLIST_AFTER_ATTEMPT GNUNET_TIME_UNIT_HOURS
+#define GREYLIST_AFTER_ATTEMPT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
 
 /**
  * For how long do we blacklist a friend after a failed connection
  * attempt?
  */
 
 /**
  * For how long do we blacklist a friend after a failed connection
  * attempt?
  */
-#define BLACKLIST_AFTER_ATTEMPT_FRIEND GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
+#define GREYLIST_AFTER_ATTEMPT_FRIEND GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 2)
+
+/**
+ * For how long do we blacklist anyone under any cirumstances after a failed connection
+ * attempt?
+ */
+#define GREYLIST_AFTER_ATTEMPT_MIN GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
+
+/**
+ * For how long do we blacklist anyone under any cirumstances after a failed connection
+ * attempt?
+ */
+#define GREYLIST_AFTER_ATTEMPT_MAX GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
 
 /**
  * How often do we at most advertise any HELLO to a peer?
 
 /**
  * How often do we at most advertise any HELLO to a peer?
 
 
 /**
 
 
 /**
- * List of neighbours, friends and blacklisted peers.
+ * Record for neighbours, friends and blacklisted peers.
  */
  */
-struct PeerList
+struct Peer
 {
 {
-
   /**
   /**
-   * This is a linked list.
+   * Which peer is this entry about?
    */
    */
-  struct PeerList *next;
+  struct GNUNET_PeerIdentity pid;
 
   /**
    * Our handle for the request to transmit HELLOs to this peer; NULL
 
   /**
    * Our handle for the request to transmit HELLOs to this peer; NULL
@@ -93,32 +105,11 @@ struct PeerList
    */
   struct GNUNET_CONTAINER_BloomFilter *filter;
 
    */
   struct GNUNET_CONTAINER_BloomFilter *filter;
 
-  /**
-   * Our request handle for *whitelisting* this peer (NULL if
-   * no whitelisting request is pending).
-   */
-  struct GNUNET_TRANSPORT_BlacklistRequest *wh;
-
-  /**
-   * Is this peer listed here because he is a friend?
-   */
-  int is_friend;
-
-  /**
-   * Are we connected to this peer right now?
-   */
-  int is_connected;
-
-  /**
-   * Are we currently blocking this peer (via blacklist)?
-   */
-  int is_blocked;
-
   /**
    * Until what time should we not try to connect again
    * to this peer?
    */
   /**
    * Until what time should we not try to connect again
    * to this peer?
    */
-  struct GNUNET_TIME_Absolute blacklisted_until;
+  struct GNUNET_TIME_Absolute greylisted_until;
 
   /**
    * Next time we are allowed to transmit a HELLO to this peer?
 
   /**
    * Next time we are allowed to transmit a HELLO to this peer?
@@ -137,37 +128,24 @@ struct PeerList
   GNUNET_SCHEDULER_TaskIdentifier hello_delay_task;
 
   /**
   GNUNET_SCHEDULER_TaskIdentifier hello_delay_task;
 
   /**
-   * ID of the peer.
+   * ID of task we use to clear peers from the greylist.
    */
    */
-  struct GNUNET_PeerIdentity id;
+  GNUNET_SCHEDULER_TaskIdentifier greylist_clean_task;
 
 
-};
-
-
-/**
- * Entry in linked list of active 'disconnect' requests that we have issued.
- */
-struct DisconnectList
-{
   /**
   /**
-   * This is a doubly-linked list.
+   * How often have we tried so far?
    */
    */
-  struct DisconnectList *next;
+  unsigned int connect_attempts;
 
   /**
 
   /**
-   * This is a doubly-linked list.
-   */
-  struct DisconnectList *prev;
-  
-  /**
-   * Our request handle.
+   * Is this peer listed here because he is a friend?
    */
    */
-  struct GNUNET_TRANSPORT_BlacklistRequest *rh;
-  
+  int is_friend;
+
   /**
   /**
-   * Peer we tried to disconnect.
+   * Are we connected to this peer right now?
    */
    */
-  struct GNUNET_PeerIdentity peer;
+  int is_connected;
 
 };
 
 
 };
 
@@ -178,11 +156,6 @@ struct DisconnectList
  */
 static struct GNUNET_PEERINFO_NotifyContext *peerinfo_notify;
 
  */
 static struct GNUNET_PEERINFO_NotifyContext *peerinfo_notify;
 
-/**
- * Our scheduler.
- */
-static struct GNUNET_SCHEDULER_Handle *sched;
-
 /**
  * Our configuration.
  */
 /**
  * Our configuration.
  */
@@ -204,16 +177,22 @@ static struct GNUNET_TRANSPORT_Handle *transport;
 static struct GNUNET_PeerIdentity my_identity;
 
 /**
 static struct GNUNET_PeerIdentity my_identity;
 
 /**
- * Linked list of all of our friends, all of our current neighbours
- * and all peers for which we have HELLOs.  So pretty much everyone.
+ * All of our friends, all of our current neighbours and all peers for
+ * which we have HELLOs.  So pretty much everyone.  Maps peer identities
+ * to 'struct Peer *' values.
  */
  */
-static struct PeerList *peers;
+static struct GNUNET_CONTAINER_MultiHashMap *peers;
 
 /**
  * Handle for reporting statistics.
  */
 static struct GNUNET_STATISTICS_Handle *stats;
 
 
 /**
  * Handle for reporting statistics.
  */
 static struct GNUNET_STATISTICS_Handle *stats;
 
+/**
+ * Blacklist (NULL if we have none).
+ */
+static struct GNUNET_TRANSPORT_Blacklist *blacklist;
+
 /**
  * Flag to disallow non-friend connections (pure F2F mode).
  */
 /**
  * Flag to disallow non-friend connections (pure F2F mode).
  */
@@ -245,220 +224,236 @@ static unsigned int friend_count;
  */
 static int autoconnect;
 
  */
 static int autoconnect;
 
-/**
- * Head of doubly-linked list of active 'disconnect' requests that we have issued.
- */
-static struct DisconnectList *disconnect_head;
-
-/**
- * Head of doubly-linked list of active 'disconnect' requests that we have issued.
- */
-static struct DisconnectList *disconnect_tail;
-
 
 /**
 
 /**
- * Function called once our request to 'disconnect' a peer
- * has completed.
+ * Function that decides if a connection is acceptable or not.  
+ * If we have a blacklist, only friends are allowed, so the check
+ * is rather simple.
  *
  *
- * @param cls our 'struct DisconnectList'
- * @param tc unused
+ * @param cls closure
+ * @param pid peer to approve or disapproave
+ * @return GNUNET_OK if the connection is allowed
  */
  */
-static void
-disconnect_done (void *cls,
-                const struct GNUNET_SCHEDULER_TaskContext *tc)
+static int
+blacklist_check (void *cls,
+                const struct GNUNET_PeerIdentity *pid)
 {
 {
-  struct DisconnectList *dl = cls;
+  struct Peer *pos;
 
 
+  pos = GNUNET_CONTAINER_multihashmap_get (peers, &pid->hashPubKey);
+  if ( (pos != NULL) &&
+       (pos->is_friend == GNUNET_YES) )
+    return GNUNET_OK;
   GNUNET_STATISTICS_update (stats,
                            gettext_noop ("# peers blacklisted"),
                            1,
                            GNUNET_NO);
   GNUNET_STATISTICS_update (stats,
                            gettext_noop ("# peers blacklisted"),
                            1,
                            GNUNET_NO);
-  GNUNET_CONTAINER_DLL_remove (disconnect_head,
-                              disconnect_tail,
-                              dl);
-  GNUNET_free (dl);
+  return GNUNET_SYSERR;
 }
 
 
 /**
 }
 
 
 /**
- * Force a disconnect from the specified peer. 
+ * Whitelist all peers that we blacklisted; we've passed
+ * the minimum number of friends.
  */
 static void
  */
 static void
-force_disconnect (struct PeerList *pl)
+whitelist_peers ()
 {
 {
-  const struct GNUNET_PeerIdentity *peer = &pl->id;
-  struct DisconnectList *dl;
-
-  if (NULL != pl->wh)
+  if (blacklist != NULL)
     {
     {
-      GNUNET_TRANSPORT_blacklist_cancel (pl->wh);
-      pl->wh = NULL;
+      GNUNET_TRANSPORT_blacklist_cancel (blacklist);
+      blacklist = NULL;
     }
     }
-  pl->is_blocked = GNUNET_YES;
-  dl = GNUNET_malloc (sizeof (struct DisconnectList));
-  dl->peer = *peer;
-  GNUNET_CONTAINER_DLL_insert (disconnect_head,
-                              disconnect_tail,
-                              dl);
-  dl->rh = GNUNET_TRANSPORT_blacklist (sched, cfg,                                             
-                                      peer,
-                                      GNUNET_TIME_UNIT_FOREVER_REL,
-                                      GNUNET_TIME_UNIT_FOREVER_REL,
-                                      &disconnect_done,
-                                      dl);
 }
 
 
 }
 
 
-
 /**
 /**
- * Function called once our request to 'whitelist' a peer
- * has completed.
+ * Function called by core when our attempt to connect succeeded.
  *
  *
- * @param cls our 'struct PeerList'
- * @param tc unused
+ * @param cls the 'struct Peer' for which we issued the connect request
+ * @param success was the request transmitted
  */
 static void
  */
 static void
-whitelist_done (void *cls,
-               const struct GNUNET_SCHEDULER_TaskContext *tc)
+connect_completed_callback (void *cls,
+                           int success)
 {
 {
-  struct PeerList *pl = cls;
+  struct Peer *pos = cls;
 
 
-  pl->wh = NULL;
-  GNUNET_STATISTICS_update (stats,
-                           gettext_noop ("# peers blacklisted"),
-                           -1,
-                           GNUNET_NO);
+  pos->connect_req = NULL;
 }
 
 
 /**
 }
 
 
 /**
- * Whitelist all peers that we blacklisted; we've passed
- * the minimum number of friends.
+ * Check if an additional connection from the given peer is allowed.
+ * 
+ * @param peer connection to check
+ * @return GNUNET_OK if the connection is allowed
  */
  */
-static void
-whitelist_peers ()
+static int
+is_connection_allowed (struct Peer *peer)
 {
 {
-  struct PeerList *pl;
-  struct DisconnectList *dl;
-
-  /* first, cancel all blacklisting requests */
-  while (NULL != (dl = disconnect_head))
-    {
-      GNUNET_CONTAINER_DLL_remove (disconnect_head,
-                                  disconnect_tail,
-                                  dl);
-      GNUNET_TRANSPORT_blacklist_cancel (dl->rh);
-      GNUNET_free (dl);
-    }
-  /* then, specifically whitelist all peers that we
-     know to have blacklisted */
-  pl = peers;
-  while (pl != NULL)
+  if (0 == memcmp (&my_identity, 
+                  &peer->pid, 
+                  sizeof (struct GNUNET_PeerIdentity)))
+    return GNUNET_SYSERR;       /* disallow connections to self */
+  if (peer->is_friend)
+    return GNUNET_OK;
+  if (GNUNET_YES == friends_only)
     {
     {
-      if (pl->is_blocked)
-       {
-         pl->wh = GNUNET_TRANSPORT_blacklist (sched, cfg,                                              
-                                              &pl->id,
-                                              GNUNET_TIME_UNIT_ZERO,
-                                              GNUNET_TIME_UNIT_FOREVER_REL,
-                                              &whitelist_done,
-                                              pl);
-         pl->is_blocked = GNUNET_NO;
-       }
-      pl = pl->next;
+#if DEBUG_TOPOLOGY
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                 "Determined that `%s' is not allowed to connect (not a friend)\n",
+                 GNUNET_i2s (&peer->pid));
+#endif       
+      return GNUNET_SYSERR;
     }
     }
+  if (friend_count >= minimum_friend_count)
+    return GNUNET_OK;
+#if DEBUG_TOPOLOGY
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Determined that `%s' is not allowed to connect (not enough connected friends)\n",
+             GNUNET_i2s (&peer->pid));
+#endif       
+  return GNUNET_SYSERR;
 }
 
 
 /**
 }
 
 
 /**
- * Function called by core when our attempt to connect succeeded.
+ * Free all resources associated with the given peer.
+ *
+ * @param cls closure (not used)
+ * @param pid identity of the peer
+ * @param value peer to free
+ * @return GNUNET_YES (always: continue to iterate)
  */
  */
-static void
-connect_completed_callback (void *cls,
-                           const struct GNUNET_SCHEDULER_TaskContext *tc)
+static int
+free_peer (void *cls,
+          const GNUNET_HashCode *pid,
+          void *value)
 {
 {
-  struct PeerList *pos = cls;
-
-  pos->connect_req = NULL;
+  struct Peer *pos = value;
+
+  GNUNET_break (GNUNET_OK == 
+               GNUNET_CONTAINER_multihashmap_remove (peers,
+                                                     pid,
+                                                     pos));
+  if (pos->hello_req != NULL)
+    GNUNET_CORE_notify_transmit_ready_cancel (pos->hello_req);
+  if (pos->connect_req != NULL)
+    GNUNET_CORE_peer_request_connect_cancel (pos->connect_req);              
+  if (pos->hello_delay_task != GNUNET_SCHEDULER_NO_TASK)
+    GNUNET_SCHEDULER_cancel (pos->hello_delay_task);
+  if (pos->greylist_clean_task != GNUNET_SCHEDULER_NO_TASK)
+    GNUNET_SCHEDULER_cancel (pos->greylist_clean_task);
+  GNUNET_free_non_null (pos->hello);   
+  if (pos->filter != NULL)
+    GNUNET_CONTAINER_bloomfilter_free (pos->filter);
+  GNUNET_free (pos);
+  return GNUNET_YES;
 }
 
 
 }
 
 
+/**
+ * Discard peer entries for greylisted peers
+ * where the greylisting has expired.
+ *
+ * @param cls 'struct Peer' to greylist
+ * @param tc scheduler context
+ */
+static void
+remove_from_greylist (void *cls,
+                     const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
 /**
  * Try to connect to the specified peer.
  *
  * @param pos peer to connect to
  */
 static void
 /**
  * Try to connect to the specified peer.
  *
  * @param pos peer to connect to
  */
 static void
-attempt_connect (struct PeerList *pos)
+attempt_connect (struct Peer *pos)
 {
 {
+  struct GNUNET_TIME_Relative rem;
+  
+  if ( (connection_count >= target_connection_count) &&
+       (friend_count >= minimum_friend_count) )
+    return;
+  if (GNUNET_YES == pos->is_connected)
+    return;
+  if (GNUNET_OK != is_connection_allowed (pos))
+    return;
+  if (GNUNET_TIME_absolute_get_remaining (pos->greylisted_until).rel_value > 0)
+    return;
   if (GNUNET_YES == pos->is_friend)
   if (GNUNET_YES == pos->is_friend)
-    pos->blacklisted_until = GNUNET_TIME_relative_to_absolute (BLACKLIST_AFTER_ATTEMPT_FRIEND);
+    rem = GREYLIST_AFTER_ATTEMPT_FRIEND;
   else
   else
-    pos->blacklisted_until = GNUNET_TIME_relative_to_absolute (BLACKLIST_AFTER_ATTEMPT);
+    rem = GREYLIST_AFTER_ATTEMPT;
+  rem = GNUNET_TIME_relative_multiply (rem, connection_count);
+  rem = GNUNET_TIME_relative_divide (rem, target_connection_count);
+  if (pos->connect_attempts > 30)
+    pos->connect_attempts = 30;
+  rem = GNUNET_TIME_relative_multiply (rem, 1 << (++pos->connect_attempts));
+  rem = GNUNET_TIME_relative_max (rem,
+                                 GREYLIST_AFTER_ATTEMPT_MIN);
+  rem = GNUNET_TIME_relative_min (rem,
+                                 GREYLIST_AFTER_ATTEMPT_MAX);
+  pos->greylisted_until = GNUNET_TIME_relative_to_absolute (rem);
+  if (pos->greylist_clean_task != GNUNET_SCHEDULER_NO_TASK)
+    GNUNET_SCHEDULER_cancel (pos->greylist_clean_task);
+  pos->greylist_clean_task 
+    = GNUNET_SCHEDULER_add_delayed (rem,
+                                   &remove_from_greylist,
+                                   pos);
 #if DEBUG_TOPOLOGY
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
 #if DEBUG_TOPOLOGY
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Asking core to connect to `%s'\n",
-             GNUNET_i2s (&pos->id));
+             "Asking  to connect to `%s'\n",
+             GNUNET_i2s (&pos->pid));
 #endif
   GNUNET_STATISTICS_update (stats,
                            gettext_noop ("# connect requests issued to core"),
                            1,
                            GNUNET_NO);
 #endif
   GNUNET_STATISTICS_update (stats,
                            gettext_noop ("# connect requests issued to core"),
                            1,
                            GNUNET_NO);
-  pos->connect_req = GNUNET_CORE_peer_request_connect (sched, cfg,
+  pos->connect_req = GNUNET_CORE_peer_request_connect (handle,
                                                       GNUNET_TIME_UNIT_MINUTES,
                                                       GNUNET_TIME_UNIT_MINUTES,
-                                                      &pos->id,
+                                                      &pos->pid,
                                                       &connect_completed_callback,
                                                       pos);
 }
 
 
 /**
                                                       &connect_completed_callback,
                                                       pos);
 }
 
 
 /**
- * Find a peer in our linked list.  
- * FIXME: should probably use a hash map instead.
+ * Discard peer entries for greylisted peers
+ * where the greylisting has expired.
+ *
+ * @param cls 'struct Peer' to greylist
+ * @param tc scheduler context
  */
  */
-struct PeerList *
-find_peer (const struct GNUNET_PeerIdentity * peer)
+static void
+remove_from_greylist (void *cls,
+                     const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
 {
-  struct PeerList *pos;
+  struct Peer *pos = cls;
+  struct GNUNET_TIME_Relative rem;
 
 
-  pos = peers;
-  while (pos != NULL)
+  pos->greylist_clean_task = GNUNET_SCHEDULER_NO_TASK;
+  rem = GNUNET_TIME_absolute_get_remaining (pos->greylisted_until);
+  if (rem.rel_value == 0)
     {
     {
-      if (0 == memcmp (&pos->id, peer, sizeof (struct GNUNET_PeerIdentity)))
-       return pos;
-      pos = pos->next;
+      attempt_connect (pos);
     }
     }
-  return NULL;
-}
-
-
-/**
- * Check if an additional connection from the given peer is allowed.
- */
-static int
-is_connection_allowed (struct PeerList *peer)
-{
-  if (0 == memcmp (&my_identity, &peer->id, sizeof (struct GNUNET_PeerIdentity)))
-    return GNUNET_SYSERR;       /* disallow connections to self */
-  if (peer->is_friend)
-    return GNUNET_OK;
-  if (GNUNET_YES == friends_only)
+  else
     {
     {
-#if DEBUG_TOPOLOGY
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                 "Determined that `%s' is not allowed to connect (not a friend)\n",
-                 GNUNET_i2s (&peer->id));
-#endif       
-      return GNUNET_SYSERR;
+      pos->greylist_clean_task 
+       = GNUNET_SCHEDULER_add_delayed (rem,
+                                       &remove_from_greylist,
+                                       pos);
+    }
+  if ( (GNUNET_NO == pos->is_friend) &&
+       (GNUNET_NO == pos->is_connected) )
+    {
+      free_peer (NULL, &pos->pid.hashPubKey, pos);
+      return;
     }
     }
-  if (friend_count >= minimum_friend_count)
-    return GNUNET_OK;
-#if DEBUG_TOPOLOGY
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Determined that `%s' is not allowed to connect (not enough connected friends)\n",
-             GNUNET_i2s (&peer->id));
-#endif       
-  return GNUNET_SYSERR;
 }
 
 
 }
 
 
@@ -470,16 +465,16 @@ is_connection_allowed (struct PeerList *peer)
  * @param is_friend is the new entry for a friend?
  * @return the new entry
  */
  * @param is_friend is the new entry for a friend?
  * @return the new entry
  */
-static struct PeerList *
+static struct Peer *
 make_peer (const struct
           GNUNET_PeerIdentity * peer,
           const struct GNUNET_HELLO_Message *hello,
           int is_friend)
 {
 make_peer (const struct
           GNUNET_PeerIdentity * peer,
           const struct GNUNET_HELLO_Message *hello,
           int is_friend)
 {
-  struct PeerList *ret;
+  struct Peer *ret;
   
   
-  ret = GNUNET_malloc (sizeof (struct PeerList));
-  ret->id = *peer;
+  ret = GNUNET_malloc (sizeof (struct Peer));
+  ret->pid = *peer;
   ret->is_friend = is_friend;
   if (hello != NULL)
     {
   ret->is_friend = is_friend;
   if (hello != NULL)
     {
@@ -487,58 +482,22 @@ make_peer (const struct
       memcpy (ret->hello, hello,
              GNUNET_HELLO_size (hello));
     }
       memcpy (ret->hello, hello,
              GNUNET_HELLO_size (hello));
     }
-  ret->next = peers;
-  peers = ret;
+  GNUNET_break (GNUNET_OK ==
+               GNUNET_CONTAINER_multihashmap_put (peers,
+                                                  &peer->hashPubKey,
+                                                  ret,
+                                                  GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
   return ret;
 }
 
 
   return ret;
 }
 
 
-/**
- * Free all resources associated with the given peer.
- *
- * @param peer peer to free
- */
-static void
-free_peer (struct PeerList *peer)
-{
-  struct PeerList *pos;
-  struct PeerList *prev;
-  
-  prev = NULL;
-  pos = peers;
-  while (peer != pos)
-    {
-      prev = pos;
-      pos = pos->next;
-    }
-  GNUNET_assert (pos != NULL);
-   if (prev == NULL)
-     peers = pos->next;
-   else
-     prev->next = pos->next;
-   if (pos->hello_req != NULL)
-     GNUNET_CORE_notify_transmit_ready_cancel (pos->hello_req);
-   if (pos->wh != NULL)
-     GNUNET_TRANSPORT_blacklist_cancel (pos->wh);
-   if (pos->connect_req != NULL)
-     GNUNET_CORE_peer_request_connect_cancel (pos->connect_req);             
-   if (pos->hello_delay_task != GNUNET_SCHEDULER_NO_TASK)
-     GNUNET_SCHEDULER_cancel (sched,
-                             pos->hello_delay_task);
-   GNUNET_free_non_null (pos->hello);   
-   if (pos->filter != NULL)
-     GNUNET_CONTAINER_bloomfilter_free (peer->filter);
-   GNUNET_free (pos);
-}
-
-
 /**
  * Setup bloom filter for the given peer entry.
  *
  * @param peer entry to initialize
  */
 static void
 /**
  * Setup bloom filter for the given peer entry.
  *
  * @param peer entry to initialize
  */
 static void
-setup_filter (struct PeerList *peer)
+setup_filter (struct Peer *peer)
 {
   /* 2^{-5} chance of not sending a HELLO to a peer is
      acceptably small (if the filter is 50% full);
 {
   /* 2^{-5} chance of not sending a HELLO to a peer is
      acceptably small (if the filter is 50% full);
@@ -550,14 +509,14 @@ setup_filter (struct PeerList *peer)
   peer->filter = GNUNET_CONTAINER_bloomfilter_load (NULL, 64, 5);
   peer->filter_expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADVERTISEMENT_MIN_REPEAT_FREQUENCY);
   /* never send a peer its own HELLO */
   peer->filter = GNUNET_CONTAINER_bloomfilter_load (NULL, 64, 5);
   peer->filter_expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADVERTISEMENT_MIN_REPEAT_FREQUENCY);
   /* never send a peer its own HELLO */
-  GNUNET_CONTAINER_bloomfilter_add (peer->filter, &peer->id.hashPubKey);
+  GNUNET_CONTAINER_bloomfilter_add (peer->filter, &peer->pid.hashPubKey);
 }
 
 
 /**
  * Function to fill send buffer with HELLO.
  *
 }
 
 
 /**
  * Function to fill send buffer with HELLO.
  *
- * @param cls 'struct PeerList' of the target peer
+ * @param cls 'struct Peer' of the target peer
  * @param size number of bytes available in buf
  * @param buf where the callee should write the message
  * @return number of bytes written to buf
  * @param size number of bytes available in buf
  * @param buf where the callee should write the message
  * @return number of bytes written to buf
@@ -568,6 +527,74 @@ hello_advertising_ready (void *cls,
                         void *buf);
 
 
                         void *buf);
 
 
+
+
+/**
+ * Closure for 'find_advertisable_hello'.
+ */
+struct FindAdvHelloContext {
+
+  /**
+   * Peer we want to advertise to.
+   */
+  struct Peer *peer;
+
+  /**
+   * Where to store the result (peer selected for advertising).
+   */
+  struct Peer *result;
+
+  /**
+   * Maximum HELLO size we can use right now.
+   */
+  size_t max_size;
+
+  struct GNUNET_TIME_Relative next_adv;
+};
+
+
+/**
+ * Find a peer that would be reasonable for advertising.
+ *
+ * @param cls closure
+ * @param pid identity of a peer
+ * @param value 'struct Peer*' for the peer we are considering 
+ * @return GNUNET_YES (continue iteration)
+ */
+static int
+find_advertisable_hello (void *cls,
+                        const GNUNET_HashCode *pid,
+                        void *value)
+{
+  struct FindAdvHelloContext *fah = cls;
+  struct Peer *pos = value;
+  struct GNUNET_TIME_Relative rst_time;
+  size_t hs;
+
+  if (pos == fah->peer)
+    return GNUNET_YES;
+  if (pos->hello == NULL)
+    return GNUNET_YES;
+  rst_time = GNUNET_TIME_absolute_get_remaining (pos->filter_expiration);
+  if (0 == rst_time.rel_value)
+    {
+      /* time to discard... */
+      GNUNET_CONTAINER_bloomfilter_free (pos->filter);
+      setup_filter (pos);
+    }
+  fah->next_adv = GNUNET_TIME_relative_min (rst_time,
+                                           fah->next_adv);
+  hs = GNUNET_HELLO_size (pos->hello);
+  if (hs > fah->max_size)
+    return GNUNET_YES;
+  if (GNUNET_NO ==
+      GNUNET_CONTAINER_bloomfilter_test (pos->filter,
+                                        &fah->peer->pid.hashPubKey))
+    fah->result = pos;    
+  return GNUNET_YES;
+}
+
+
 /**
  * Calculate when we would like to send the next HELLO to this
  * peer and ask for it.
 /**
  * Calculate when we would like to send the next HELLO to this
  * peer and ask for it.
@@ -579,62 +606,42 @@ static void
 schedule_next_hello (void *cls,
                     const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
 schedule_next_hello (void *cls,
                     const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
-  struct PeerList *pl = cls;
-  struct PeerList *pos;
-  struct PeerList *next;
-  uint16_t next_want;
-  struct GNUNET_TIME_Relative next_adv;
-  struct GNUNET_TIME_Relative rst_time;
-  
+  struct Peer *pl = cls;
+  struct FindAdvHelloContext fah;
+  size_t next_want;
+  struct GNUNET_TIME_Relative delay;
   pl->hello_delay_task = GNUNET_SCHEDULER_NO_TASK;
   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
     return; /* we're out of here */
   pl->hello_delay_task = GNUNET_SCHEDULER_NO_TASK;
   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
     return; /* we're out of here */
-  next_want = 0;
-  next_adv = GNUNET_TIME_UNIT_FOREVER_REL;
+  if (pl->hello_req != NULL)
+    return; /* did not finish sending the previous one */
   /* find applicable HELLOs */
   /* find applicable HELLOs */
-  next = peers;
-  while (NULL != (pos = next))
-    {
-      next = pos->next;
-      if (pos->hello == NULL)
-       continue;
-      rst_time = GNUNET_TIME_absolute_get_remaining (pos->filter_expiration);
-      if (0 == rst_time.value)
-       {
-         /* time to discard... */
-         GNUNET_CONTAINER_bloomfilter_free (pos->filter);
-         setup_filter (pos);
-       }
-      else
-       {
-         if (rst_time.value < next_adv.value)
-           next_want = GNUNET_HELLO_size (pos->hello);
-         next_adv = GNUNET_TIME_relative_min (rst_time,
-                                              next_adv);         
-       }
-      if (GNUNET_NO ==
-         GNUNET_CONTAINER_bloomfilter_test (pos->filter,
-                                            &pl->id.hashPubKey))
-       break;
-    }
-  if (pos != NULL)  
-    next_adv = GNUNET_TIME_absolute_get_remaining (pl->next_hello_allowed);
-  if (next_adv.value == 0)
+  fah.peer = pl;
+  fah.result = NULL;
+  fah.max_size = GNUNET_SERVER_MAX_MESSAGE_SIZE - 1;
+  fah.next_adv = GNUNET_TIME_UNIT_FOREVER_REL;
+  GNUNET_CONTAINER_multihashmap_iterate (peers,
+                                        &find_advertisable_hello,
+                                        &fah);
+  pl->hello_delay_task 
+    = GNUNET_SCHEDULER_add_delayed (fah.next_adv,
+                                   &schedule_next_hello,
+                                   pl);
+  if (fah.result == NULL)
+    return;   
+  next_want = GNUNET_HELLO_size (fah.result->hello);
+  delay = GNUNET_TIME_absolute_get_remaining (pl->next_hello_allowed);
+  if (delay.rel_value == 0)
     {
       /* now! */
       pl->hello_req = GNUNET_CORE_notify_transmit_ready (handle, 0,
     {
       /* now! */
       pl->hello_req = GNUNET_CORE_notify_transmit_ready (handle, 0,
-                                                        next_adv,
-                                                        &pl->id,
+                                                        GNUNET_CONSTANTS_SERVICE_TIMEOUT,
+                                                        &pl->pid,
                                                         next_want,
                                                         &hello_advertising_ready,
                                                         pl);
                                                         next_want,
                                                         &hello_advertising_ready,
                                                         pl);
-      return;
     }
     }
-  pl->hello_delay_task 
-    = GNUNET_SCHEDULER_add_delayed (sched,
-                                   next_adv,
-                                   &schedule_next_hello,
-                                   pl);
 }
 
 
 }
 
 
@@ -642,25 +649,38 @@ schedule_next_hello (void *cls,
  * Cancel existing requests for sending HELLOs to this peer
  * and recalculate when we should send HELLOs to it based
  * on our current state (something changed!).
  * Cancel existing requests for sending HELLOs to this peer
  * and recalculate when we should send HELLOs to it based
  * on our current state (something changed!).
+ *
+ * @param cls closure, 'struct Peer' to skip, or NULL
+ * @param pid identity of a peer
+ * @param value 'struct Peer*' for the peer
+ * @return GNUNET_YES (always)
  */
  */
-static void
-reschedule_hellos (struct PeerList *peer)
+static int
+reschedule_hellos (void *cls,
+                  const GNUNET_HashCode *pid,
+                  void *value)
 {
 {
+  struct Peer *peer = value;
+  struct Peer *skip = cls;
+
+  if (skip == peer)
+    return GNUNET_YES;
+  if (! peer->is_connected) 
+    return GNUNET_YES;
   if (peer->hello_req != NULL)
     {
       GNUNET_CORE_notify_transmit_ready_cancel (peer->hello_req);
       peer->hello_req = NULL;
     }
   if (peer->hello_req != NULL)
     {
       GNUNET_CORE_notify_transmit_ready_cancel (peer->hello_req);
       peer->hello_req = NULL;
     }
-   if (peer->hello_delay_task != GNUNET_SCHEDULER_NO_TASK)
-     {
-       GNUNET_SCHEDULER_cancel (sched,
-                               peer->hello_delay_task);
-       peer->hello_delay_task = GNUNET_SCHEDULER_NO_TASK;
-     }
-   peer->hello_delay_task 
-     = GNUNET_SCHEDULER_add_now (sched,
-                                &schedule_next_hello,
-                                peer);
+  if (peer->hello_delay_task != GNUNET_SCHEDULER_NO_TASK)
+    {
+      GNUNET_SCHEDULER_cancel (peer->hello_delay_task);
+      peer->hello_delay_task = GNUNET_SCHEDULER_NO_TASK;
+    }
+  peer->hello_delay_task 
+    = GNUNET_SCHEDULER_add_now (&schedule_next_hello,
+                               peer);
+  return GNUNET_YES;
 }
 
 
 }
 
 
@@ -669,51 +689,42 @@ reschedule_hellos (struct PeerList *peer)
  *
  * @param cls closure
  * @param peer peer identity this notification is about
  *
  * @param cls closure
  * @param peer peer identity this notification is about
- * @param latency reported latency of the connection with 'other'
- * @param distance reported distance (DV) to 'other' 
+ * @param atsi performance data
  */
 static void 
 connect_notify (void *cls,
                const struct
                GNUNET_PeerIdentity * peer,
  */
 static void 
 connect_notify (void *cls,
                const struct
                GNUNET_PeerIdentity * peer,
-               struct GNUNET_TIME_Relative latency,
-               uint32_t distance)
+               const struct GNUNET_TRANSPORT_ATS_Information *atsi)
 {
 {
-  struct PeerList *pos;
+  struct Peer *pos;
 
 #if DEBUG_TOPOLOGY
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Core told us that we are connecting to `%s'\n",
              GNUNET_i2s (peer));
 #endif
 
 #if DEBUG_TOPOLOGY
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Core told us that we are connecting to `%s'\n",
              GNUNET_i2s (peer));
 #endif
+  if (0 == memcmp(&my_identity, peer, sizeof(struct GNUNET_PeerIdentity)))
+    return;
+
   connection_count++;
   GNUNET_STATISTICS_set (stats,
                         gettext_noop ("# peers connected"),
                         connection_count,
                         GNUNET_NO);
   connection_count++;
   GNUNET_STATISTICS_set (stats,
                         gettext_noop ("# peers connected"),
                         connection_count,
                         GNUNET_NO);
-  pos = find_peer (peer);
+  pos = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey);
   if (pos == NULL)    
     {
       pos = make_peer (peer, NULL, GNUNET_NO);
   if (pos == NULL)    
     {
       pos = make_peer (peer, NULL, GNUNET_NO);
-      if (GNUNET_OK != is_connection_allowed (pos))
-       {
-         GNUNET_assert (pos->is_friend == GNUNET_NO);
-         pos->is_connected = GNUNET_YES;
-#if DEBUG_TOPOLOGY
-         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                     "Connection to `%s' is forbidden, forcing disconnect!\n",
-                     GNUNET_i2s (peer));
-#endif       
-         force_disconnect (pos);
-         return;
-       }
+      GNUNET_break (GNUNET_OK == is_connection_allowed (pos));
     }
   else
     {
       GNUNET_assert (GNUNET_NO == pos->is_connected);
     }
   else
     {
       GNUNET_assert (GNUNET_NO == pos->is_connected);
-      pos->blacklisted_until.value = 0; /* remove blacklisting */
+      pos->greylisted_until.abs_value = 0; /* remove greylisting */
     }
   pos->is_connected = GNUNET_YES;
     }
   pos->is_connected = GNUNET_YES;
+  pos->connect_attempts = 0; /* re-set back-off factor */
   if (pos->is_friend)
     {
       if ( (friend_count == minimum_friend_count - 1) &&
   if (pos->is_friend)
     {
       if ( (friend_count == minimum_friend_count - 1) &&
@@ -722,57 +733,30 @@ connect_notify (void *cls,
       friend_count++;
       GNUNET_STATISTICS_set (stats,
                             gettext_noop ("# friends connected"),
       friend_count++;
       GNUNET_STATISTICS_set (stats,
                             gettext_noop ("# friends connected"),
-                            connection_count,
+                            friend_count,
                             GNUNET_NO);
     }
                             GNUNET_NO);
     }
-  reschedule_hellos (pos);
-}
-
-
-/**
- * Disconnect from all non-friends (we're below quota).
- */
-static void
-drop_non_friends ()
-{
-  struct PeerList *pos;
-
-  pos = peers;
-  while (pos != NULL)
-    {
-      if ( (GNUNET_NO == pos->is_friend) &&
-          (GNUNET_YES == pos->is_connected) )
-       {
-#if DEBUG_TOPOLOGY
-         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                     "Connection to `%s' is not from a friend, forcing disconnect!\n",
-                     GNUNET_i2s (&pos->id));
-#endif       
-         force_disconnect (pos);
-       }
-      pos = pos->next;
-    }
+  reschedule_hellos (NULL, &peer->hashPubKey, pos);
 }
 
 
 /**
  * Try to add more peers to our connection set.
 }
 
 
 /**
  * Try to add more peers to our connection set.
+ *
+ * @param cls closure, not used
+ * @param pid identity of a peer
+ * @param value 'struct Peer*' for the peer
+ * @return GNUNET_YES (continue to iterate)
  */
  */
-static void
-try_add_peers ()
+static int
+try_add_peers (void *cls,
+              const GNUNET_HashCode *pid,
+              void *value)
 {
 {
-  struct PeerList *pos;
+  struct Peer *pos = value;
 
 
-  pos = peers;
-  while (pos != NULL)
-    {
-      if ( (GNUNET_TIME_absolute_get_remaining (pos->blacklisted_until).value == 0) &&
-          ( (GNUNET_YES == pos->is_friend) ||
-            (friend_count >= minimum_friend_count) ) &&
-          (GNUNET_YES != pos->is_connected) )
-       attempt_connect (pos);
-      pos = pos->next;
-    }
+  attempt_connect (pos);
+  return GNUNET_YES;
 }
 
 
 }
 
 
@@ -787,14 +771,17 @@ disconnect_notify (void *cls,
                   const struct
                   GNUNET_PeerIdentity * peer)
 {
                   const struct
                   GNUNET_PeerIdentity * peer)
 {
-  struct PeerList *pos;
+  struct Peer *pos;
+
+  if (0 == memcmp(&my_identity, peer, sizeof(struct GNUNET_PeerIdentity)))
+    return;
 #if DEBUG_TOPOLOGY
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Core told us that we disconnected from `%s'\n",
              GNUNET_i2s (peer));
 #endif       
 #if DEBUG_TOPOLOGY
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Core told us that we disconnected from `%s'\n",
              GNUNET_i2s (peer));
 #endif       
-  pos = find_peer (peer);
+  pos = GNUNET_CONTAINER_multihashmap_get (peers,
+                                          &peer->hashPubKey);
   if (pos == NULL)
     {
       GNUNET_break (0);
   if (pos == NULL)
     {
       GNUNET_break (0);
@@ -815,21 +802,18 @@ disconnect_notify (void *cls,
       friend_count--; 
       GNUNET_STATISTICS_set (stats,
                             gettext_noop ("# friends connected"),
       friend_count--; 
       GNUNET_STATISTICS_set (stats,
                             gettext_noop ("# friends connected"),
-                            connection_count,
+                            friend_count,
                             GNUNET_NO);
     }
   if ( (connection_count < target_connection_count) ||
        (friend_count < minimum_friend_count) )
                             GNUNET_NO);
     }
   if ( (connection_count < target_connection_count) ||
        (friend_count < minimum_friend_count) )
-    try_add_peers ();   
-  if (friend_count < minimum_friend_count)
-    {
-      /* disconnect from all non-friends */
-#if DEBUG_TOPOLOGY
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                 "Not enough friendly connections, dropping all non-friend connections\n");
-#endif       
-      drop_non_friends ();
-    }
+    GNUNET_CONTAINER_multihashmap_iterate (peers,
+                                          &try_add_peers,
+                                          NULL);
+  if ( (friend_count < minimum_friend_count) &&
+       (blacklist == NULL) )
+    blacklist = GNUNET_TRANSPORT_blacklist (cfg,
+                                           &blacklist_check, NULL);
 }
 
 
 }
 
 
@@ -847,7 +831,8 @@ static int
 address_iterator (void *cls,
                  const char *tname,
                  struct GNUNET_TIME_Absolute expiration,
 address_iterator (void *cls,
                  const char *tname,
                  struct GNUNET_TIME_Absolute expiration,
-                 const void *addr, size_t addrlen)
+                 const void *addr, 
+                 uint16_t addrlen)
 {
   int *flag = cls;
   *flag = GNUNET_YES;
 {
   int *flag = cls;
   *flag = GNUNET_YES;
@@ -858,17 +843,24 @@ address_iterator (void *cls,
 /**
  * We've gotten a HELLO from another peer.  Consider it for
  * advertising.
 /**
  * We've gotten a HELLO from another peer.  Consider it for
  * advertising.
+ *
+ * @param hello the HELLO we got
  */
 static void
 consider_for_advertising (const struct GNUNET_HELLO_Message *hello)
 {
   int have_address;
   struct GNUNET_PeerIdentity pid;
  */
 static void
 consider_for_advertising (const struct GNUNET_HELLO_Message *hello)
 {
   int have_address;
   struct GNUNET_PeerIdentity pid;
-  struct PeerList *peer;
-  struct PeerList *pos;
+  struct GNUNET_TIME_Absolute dt;
+  struct GNUNET_HELLO_Message *nh;
+  struct Peer *peer;
   uint16_t size;
 
   uint16_t size;
 
-  GNUNET_break (GNUNET_OK == GNUNET_HELLO_get_id (hello, &pid));
+  if (GNUNET_OK != GNUNET_HELLO_get_id (hello, &pid))
+    {
+       GNUNET_break (0);
+       return;
+    }
   if (0 == memcmp (&pid,
                   &my_identity,
                   sizeof (struct GNUNET_PeerIdentity)))
   if (0 == memcmp (&pid,
                   &my_identity,
                   sizeof (struct GNUNET_PeerIdentity)))
@@ -880,50 +872,64 @@ consider_for_advertising (const struct GNUNET_HELLO_Message *hello)
                                  &have_address);
   if (GNUNET_NO == have_address)
     return; /* no point in advertising this one... */
                                  &have_address);
   if (GNUNET_NO == have_address)
     return; /* no point in advertising this one... */
-  peer = find_peer (&pid);
+  peer = GNUNET_CONTAINER_multihashmap_get (peers,
+                                           &pid.hashPubKey);
   if (peer == NULL)
   if (peer == NULL)
-    peer = make_peer (&pid, hello, GNUNET_NO);
-  // FIXME: check if 'hello' is any different from peer->hello?
+    {
+      peer = make_peer (&pid, hello, GNUNET_NO);
+    }
+  else if (peer->hello != NULL)
+    {
+      dt = GNUNET_HELLO_equals (peer->hello,
+                               hello,
+                               GNUNET_TIME_absolute_get());
+      if (dt.abs_value == GNUNET_TIME_UNIT_FOREVER_ABS.abs_value)
+       return; /* nothing new here */
+    }
 #if DEBUG_TOPOLOGY
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Found `%s' from peer `%s' for advertising\n",
              "HELLO",
              GNUNET_i2s (&pid));
 #endif 
 #if DEBUG_TOPOLOGY
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Found `%s' from peer `%s' for advertising\n",
              "HELLO",
              GNUNET_i2s (&pid));
 #endif 
-  size = GNUNET_HELLO_size (hello);
-  GNUNET_free_non_null (peer->hello);
-  peer->hello = GNUNET_malloc (size);
-  memcpy (peer->hello, hello, size);
+  if (peer->hello != NULL)
+    {
+      nh = GNUNET_HELLO_merge (peer->hello,
+                              hello);
+      GNUNET_free (peer->hello);
+      peer->hello = nh;
+    }
+  else
+    {
+      size = GNUNET_HELLO_size (hello);
+      peer->hello = GNUNET_malloc (size);
+      memcpy (peer->hello, hello, size);
+    }
   if (peer->filter != NULL)
     GNUNET_CONTAINER_bloomfilter_free (peer->filter);
   setup_filter (peer);
   /* since we have a new HELLO to pick from, re-schedule all
      HELLO requests that are not bound by the HELLO send rate! */
   if (peer->filter != NULL)
     GNUNET_CONTAINER_bloomfilter_free (peer->filter);
   setup_filter (peer);
   /* since we have a new HELLO to pick from, re-schedule all
      HELLO requests that are not bound by the HELLO send rate! */
-  pos = peers;
-  while (NULL != pos)
-    {
-      if (pos != peer) 
-       {
-         if ( (pos->is_connected) &&
-              (GNUNET_TIME_absolute_get_remaining (pos->next_hello_allowed).value <= HELLO_ADVERTISEMENT_MIN_FREQUENCY.value) )
-           reschedule_hellos (pos);    
-       }
-      pos = pos->next;
-    }
+  GNUNET_CONTAINER_multihashmap_iterate (peers,
+                                        &reschedule_hellos,
+                                        peer);
 }
 
 
 /**
 }
 
 
 /**
- * Peerinfo calls this function to let us know about a possible peer
+ * PEERINFO calls this function to let us know about a possible peer
  * that we might want to connect to.
  * that we might want to connect to.
+ *
+ * @param cls closure (not used)
+ * @param peer potential peer to connect to
+ * @param hello HELLO for this peer (or NULL)
  */
 static void
 process_peer (void *cls,
              const struct GNUNET_PeerIdentity *peer,
  */
 static void
 process_peer (void *cls,
              const struct GNUNET_PeerIdentity *peer,
-             const struct GNUNET_HELLO_Message *hello,
-             uint32_t trust)
+             const struct GNUNET_HELLO_Message *hello)
 {
 {
-  struct PeerList *pos;
+  struct Peer *pos;
 
   GNUNET_assert (peer != NULL);
   if (0 == memcmp (&my_identity,
 
   GNUNET_assert (peer != NULL);
   if (0 == memcmp (&my_identity,
@@ -932,7 +938,9 @@ process_peer (void *cls,
   if (hello == NULL)
     {
       /* free existing HELLO, if any */
   if (hello == NULL)
     {
       /* free existing HELLO, if any */
-      if (NULL != (pos = find_peer (peer)))
+      pos = GNUNET_CONTAINER_multihashmap_get (peers,
+                                              &peer->hashPubKey);
+      if (NULL != pos)
        {
          GNUNET_free_non_null (pos->hello);
          pos->hello = NULL;
        {
          GNUNET_free_non_null (pos->hello);
          pos->hello = NULL;
@@ -943,21 +951,17 @@ process_peer (void *cls,
            }
          if ( (! pos->is_connected) &&
               (! pos->is_friend) &&
            }
          if ( (! pos->is_connected) &&
               (! pos->is_friend) &&
-              (0 == GNUNET_TIME_absolute_get_remaining (pos->blacklisted_until).value) )
-           free_peer (pos);
+              (0 == GNUNET_TIME_absolute_get_remaining (pos->greylisted_until).rel_value) )
+           free_peer (NULL, &pos->pid.hashPubKey, pos);
        }
       return;
     }
   consider_for_advertising (hello);
        }
       return;
     }
   consider_for_advertising (hello);
-  pos = find_peer (peer);  
+  pos = GNUNET_CONTAINER_multihashmap_get (peers,
+                                          &peer->hashPubKey);
   if (pos == NULL)
     pos = make_peer (peer, hello, GNUNET_NO);
   GNUNET_assert (NULL != pos);
   if (pos == NULL)
     pos = make_peer (peer, hello, GNUNET_NO);
   GNUNET_assert (NULL != pos);
-#if DEBUG_TOPOLOGY
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Considering connecting to peer `%s'\n",
-             GNUNET_i2s (peer));
-#endif 
   if (GNUNET_YES == pos->is_connected)
     {
 #if DEBUG_TOPOLOGY
   if (GNUNET_YES == pos->is_connected)
     {
 #if DEBUG_TOPOLOGY
@@ -967,49 +971,21 @@ process_peer (void *cls,
 #endif 
       return;
     }
 #endif 
       return;
     }
-  if (GNUNET_TIME_absolute_get_remaining (pos->blacklisted_until).value > 0)
+  if (GNUNET_TIME_absolute_get_remaining (pos->greylisted_until).rel_value > 0)
     {
 #if DEBUG_TOPOLOGY
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                  "Already tried peer `%s' recently\n",
                  GNUNET_i2s (peer));
 #endif 
     {
 #if DEBUG_TOPOLOGY
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                  "Already tried peer `%s' recently\n",
                  GNUNET_i2s (peer));
 #endif 
-      return; /* peer still blacklisted */
-    }
-  if ( (GNUNET_YES == pos->is_friend) ||
-       (GNUNET_YES != friends_only) ||    
-       (friend_count >= minimum_friend_count) )
-    attempt_connect (pos);
-}
-
-
-/**
- * Discard peer entries for blacklisted peers
- * where the blacklisting has expired.
- */
-static void
-discard_old_blacklist_entries (void *cls,
-                              const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
-  struct PeerList *pos;
-  struct PeerList *next;
-
-  if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
-    return;
-  next = peers;
-  while (NULL != (pos = next))
-    {
-      next = pos->next;
-      if ( (GNUNET_NO == pos->is_friend) &&
-          (GNUNET_NO == pos->is_connected) &&
-          (GNUNET_NO == pos->is_blocked) &&
-          (0 == GNUNET_TIME_absolute_get_remaining (pos->blacklisted_until).value) )
-       free_peer (pos);
+      return; /* peer still greylisted */
     }
     }
-  GNUNET_SCHEDULER_add_delayed (sched,
-                               BLACKLIST_AFTER_ATTEMPT,
-                               &discard_old_blacklist_entries,
-                               NULL);
+#if DEBUG_TOPOLOGY
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Considering connecting to peer `%s'\n",
+             GNUNET_i2s (peer));
+#endif 
+  attempt_connect (pos);
 }
 
 
 }
 
 
@@ -1035,7 +1011,7 @@ core_init (void *cls,
     {
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                  _("Failed to connect to core service, can not manage topology!\n"));
     {
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                  _("Failed to connect to core service, can not manage topology!\n"));
-      GNUNET_SCHEDULER_shutdown (sched);
+      GNUNET_SCHEDULER_shutdown ();
       return;
     }
   handle = server;
       return;
     }
   handle = server;
@@ -1045,12 +1021,7 @@ core_init (void *cls,
              "I am peer `%s'\n",
              GNUNET_i2s (my_id));
 #endif         
              "I am peer `%s'\n",
              GNUNET_i2s (my_id));
 #endif         
-  GNUNET_SCHEDULER_add_delayed (sched,
-                               BLACKLIST_AFTER_ATTEMPT,
-                               &discard_old_blacklist_entries,
-                               NULL);
-  peerinfo_notify = GNUNET_PEERINFO_notify (cfg, sched,
-                                           &process_peer,
+  peerinfo_notify = GNUNET_PEERINFO_notify (cfg, &process_peer,
                                            NULL);
 }
 
                                            NULL);
 }
 
@@ -1068,7 +1039,7 @@ read_friends_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
   struct stat frstat;
   struct GNUNET_CRYPTO_HashAsciiEncoded enc;
   unsigned int entries_found;
   struct stat frstat;
   struct GNUNET_CRYPTO_HashAsciiEncoded enc;
   unsigned int entries_found;
-  struct PeerList *fl;
+  struct Peer *fl;
 
   if (GNUNET_OK !=
       GNUNET_CONFIGURATION_get_value_filename (cfg,
 
   if (GNUNET_OK !=
       GNUNET_CONFIGURATION_get_value_filename (cfg,
@@ -1083,17 +1054,16 @@ read_friends_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
       return;
     }
   if (GNUNET_OK != GNUNET_DISK_file_test (fn))
       return;
     }
   if (GNUNET_OK != GNUNET_DISK_file_test (fn))
-    GNUNET_DISK_fn_write (fn, NULL, 0, GNUNET_DISK_PERM_USER_READ
-        | GNUNET_DISK_PERM_USER_WRITE);
+    GNUNET_DISK_fn_write (fn, NULL, 0, 
+                         GNUNET_DISK_PERM_USER_READ
+                         | GNUNET_DISK_PERM_USER_WRITE);
   if (0 != STAT (fn, &frstat))
     {
       if ((friends_only) || (minimum_friend_count > 0))
   if (0 != STAT (fn, &frstat))
     {
       if ((friends_only) || (minimum_friend_count > 0))
-        {
-          GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                     _("Could not read friends list `%s'\n"), fn);
-         GNUNET_free (fn);
-          return;
-        }
+       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                   _("Could not read friends list `%s'\n"), fn);
+      GNUNET_free (fn);
+      return;
     }
   if (frstat.st_size == 0)
     {
     }
   if (frstat.st_size == 0)
     {
@@ -1104,6 +1074,13 @@ read_friends_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
       return;
     }
   data = GNUNET_malloc_large (frstat.st_size);
       return;
     }
   data = GNUNET_malloc_large (frstat.st_size);
+  if (data == NULL)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                 _("Failed to read friends list from `%s': out of memory\n"), fn);
+      GNUNET_free (fn);
+      return;
+    }
   if (frstat.st_size !=
       GNUNET_DISK_fn_read (fn, data, frstat.st_size))
     {
   if (frstat.st_size !=
       GNUNET_DISK_fn_read (fn, data, frstat.st_size))
     {
@@ -1115,19 +1092,19 @@ read_friends_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
     }
   entries_found = 0;
   pos = 0;
     }
   entries_found = 0;
   pos = 0;
-  while ((pos < frstat.st_size) && isspace (data[pos]))
+  while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
     pos++;
   while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) &&
         (pos <= frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
     {
       memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
     pos++;
   while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) &&
         (pos <= frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
     {
       memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
-      if (!isspace (enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
+      if (!isspace ( (unsigned char) enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
        {
          GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                      _("Syntax error in topology specification at offset %llu, skipping bytes.\n"),
                      (unsigned long long) pos);
          pos++;
        {
          GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                      _("Syntax error in topology specification at offset %llu, skipping bytes.\n"),
                      (unsigned long long) pos);
          pos++;
-         while ((pos < frstat.st_size) && (!isspace (data[pos])))
+         while ((pos < frstat.st_size) && (!isspace ( (unsigned char) data[pos])))
            pos++;
          continue;
        }
            pos++;
          continue;
        }
@@ -1151,7 +1128,7 @@ read_friends_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
                              GNUNET_YES);
              GNUNET_log (GNUNET_ERROR_TYPE_INFO,
                          _("Found friend `%s' in configuration\n"),
                              GNUNET_YES);
              GNUNET_log (GNUNET_ERROR_TYPE_INFO,
                          _("Found friend `%s' in configuration\n"),
-                         GNUNET_i2s (&fl->id));
+                         GNUNET_i2s (&fl->pid));
            }
          else
            {
            }
          else
            {
@@ -1161,7 +1138,7 @@ read_friends_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
            }
        }
       pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
            }
        }
       pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
-      while ((pos < frstat.st_size) && isspace (data[pos]))
+      while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
        pos++;
     }
   GNUNET_free (data);
        pos++;
     }
   GNUNET_free (data);
@@ -1193,8 +1170,7 @@ read_friends_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
  * @param other the other peer involved (sender or receiver, NULL
  *        for loopback messages where we are both sender and receiver)
  * @param message the actual HELLO message
  * @param other the other peer involved (sender or receiver, NULL
  *        for loopback messages where we are both sender and receiver)
  * @param message the actual HELLO message
- * @param latency reported latency of the connection with 'other'
- * @param distance reported distance (DV) to 'other' 
+ * @param atsi performance data
  * @return GNUNET_OK to keep the connection open,
  *         GNUNET_SYSERR to close it (signal serious error)
  */
  * @return GNUNET_OK to keep the connection open,
  *         GNUNET_SYSERR to close it (signal serious error)
  */
@@ -1203,19 +1179,45 @@ handle_encrypted_hello (void *cls,
                        const struct GNUNET_PeerIdentity * other,
                        const struct GNUNET_MessageHeader *
                        message,
                        const struct GNUNET_PeerIdentity * other,
                        const struct GNUNET_MessageHeader *
                        message,
-                       struct GNUNET_TIME_Relative latency,
-                       uint32_t distance)
+                       const struct GNUNET_TRANSPORT_ATS_Information *atsi)
 {
 {
+  struct Peer *peer;
+  struct GNUNET_PeerIdentity pid;
+
 #if DEBUG_TOPOLOGY
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Received encrypted `%s' from peer `%s'",
              "HELLO",
              GNUNET_i2s (other));
 #endif         
 #if DEBUG_TOPOLOGY
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Received encrypted `%s' from peer `%s'",
              "HELLO",
              GNUNET_i2s (other));
 #endif         
+  if (GNUNET_OK !=
+      GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message*) message,
+                          &pid))
+    {
+      GNUNET_break_op (0);
+      return GNUNET_SYSERR;
+    }
   GNUNET_STATISTICS_update (stats,
                            gettext_noop ("# HELLO messages received"),
                            1,
                            GNUNET_NO);
   GNUNET_STATISTICS_update (stats,
                            gettext_noop ("# HELLO messages received"),
                            1,
                            GNUNET_NO);
+  peer = GNUNET_CONTAINER_multihashmap_get (peers,
+                                           &pid.hashPubKey);
+  if (peer == NULL)
+    {
+      if ( (GNUNET_YES == friends_only) ||
+          (friend_count < minimum_friend_count) )
+       return GNUNET_OK;      
+    }
+  else
+    {
+      if ( (GNUNET_YES != peer->is_friend) &&
+          (GNUNET_YES == friends_only) )
+       return GNUNET_OK;
+      if ( (GNUNET_YES != peer->is_friend) &&
+          (friend_count < minimum_friend_count) )
+       return GNUNET_OK;      
+    }
   if (transport != NULL)
     GNUNET_TRANSPORT_offer_hello (transport,
                                  message);
   if (transport != NULL)
     GNUNET_TRANSPORT_offer_hello (transport,
                                  message);
@@ -1226,7 +1228,7 @@ handle_encrypted_hello (void *cls,
 /**
  * Function to fill send buffer with HELLO.
  *
 /**
  * Function to fill send buffer with HELLO.
  *
- * @param cls 'struct PeerList' of the target peer
+ * @param cls 'struct Peer' of the target peer
  * @param size number of bytes available in buf
  * @param buf where the callee should write the message
  * @return number of bytes written to buf
  * @param size number of bytes available in buf
  * @param buf where the callee should write the message
  * @return number of bytes written to buf
@@ -1236,63 +1238,41 @@ hello_advertising_ready (void *cls,
                         size_t size,
                         void *buf)
 {
                         size_t size,
                         void *buf)
 {
-  struct PeerList *pl = cls;
-  struct PeerList *pos; 
-  struct PeerList *next;
-  uint16_t want;
-  size_t hs;
+  struct Peer *pl = cls;
+  struct FindAdvHelloContext fah;
+  size_t want;
 
   pl->hello_req = NULL;
 
   pl->hello_req = NULL;
-#if DEBUG_TOPOLOGY
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Data solicited for `%s', considering sending `%s'",
-             GNUNET_i2s (&pl->id),
-             "HELLO");
-#endif         
   /* find applicable HELLOs */
   /* find applicable HELLOs */
-  next = peers;
-  while (NULL != (pos = next))
-    {
-      next = pos->next;
-      if (pos->hello == NULL)
-       continue;
-      if (0 == GNUNET_TIME_absolute_get_remaining (pos->filter_expiration).value)
-       {
-         /* time to discard... */
-         GNUNET_CONTAINER_bloomfilter_free (pos->filter);
-         setup_filter (pos);
-       }
-      if (GNUNET_NO ==
-         GNUNET_CONTAINER_bloomfilter_test (pos->filter,
-                                            &pl->id.hashPubKey))
-       break;
-    }
+  fah.peer = pl;
+  fah.result = NULL;
+  fah.max_size = size;
+  fah.next_adv = GNUNET_TIME_UNIT_FOREVER_REL;
+  GNUNET_CONTAINER_multihashmap_iterate (peers,
+                                        &find_advertisable_hello,
+                                        &fah);
   want = 0;
   want = 0;
-  if (pos != NULL)
+  if (fah.result != NULL)
     {
     {
-      hs = GNUNET_HELLO_size (pos->hello);
-      if (hs < size)
-       {
-         want = hs;
-         memcpy (buf, pos->hello, want);
-         GNUNET_CONTAINER_bloomfilter_add (pos->filter,
-                                           &pl->id.hashPubKey);
+      want = GNUNET_HELLO_size (fah.result->hello);
+      GNUNET_assert (want <= size);
+      memcpy (buf, fah.result->hello, want);
+      GNUNET_CONTAINER_bloomfilter_add (fah.result->filter,
+                                       &pl->pid.hashPubKey);
 #if DEBUG_TOPOLOGY
 #if DEBUG_TOPOLOGY
-         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                     "Sending %u bytes of `%s's",
-                     (unsigned int) want,
-                     "HELLO");
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                 "Sending `%s' with %u bytes",
+                 "HELLO",
+                 (unsigned int) want);
 #endif         
 #endif         
-         GNUNET_STATISTICS_update (stats,
-                                   gettext_noop ("# HELLO messages gossipped"),
-                                   1,
-                                   GNUNET_NO);
-       }
+      GNUNET_STATISTICS_update (stats,
+                               gettext_noop ("# HELLO messages gossipped"),
+                               1,
+                               GNUNET_NO);    
     }
   pl->next_hello_allowed = GNUNET_TIME_relative_to_absolute (HELLO_ADVERTISEMENT_MIN_FREQUENCY);
   pl->hello_delay_task 
     }
   pl->next_hello_allowed = GNUNET_TIME_relative_to_absolute (HELLO_ADVERTISEMENT_MIN_FREQUENCY);
   pl->hello_delay_task 
-    = GNUNET_SCHEDULER_add_now (sched,
-                               &schedule_next_hello,
+    = GNUNET_SCHEDULER_add_now (&schedule_next_hello,
                                pl);
   return want;
 }
                                pl);
   return want;
 }
@@ -1301,12 +1281,14 @@ hello_advertising_ready (void *cls,
 /**
  * Last task run during shutdown.  Disconnects us from
  * the transport and core.
 /**
  * Last task run during shutdown.  Disconnects us from
  * the transport and core.
+ *
+ * @param cls unused, NULL
+ * @param tc scheduler context
  */
 static void
  */
 static void
-cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+cleaning_task (void *cls, 
+              const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
 {
-  struct DisconnectList *dl;
-
   if (NULL != peerinfo_notify)
     {
       GNUNET_PEERINFO_notify_cancel (peerinfo_notify);
   if (NULL != peerinfo_notify)
     {
       GNUNET_PEERINFO_notify_cancel (peerinfo_notify);
@@ -1314,21 +1296,16 @@ cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
     }
   GNUNET_TRANSPORT_disconnect (transport);
   transport = NULL;
     }
   GNUNET_TRANSPORT_disconnect (transport);
   transport = NULL;
-  while (NULL != peers)
-    free_peer (peers);     
+  GNUNET_CONTAINER_multihashmap_iterate (peers,
+                                        &free_peer,
+                                        NULL);
+  GNUNET_CONTAINER_multihashmap_destroy (peers);
   if (handle != NULL)
     {
       GNUNET_CORE_disconnect (handle);
       handle = NULL;
     }
   if (handle != NULL)
     {
       GNUNET_CORE_disconnect (handle);
       handle = NULL;
     }
-  while (NULL != (dl = disconnect_head))
-    {
-      GNUNET_CONTAINER_DLL_remove (disconnect_head,
-                                  disconnect_tail,
-                                  dl);
-      GNUNET_TRANSPORT_blacklist_cancel (dl->rh);
-      GNUNET_free (dl);
-    }
+  whitelist_peers ();
   if (stats != NULL)
     {
       GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
   if (stats != NULL)
     {
       GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
@@ -1341,14 +1318,12 @@ cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  * Main function that will be run.
  *
  * @param cls closure
  * Main function that will be run.
  *
  * @param cls closure
- * @param s the scheduler to use
  * @param args remaining command-line arguments
  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
  * @param c configuration
  */
 static void
 run (void *cls,
  * @param args remaining command-line arguments
  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
  * @param c configuration
  */
 static void
 run (void *cls,
-     struct GNUNET_SCHEDULER_Handle * s,
      char *const *args,
      const char *cfgfile,
      const struct GNUNET_CONFIGURATION_Handle * c)
      char *const *args,
      const char *cfgfile,
      const struct GNUNET_CONFIGURATION_Handle * c)
@@ -1360,9 +1335,8 @@ run (void *cls,
     };
   unsigned long long opt;
 
     };
   unsigned long long opt;
 
-  sched = s;
   cfg = c;
   cfg = c;
-  stats = GNUNET_STATISTICS_create (sched, "topology", cfg);
+  stats = GNUNET_STATISTICS_create ("topology", cfg);
   autoconnect = GNUNET_CONFIGURATION_get_value_yesno (cfg,
                                                      "TOPOLOGY",
                                                      "AUTOCONNECT");
   autoconnect = GNUNET_CONFIGURATION_get_value_yesno (cfg,
                                                      "TOPOLOGY",
                                                      "AUTOCONNECT");
@@ -1383,6 +1357,7 @@ run (void *cls,
                                             &opt))
     opt = 16;
   target_connection_count = (unsigned int) opt;
                                             &opt))
     opt = 16;
   target_connection_count = (unsigned int) opt;
+  peers = GNUNET_CONTAINER_multihashmap_create (target_connection_count * 2);
 
   if ( (friends_only == GNUNET_YES) ||
        (minimum_friend_count > 0) )
 
   if ( (friends_only == GNUNET_YES) ||
        (minimum_friend_count > 0) )
@@ -1394,32 +1369,33 @@ run (void *cls,
              minimum_friend_count,
              autoconnect ? "autoconnect enabled" : "autoconnect disabled");
 #endif       
              minimum_friend_count,
              autoconnect ? "autoconnect enabled" : "autoconnect disabled");
 #endif       
-  transport = GNUNET_TRANSPORT_connect (sched,
-                                       cfg,
+  if (friend_count < minimum_friend_count) 
+    blacklist = GNUNET_TRANSPORT_blacklist (cfg,
+                                           &blacklist_check, NULL);
+  transport = GNUNET_TRANSPORT_connect (cfg,
+                                       NULL,
                                        NULL,
                                        NULL,
                                        NULL,
                                        NULL);
                                        NULL,
                                        NULL,
                                        NULL,
                                        NULL);
-  handle = GNUNET_CORE_connect (sched,
-                               cfg,
-                               GNUNET_TIME_UNIT_FOREVER_REL,
+  handle = GNUNET_CORE_connect (cfg,
+                               1,
                                NULL,
                                &core_init,
                                NULL,
                                &core_init,
-                               NULL,
                                &connect_notify,
                                &connect_notify,
-                               &disconnect_notify,
+                               &disconnect_notify, 
+                               NULL,
                                NULL, GNUNET_NO,
                                NULL, GNUNET_NO,
                                handlers);
                                NULL, GNUNET_NO,
                                NULL, GNUNET_NO,
                                handlers);
-  GNUNET_SCHEDULER_add_delayed (sched,
-                                GNUNET_TIME_UNIT_FOREVER_REL,
+  GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
                                 &cleaning_task, NULL);
   if (NULL == transport)
     {
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                  _("Failed to connect to `%s' service.\n"),
                  "transport");
                                 &cleaning_task, NULL);
   if (NULL == transport)
     {
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                  _("Failed to connect to `%s' service.\n"),
                  "transport");
-      GNUNET_SCHEDULER_shutdown (sched);
+      GNUNET_SCHEDULER_shutdown ();
       return;
     }
   if (NULL == handle)
       return;
     }
   if (NULL == handle)
@@ -1427,20 +1403,12 @@ run (void *cls,
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                  _("Failed to connect to `%s' service.\n"),
                  "core");
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                  _("Failed to connect to `%s' service.\n"),
                  "core");
-      GNUNET_SCHEDULER_shutdown (sched);
+      GNUNET_SCHEDULER_shutdown ();
       return;
     }
 }
 
 
       return;
     }
 }
 
 
-/**
- * gnunet-daemon-topology command line options.
- */
-static struct GNUNET_GETOPT_CommandLineOption options[] = {
-  GNUNET_GETOPT_OPTION_END
-};
-
-
 /**
  * The main function for the topology daemon.
  *
 /**
  * The main function for the topology daemon.
  *
@@ -1451,6 +1419,9 @@ static struct GNUNET_GETOPT_CommandLineOption options[] = {
 int
 main (int argc, char *const *argv)
 {
 int
 main (int argc, char *const *argv)
 {
+  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
+    GNUNET_GETOPT_OPTION_END
+  };
   int ret;
 
   ret = (GNUNET_OK ==
   int ret;
 
   ret = (GNUNET_OK ==