use new SCHEDULER_add_at API where applicable
[oweals/gnunet.git] / src / topology / gnunet-daemon-topology.c
index 8c31fea58b0124ffddbe0a149cef1c630349a7fe..067ebce238890b34cbaffd2abb3c3890065bea5c 100644 (file)
@@ -1,10 +1,10 @@
 /*
      This file is part of GNUnet.
 /*
      This file is part of GNUnet.
-     (C) 2007, 2008, 2009, 2010 Christian Grothoff (and other contributing authors)
+     Copyright (C) 2007-2016 GNUnet e.V.
 
      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
 
      You should have received a copy of the GNU General Public License
      along with GNUnet; see the file COPYING.  If not, write to the
 
      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.
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
 */
 
 /**
  * @file topology/gnunet-daemon-topology.c
 */
 
 /**
  * @file topology/gnunet-daemon-topology.c
- * @brief code for maintaining the mesh topology
+ * @brief code for maintaining the overlay topology
  * @author Christian Grothoff
  * @author Christian Grothoff
+ *
+ * This daemon combines three functions:
+ * - suggesting to ATS which peers we might want to connect to
+ * - enforcing the F2F restrictions (by blacklisting)
+ * - gossping HELLOs
+ *
+ * All three require similar information (who are our friends
+ * impacts connectivity suggestions; connectivity suggestions
+ * should consider blacklisting; connectivity suggestions
+ * should consider available/known HELLOs; gossip requires
+ * connectivity data; connectivity suggestions require
+ * connectivity data), which is why they are combined in this
+ * program.
  */
  */
-
-#include <stdlib.h>
 #include "platform.h"
 #include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_friends_lib.h"
 #include "gnunet_constants.h"
 #include "gnunet_core_service.h"
 #include "gnunet_protocols.h"
 #include "gnunet_peerinfo_service.h"
 #include "gnunet_statistics_service.h"
 #include "gnunet_transport_service.h"
 #include "gnunet_constants.h"
 #include "gnunet_core_service.h"
 #include "gnunet_protocols.h"
 #include "gnunet_peerinfo_service.h"
 #include "gnunet_statistics_service.h"
 #include "gnunet_transport_service.h"
-#include "gnunet_util_lib.h"
+#include "gnunet_ats_service.h"
 
 
 
 
-#define DEBUG_TOPOLOGY GNUNET_NO
-
 /**
 /**
- * For how long do we blacklist a peer after a failed connection
- * attempt?
+ * At what frequency do we sent HELLOs to a peer?
  */
  */
-#define GREYLIST_AFTER_ATTEMPT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
+#define HELLO_ADVERTISEMENT_MIN_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
 
 /**
 
 /**
- * For how long do we blacklist a friend after a failed connection
- * attempt?
- */
-#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, 18)
-
-/**
- * How often do we at most advertise any HELLO to a peer?
- */
-#define HELLO_ADVERTISEMENT_MIN_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
-
-/**
- * How often do we at most advertise the same HELLO to the same peer?
+ * After what time period do we expire the HELLO Bloom filter?
  */
 #define HELLO_ADVERTISEMENT_MIN_REPEAT_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
 
  */
 #define HELLO_ADVERTISEMENT_MIN_REPEAT_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
 
@@ -83,16 +70,10 @@ struct Peer
   struct GNUNET_PeerIdentity pid;
 
   /**
   struct GNUNET_PeerIdentity pid;
 
   /**
-   * Our handle for the request to transmit HELLOs to this peer; NULL
-   * if no such request is pending.
+   * Our handle for transmitting to this peer; NULL
+   * if peer is not connected.
    */
    */
-  struct GNUNET_CORE_TransmitHandle *hello_req;  
-
-  /**
-   * Our handle for the request to connect to this peer; NULL if no
-   * such request is pending.
-   */
-  struct GNUNET_CORE_PeerRequestHandle *connect_req;  
+  struct GNUNET_MQ_Handle *mq;
 
   /**
    * Pointer to the HELLO message of this peer; can be NULL.
 
   /**
    * Pointer to the HELLO message of this peer; can be NULL.
@@ -105,12 +86,6 @@ struct Peer
    */
   struct GNUNET_CONTAINER_BloomFilter *filter;
 
    */
   struct GNUNET_CONTAINER_BloomFilter *filter;
 
-  /**
-   * Until what time should we not try to connect again
-   * to this peer?
-   */
-  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?
    */
@@ -125,28 +100,23 @@ struct Peer
    * ID of task we use to wait for the time to send the next HELLO
    * to this peer.
    */
    * ID of task we use to wait for the time to send the next HELLO
    * to this peer.
    */
-  GNUNET_SCHEDULER_TaskIdentifier hello_delay_task;
+  struct GNUNET_SCHEDULER_Task *hello_delay_task;
 
   /**
 
   /**
-   * ID of task we use to clear peers from the greylist.
+   * Handle for our connectivity suggestion for this peer.
    */
    */
-  GNUNET_SCHEDULER_TaskIdentifier greylist_clean_task;
+  struct GNUNET_ATS_ConnectivitySuggestHandle *sh;
 
   /**
 
   /**
-   * How often have we tried so far?
+   * How much would we like to connect to this peer?
    */
    */
-  unsigned int connect_attempts;
+  uint32_t strength;
 
   /**
    * Is this peer listed here because he is a friend?
    */
   int is_friend;
 
 
   /**
    * Is this peer listed here because he is a friend?
    */
   int is_friend;
 
-  /**
-   * Are we connected to this peer right now?
-   */
-  int is_connected;
-
 };
 
 
 };
 
 
@@ -156,25 +126,20 @@ struct Peer
  */
 static struct GNUNET_PEERINFO_NotifyContext *peerinfo_notify;
 
  */
 static struct GNUNET_PEERINFO_NotifyContext *peerinfo_notify;
 
-/**
- * Our scheduler.
- */
-static struct GNUNET_SCHEDULER_Handle *sched;
-
 /**
  * Our configuration.
  */
 static const struct GNUNET_CONFIGURATION_Handle *cfg;
 
 /**
 /**
  * Our configuration.
  */
 static const struct GNUNET_CONFIGURATION_Handle *cfg;
 
 /**
- * Handle to the core API.
+ * Handle to the CORE service.
  */
 static struct GNUNET_CORE_Handle *handle;
 
 /**
  */
 static struct GNUNET_CORE_Handle *handle;
 
 /**
- * Handle to the transport API.
+ * Handle to the ATS service.
  */
  */
-static struct GNUNET_TRANSPORT_Handle *transport;
+static struct GNUNET_ATS_ConnectivityHandle *ats;
 
 /**
  * Identity of this peer.
 
 /**
  * Identity of this peer.
@@ -184,9 +149,9 @@ static struct GNUNET_PeerIdentity my_identity;
 /**
  * All of our friends, all of our current neighbours and all peers for
  * which we have HELLOs.  So pretty much everyone.  Maps peer identities
 /**
  * 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.
+ * to `struct Peer *` values.
  */
  */
-static struct GNUNET_CONTAINER_MultiHashMap *peers;
+static struct GNUNET_CONTAINER_MultiPeerMap *peers;
 
 /**
  * Handle for reporting statistics.
 
 /**
  * Handle for reporting statistics.
@@ -198,6 +163,17 @@ static struct GNUNET_STATISTICS_Handle *stats;
  */
 static struct GNUNET_TRANSPORT_Blacklist *blacklist;
 
  */
 static struct GNUNET_TRANSPORT_Blacklist *blacklist;
 
+/**
+ * Task scheduled to asynchronously reconsider adding/removing
+ * peer connectivity suggestions.
+ */
+static struct GNUNET_SCHEDULER_Task *add_task;
+
+/**
+ * Active HELLO offering to transport service.
+ */
+static struct GNUNET_TRANSPORT_OfferHelloHandle *oh;
+
 /**
  * Flag to disallow non-friend connections (pure F2F mode).
  */
 /**
  * Flag to disallow non-friend connections (pure F2F mode).
  */
@@ -224,35 +200,31 @@ static unsigned int target_connection_count;
  */
 static unsigned int friend_count;
 
  */
 static unsigned int friend_count;
 
-/**
- * Should the topology daemon try to establish connections?
- */
-static int autoconnect;
-
 
 /**
 
 /**
- * Function that decides if a connection is acceptable or not.  
+ * 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 closure
  * If we have a blacklist, only friends are allowed, so the check
  * is rather simple.
  *
  * @param cls closure
- * @param pid peer to approve or disapproave
- * @return GNUNET_OK if the connection is allowed
+ * @param pid peer to approve or disapprove
+ * @return #GNUNET_OK if the connection is allowed
  */
 static int
 blacklist_check (void *cls,
  */
 static int
 blacklist_check (void *cls,
-                const struct GNUNET_PeerIdentity *pid)
+                 const struct GNUNET_PeerIdentity *pid)
 {
   struct Peer *pos;
 
 {
   struct Peer *pos;
 
-  pos = GNUNET_CONTAINER_multihashmap_get (peers, &pid->hashPubKey);
-  if ( (pos != NULL) &&
-       (pos->is_friend == GNUNET_YES) )
+  pos = GNUNET_CONTAINER_multipeermap_get (peers,
+                                           pid);
+  if ( (NULL != pos) &&
+       (GNUNET_YES == pos->is_friend))
     return GNUNET_OK;
   GNUNET_STATISTICS_update (stats,
     return GNUNET_OK;
   GNUNET_STATISTICS_update (stats,
-                           gettext_noop ("# peers blacklisted"),
-                           1,
-                           GNUNET_NO);
+                            gettext_noop ("# peers blacklisted"),
+                            1,
+                            GNUNET_NO);
   return GNUNET_SYSERR;
 }
 
   return GNUNET_SYSERR;
 }
 
@@ -264,62 +236,11 @@ blacklist_check (void *cls,
 static void
 whitelist_peers ()
 {
 static void
 whitelist_peers ()
 {
-  if (blacklist != NULL)
-    {
-      GNUNET_TRANSPORT_blacklist_cancel (blacklist);
-      blacklist = NULL;
-    }
-}
-
-
-/**
- * Function called by core when our attempt to connect succeeded.
- *
- * @param cls the 'struct Peer' for which we issued the connect request
- * @param tc scheduler context
- */
-static void
-connect_completed_callback (void *cls,
-                           const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
-  struct Peer *pos = cls;
-
-  pos->connect_req = NULL;
-}
-
-
-/**
- * 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 int
-is_connection_allowed (struct Peer *peer)
-{
-  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 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;
+  if (NULL != blacklist)
+  {
+    GNUNET_TRANSPORT_blacklist_cancel (blacklist);
+    blacklist = NULL;
+  }
 }
 
 
 }
 
 
@@ -329,141 +250,99 @@ is_connection_allowed (struct Peer *peer)
  * @param cls closure (not used)
  * @param pid identity of the peer
  * @param value peer to free
  * @param cls closure (not used)
  * @param pid identity of the peer
  * @param value peer to free
- * @return GNUNET_YES (always: continue to iterate)
+ * @return #GNUNET_YES (always: continue to iterate)
  */
 static int
 free_peer (void *cls,
  */
 static int
 free_peer (void *cls,
-          const GNUNET_HashCode *pid,
-          void *value)
+           const struct GNUNET_PeerIdentity * pid,
+           void *value)
 {
   struct Peer *pos = value;
 
 {
   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 (sched,
-                            pos->hello_delay_task);
-  if (pos->greylist_clean_task != GNUNET_SCHEDULER_NO_TASK)
-    GNUNET_SCHEDULER_cancel (sched,
-                            pos->greylist_clean_task);
-  GNUNET_free_non_null (pos->hello);   
-  if (pos->filter != NULL)
+  GNUNET_break (NULL == pos->mq);
+  GNUNET_break (GNUNET_OK ==
+                GNUNET_CONTAINER_multipeermap_remove (peers,
+                                                      pid,
+                                                      pos));
+  if (NULL != pos->hello_delay_task)
+  {
+    GNUNET_SCHEDULER_cancel (pos->hello_delay_task);
+    pos->hello_delay_task = NULL;
+  }
+  if (NULL != pos->sh)
+  {
+    GNUNET_ATS_connectivity_suggest_cancel (pos->sh);
+    pos->sh = NULL;
+  }
+  if (NULL != pos->hello)
+  {
+    GNUNET_free_non_null (pos->hello);
+    pos->hello = NULL;
+  }
+  if (NULL != pos->filter)
+  {
     GNUNET_CONTAINER_bloomfilter_free (pos->filter);
     GNUNET_CONTAINER_bloomfilter_free (pos->filter);
+    pos->filter = NULL;
+  }
   GNUNET_free (pos);
   return GNUNET_YES;
 }
 
 
 /**
   GNUNET_free (pos);
   return GNUNET_YES;
 }
 
 
 /**
- * Discard peer entries for greylisted peers
- * where the greylisting has expired.
+ * Recalculate how much we want to be connected to the specified peer
+ * and let ATS know about the result.
  *
  *
- * @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
+ * @param pos peer to consider connecting to
  */
 static void
 attempt_connect (struct Peer *pos)
 {
  */
 static void
 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).value > 0)
-    return;
-  if (GNUNET_YES == pos->is_friend)
-    rem = GREYLIST_AFTER_ATTEMPT_FRIEND;
-  else
-    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 (sched,
-                            pos->greylist_clean_task);
-  pos->greylist_clean_task 
-    = GNUNET_SCHEDULER_add_delayed (sched,
-                                   rem,
-                                   &remove_from_greylist,
-                                   pos);
-#if DEBUG_TOPOLOGY
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "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);
-  pos->connect_req = GNUNET_CORE_peer_request_connect (sched, cfg,
-                                                      GNUNET_TIME_UNIT_MINUTES,
-                                                      &pos->pid,
-                                                      &connect_completed_callback,
-                                                      pos);
-}
-
-
-/**
- * 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)
-{
-  struct Peer *pos = cls;
-  struct GNUNET_TIME_Relative rem;
-
-  pos->greylist_clean_task = GNUNET_SCHEDULER_NO_TASK;
-  rem = GNUNET_TIME_absolute_get_remaining (pos->greylisted_until);
-  if (rem.value == 0)
-    {
-      attempt_connect (pos);
-    }
+  uint32_t strength;
+
+  if (0 ==
+      memcmp (&my_identity,
+              &pos->pid,
+              sizeof (struct GNUNET_PeerIdentity)))
+    return; /* This is myself, nothing to do. */
+  if (connection_count < target_connection_count)
+    strength = 1;
   else
   else
-    {
-      pos->greylist_clean_task 
-       = GNUNET_SCHEDULER_add_delayed (sched,
-                                       rem,
-                                       &remove_from_greylist,
-                                       pos);
-    }
-  if ( (GNUNET_NO == pos->is_friend) &&
-       (GNUNET_NO == pos->is_connected) )
-    {
-      free_peer (NULL, &pos->pid.hashPubKey, pos);
-      return;
-    }
+    strength = 0;
+  if ( (friend_count < minimum_friend_count) ||
+       (GNUNET_YES == friends_only) )
+  {
+    if (pos->is_friend)
+      strength += 10; /* urgently needed */
+    else
+      strength = 0; /* disallowed */
+  }
+  if (pos->is_friend)
+    strength *= 2; /* friends always count more */
+  if (NULL != pos->mq)
+    strength *= 2; /* existing connections preferred */
+  if (strength == pos->strength)
+    return; /* nothing to do */
+  if (NULL != pos->sh)
+  {
+    GNUNET_ATS_connectivity_suggest_cancel (pos->sh);
+    pos->sh = NULL;
+  }
+  pos->strength = strength;
+  if (0 != strength)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Asking to connect to `%s' with strength %u\n",
+                GNUNET_i2s (&pos->pid),
+                (unsigned int) strength);
+    GNUNET_STATISTICS_update (stats,
+                              gettext_noop ("# connect requests issued to ATS"),
+                              1,
+                              GNUNET_NO);
+    pos->sh = GNUNET_ATS_connectivity_suggest (ats,
+                                               &pos->pid,
+                                               strength);
+  }
 }
 
 
 }
 
 
@@ -476,27 +355,27 @@ remove_from_greylist (void *cls,
  * @return the new entry
  */
 static struct Peer *
  * @return the new entry
  */
 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 Peer *ret;
 {
   struct Peer *ret;
-  
-  ret = GNUNET_malloc (sizeof (struct Peer));
+
+  ret = GNUNET_new (struct Peer);
   ret->pid = *peer;
   ret->is_friend = is_friend;
   ret->pid = *peer;
   ret->is_friend = is_friend;
-  if (hello != NULL)
-    {
-      ret->hello = GNUNET_malloc (GNUNET_HELLO_size (hello));
-      memcpy (ret->hello, hello,
-             GNUNET_HELLO_size (hello));
-    }
+  if (NULL != hello)
+  {
+    ret->hello = GNUNET_malloc (GNUNET_HELLO_size (hello));
+    GNUNET_memcpy (ret->hello,
+                  hello,
+                  GNUNET_HELLO_size (hello));
+  }
   GNUNET_break (GNUNET_OK ==
   GNUNET_break (GNUNET_OK ==
-               GNUNET_CONTAINER_multihashmap_put (peers,
-                                                  &peer->hashPubKey,
-                                                  ret,
-                                                  GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+                GNUNET_CONTAINER_multipeermap_put (peers,
+                                                   peer,
+                                                   ret,
+                                                   GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
   return ret;
 }
 
   return ret;
 }
 
@@ -509,40 +388,32 @@ make_peer (const struct
 static void
 setup_filter (struct Peer *peer)
 {
 static void
 setup_filter (struct Peer *peer)
 {
+  struct GNUNET_HashCode hc;
+
   /* 2^{-5} chance of not sending a HELLO to a peer is
   /* 2^{-5} chance of not sending a HELLO to a peer is
-     acceptably small (if the filter is 50% full);
-     64 bytes of memory are small compared to the rest
-     of the data structure and would only really become
-     "useless" once a HELLO has been passed on to ~100
-     other peers, which is likely more than enough in
-     any case; hence 64, 5 as bloomfilter parameters. */
-  peer->filter = GNUNET_CONTAINER_bloomfilter_load (NULL, 64, 5);
-  peer->filter_expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADVERTISEMENT_MIN_REPEAT_FREQUENCY);
+   * acceptably small (if the filter is 50% full);
+   * 64 bytes of memory are small compared to the rest
+   * of the data structure and would only really become
+   * "useless" once a HELLO has been passed on to ~100
+   * other peers, which is likely more than enough in
+   * any case; hence 64, 5 as bloomfilter parameters. */
+  peer->filter = GNUNET_CONTAINER_bloomfilter_init (NULL, 64, 5);
+  peer->filter_expiration =
+      GNUNET_TIME_relative_to_absolute
+      (HELLO_ADVERTISEMENT_MIN_REPEAT_FREQUENCY);
   /* never send a peer its own HELLO */
   /* never send a peer its own HELLO */
-  GNUNET_CONTAINER_bloomfilter_add (peer->filter, &peer->pid.hashPubKey);
+  GNUNET_CRYPTO_hash (&peer->pid,
+                      sizeof (struct GNUNET_PeerIdentity),
+                      &hc);
+  GNUNET_CONTAINER_bloomfilter_add (peer->filter, &hc);
 }
 
 
 /**
 }
 
 
 /**
- * Function to fill send buffer with HELLO.
- *
- * @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
+ * Closure for #find_advertisable_hello().
  */
  */
-static size_t
-hello_advertising_ready (void *cls,
-                        size_t size,
-                        void *buf);
-
-
-
-
-/**
- * Closure for 'find_advertisable_hello'.
- */
-struct FindAdvHelloContext {
+struct FindAdvHelloContext
+{
 
   /**
    * Peer we want to advertise to.
 
   /**
    * Peer we want to advertise to.
@@ -568,17 +439,18 @@ struct FindAdvHelloContext {
  *
  * @param cls closure
  * @param pid identity of a peer
  *
  * @param cls closure
  * @param pid identity of a peer
- * @param value 'struct Peer*' for the peer we are considering 
- * @return GNUNET_YES (continue iteration)
+ * @param value 'struct Peer*' for the peer we are considering
+ * @return #GNUNET_YES (continue iteration)
  */
 static int
 find_advertisable_hello (void *cls,
  */
 static int
 find_advertisable_hello (void *cls,
-                        const GNUNET_HashCode *pid,
-                        void *value)
+                         const struct GNUNET_PeerIdentity *pid,
+                         void *value)
 {
   struct FindAdvHelloContext *fah = cls;
   struct Peer *pos = value;
   struct GNUNET_TIME_Relative rst_time;
 {
   struct FindAdvHelloContext *fah = cls;
   struct Peer *pos = value;
   struct GNUNET_TIME_Relative rst_time;
+  struct GNUNET_HashCode hc;
   size_t hs;
 
   if (pos == fah->peer)
   size_t hs;
 
   if (pos == fah->peer)
@@ -586,21 +458,22 @@ find_advertisable_hello (void *cls,
   if (pos->hello == NULL)
     return GNUNET_YES;
   rst_time = GNUNET_TIME_absolute_get_remaining (pos->filter_expiration);
   if (pos->hello == NULL)
     return GNUNET_YES;
   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);
-    }
-  fah->next_adv = GNUNET_TIME_relative_min (rst_time,
-                                           fah->next_adv);
+  if (0 == rst_time.rel_value_us)
+  {
+    /* 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;
   hs = GNUNET_HELLO_size (pos->hello);
   if (hs > fah->max_size)
     return GNUNET_YES;
+  GNUNET_CRYPTO_hash (&fah->peer->pid,
+                     sizeof (struct GNUNET_PeerIdentity), &hc);
   if (GNUNET_NO ==
       GNUNET_CONTAINER_bloomfilter_test (pos->filter,
   if (GNUNET_NO ==
       GNUNET_CONTAINER_bloomfilter_test (pos->filter,
-                                        &fah->peer->pid.hashPubKey))
-    fah->result = pos;    
+                                         &hc))
+    fah->result = pos;
   return GNUNET_YES;
 }
 
   return GNUNET_YES;
 }
 
@@ -610,50 +483,64 @@ find_advertisable_hello (void *cls,
  * peer and ask for it.
  *
  * @param cls for which peer to schedule the HELLO
  * peer and ask for it.
  *
  * @param cls for which peer to schedule the HELLO
- * @param tc task context
  */
 static void
  */
 static void
-schedule_next_hello (void *cls,
-                    const struct GNUNET_SCHEDULER_TaskContext *tc)
+schedule_next_hello (void *cls)
 {
   struct Peer *pl = cls;
   struct FindAdvHelloContext fah;
 {
   struct Peer *pl = cls;
   struct FindAdvHelloContext fah;
-  size_t next_want;
+  struct GNUNET_MQ_Envelope *env;
+  size_t want;
   struct GNUNET_TIME_Relative delay;
   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 */
-  if (pl->hello_req != NULL)
-    return; /* did not finish sending the previous one */
+  struct GNUNET_HashCode hc;
+
+  pl->hello_delay_task = NULL;
+  GNUNET_assert (NULL != pl->mq);
   /* find applicable HELLOs */
   fah.peer = pl;
   fah.result = NULL;
   /* find applicable HELLOs */
   fah.peer = pl;
   fah.result = NULL;
-  fah.max_size = GNUNET_SERVER_MAX_MESSAGE_SIZE;
+  fah.max_size = GNUNET_SERVER_MAX_MESSAGE_SIZE - 1;
   fah.next_adv = GNUNET_TIME_UNIT_FOREVER_REL;
   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 (sched,
-                                   fah.next_adv,
-                                   &schedule_next_hello,
-                                   pl);
-  if (fah.result == NULL)
-    return;   
-  next_want = GNUNET_HELLO_size (fah.result->hello);
+  GNUNET_CONTAINER_multipeermap_iterate (peers,
+                                         &find_advertisable_hello,
+                                         &fah);
+  pl->hello_delay_task =
+      GNUNET_SCHEDULER_add_delayed (fah.next_adv,
+                                    &schedule_next_hello,
+                                    pl);
+  if (NULL == fah.result)
+    return;
   delay = GNUNET_TIME_absolute_get_remaining (pl->next_hello_allowed);
   delay = GNUNET_TIME_absolute_get_remaining (pl->next_hello_allowed);
-  if (delay.value == 0)
-    {
-      /* now! */
-      pl->hello_req = GNUNET_CORE_notify_transmit_ready (handle, 0,
-                                                        GNUNET_CONSTANTS_SERVICE_TIMEOUT,
-                                                        &pl->pid,
-                                                        next_want,
-                                                        &hello_advertising_ready,
-                                                        pl);
-      return;
-    }
+  if (0 != delay.rel_value_us)
+    return;
+
+  want = GNUNET_HELLO_size (fah.result->hello);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Sending HELLO with %u bytes",
+             (unsigned int) want);
+  env = GNUNET_MQ_msg_copy (&fah.result->hello->header);
+  GNUNET_MQ_send (pl->mq,
+                 env);
+
+  /* avoid sending this one again soon */
+  GNUNET_CRYPTO_hash (&pl->pid,
+                     sizeof (struct GNUNET_PeerIdentity),
+                     &hc);
+  GNUNET_CONTAINER_bloomfilter_add (fah.result->filter,
+                                   &hc);
+
+  GNUNET_STATISTICS_update (stats,
+                           gettext_noop ("# HELLO messages gossipped"),
+                           1,
+                           GNUNET_NO);
+  /* prepare to send the next one */
+  pl->next_hello_allowed
+    = GNUNET_TIME_relative_to_absolute (HELLO_ADVERTISEMENT_MIN_FREQUENCY);
+  if (NULL != pl->hello_delay_task)
+    GNUNET_SCHEDULER_cancel (pl->hello_delay_task);
+  pl->hello_delay_task
+    = GNUNET_SCHEDULER_add_now (&schedule_next_hello,
+                               pl);
 }
 
 
 }
 
 
@@ -662,38 +549,30 @@ schedule_next_hello (void *cls,
  * and recalculate when we should send HELLOs to it based
  * on our current state (something changed!).
  *
  * 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 cls closure `struct Peer` to skip, or NULL
  * @param pid identity of a peer
  * @param pid identity of a peer
- * @param value 'struct Peer*' for the peer
- * @return GNUNET_YES (always)
+ * @param value `struct Peer *` for the peer
+ * @return #GNUNET_YES (always)
  */
 static int
 reschedule_hellos (void *cls,
  */
 static int
 reschedule_hellos (void *cls,
-                  const GNUNET_HashCode *pid,
-                  void *value)
+                   const struct GNUNET_PeerIdentity *pid,
+                   void *value)
 {
   struct Peer *peer = value;
   struct Peer *skip = cls;
 
   if (skip == peer)
     return GNUNET_YES;
 {
   struct Peer *peer = value;
   struct Peer *skip = cls;
 
   if (skip == peer)
     return GNUNET_YES;
-  if (! peer->is_connected) 
+  if (NULL == peer->mq)
     return GNUNET_YES;
     return GNUNET_YES;
-  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 (NULL != peer->hello_delay_task)
+  {
+    GNUNET_SCHEDULER_cancel (peer->hello_delay_task);
+    peer->hello_delay_task = NULL;
+  }
+  peer->hello_delay_task =
+      GNUNET_SCHEDULER_add_now (&schedule_next_hello, peer);
   return GNUNET_YES;
 }
 
   return GNUNET_YES;
 }
 
@@ -703,53 +582,64 @@ reschedule_hellos (void *cls,
  *
  * @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 mq message queue for communicating with @a peer
+ * @return our `struct Peer` for @a peer
  */
  */
-static void 
+static void *
 connect_notify (void *cls,
 connect_notify (void *cls,
-               const struct
-               GNUNET_PeerIdentity * peer,
-               struct GNUNET_TIME_Relative latency,
-               uint32_t distance)
+                const struct GNUNET_PeerIdentity *peer,
+               struct GNUNET_MQ_Handle *mq)
 {
   struct Peer *pos;
 {
   struct Peer *pos;
+  uint64_t flags;
+  const void *extra;
 
 
-#if DEBUG_TOPOLOGY
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Core told us that we are connecting to `%s'\n",
-             GNUNET_i2s (peer));
-#endif
+              "Core told us that we are connecting to `%s'\n",
+              GNUNET_i2s (peer));
+  if (0 == memcmp (&my_identity,
+                   peer,
+                   sizeof (struct GNUNET_PeerIdentity)))
+    return NULL;
+  extra = GNUNET_CORE_get_mq_options (GNUNET_YES,
+                                     GNUNET_CORE_PRIO_BEST_EFFORT,
+                                     &flags);
+  GNUNET_MQ_set_options (mq,
+                        flags,
+                        extra);
   connection_count++;
   GNUNET_STATISTICS_set (stats,
   connection_count++;
   GNUNET_STATISTICS_set (stats,
-                        gettext_noop ("# peers connected"),
-                        connection_count,
-                        GNUNET_NO);
-  pos = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey);
-  if (pos == NULL)    
-    {
-      pos = make_peer (peer, NULL, GNUNET_NO);
-      GNUNET_break (GNUNET_OK == is_connection_allowed (pos));
-    }
+                         gettext_noop ("# peers connected"),
+                         connection_count,
+                         GNUNET_NO);
+  pos = GNUNET_CONTAINER_multipeermap_get (peers,
+                                           peer);
+  if (NULL == pos)
+  {
+    pos = make_peer (peer,
+                     NULL,
+                     GNUNET_NO);
+  }
   else
   else
-    {
-      GNUNET_assert (GNUNET_NO == pos->is_connected);
-      pos->greylisted_until.value = 0; /* remove greylisting */
-    }
-  pos->is_connected = GNUNET_YES;
-  pos->connect_attempts = 0; /* re-set back-off factor */
+  {
+    GNUNET_assert (NULL == pos->mq);
+  }
+  pos->mq = mq;
   if (pos->is_friend)
   if (pos->is_friend)
-    {
-      if ( (friend_count == minimum_friend_count - 1) &&
-          (GNUNET_YES != friends_only) )       
-       whitelist_peers ();       
-      friend_count++;
-      GNUNET_STATISTICS_set (stats,
-                            gettext_noop ("# friends connected"),
-                            connection_count,
-                            GNUNET_NO);
-    }
-  reschedule_hellos (NULL, &peer->hashPubKey, pos);
+  {
+    friend_count++;
+    if ( (friend_count == minimum_friend_count) &&
+         (GNUNET_YES != friends_only) )
+      whitelist_peers ();
+    GNUNET_STATISTICS_set (stats,
+                           gettext_noop ("# friends connected"),
+                           friend_count,
+                           GNUNET_NO);
+  }
+  reschedule_hellos (NULL,
+                     peer,
+                     pos);
+  return pos;
 }
 
 
 }
 
 
@@ -758,13 +648,13 @@ connect_notify (void *cls,
  *
  * @param cls closure, not used
  * @param pid identity of a peer
  *
  * @param cls closure, not used
  * @param pid identity of a peer
- * @param value 'struct Peer*' for the peer
- * @return GNUNET_YES (continue to iterate)
+ * @param value `struct Peer *` for the peer
+ * @return #GNUNET_YES (continue to iterate)
  */
 static int
 try_add_peers (void *cls,
  */
 static int
 try_add_peers (void *cls,
-              const GNUNET_HashCode *pid,
-              void *value)
+               const struct GNUNET_PeerIdentity *pid,
+               void *value)
 {
   struct Peer *pos = value;
 
 {
   struct Peer *pos = value;
 
@@ -773,58 +663,75 @@ try_add_peers (void *cls,
 }
 
 
 }
 
 
+/**
+ * Add peers and schedule connection attempt
+ *
+ * @param cls unused, NULL
+ */
+static void
+add_peer_task (void *cls)
+{
+  add_task = NULL;
+
+  GNUNET_CONTAINER_multipeermap_iterate (peers,
+                                         &try_add_peers,
+                                         NULL);
+}
+
+
 /**
  * Method called whenever a peer disconnects.
  *
  * @param cls closure
  * @param peer peer identity this notification is about
 /**
  * Method called whenever a peer disconnects.
  *
  * @param cls closure
  * @param peer peer identity this notification is about
+ * @param internal_cls the `struct Peer` for this peer
  */
  */
-static void 
+static void
 disconnect_notify (void *cls,
 disconnect_notify (void *cls,
-                  const struct
-                  GNUNET_PeerIdentity * peer)
+                   const struct GNUNET_PeerIdentity *peer,
+                  void *internal_cls)
 {
 {
-  struct Peer *pos;
-#if DEBUG_TOPOLOGY
+  struct Peer *pos = internal_cls;
+
+  if (NULL == pos)
+    return; /* myself, we're shutting down */
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Core told us that we disconnected from `%s'\n",
-             GNUNET_i2s (peer));
-#endif       
-  pos = GNUNET_CONTAINER_multihashmap_get (peers,
-                                          &peer->hashPubKey);
-  if (pos == NULL)
-    {
-      GNUNET_break (0);
-      return;
-    }
-  if (pos->is_connected != GNUNET_YES)
-    {
-      GNUNET_break (0);
-      return;
-    }
+              "Core told us that we disconnected from `%s'\n",
+              GNUNET_i2s (peer));
+  if (NULL == pos->mq)
+  {
+    GNUNET_break (0);
+    return;
+  }
+  pos->mq = NULL;
   connection_count--;
   connection_count--;
+  if (NULL != pos->hello_delay_task)
+  {
+    GNUNET_SCHEDULER_cancel (pos->hello_delay_task);
+    pos->hello_delay_task = NULL;
+  }
   GNUNET_STATISTICS_set (stats,
   GNUNET_STATISTICS_set (stats,
-                        gettext_noop ("# peers connected"),
-                        connection_count,
-                        GNUNET_NO);
+                         gettext_noop ("# peers connected"),
+                         connection_count,
+                         GNUNET_NO);
   if (pos->is_friend)
   if (pos->is_friend)
-    {
-      friend_count--; 
-      GNUNET_STATISTICS_set (stats,
-                            gettext_noop ("# friends connected"),
-                            connection_count,
-                            GNUNET_NO);
-    }
-  if ( (connection_count < target_connection_count) ||
-       (friend_count < minimum_friend_count) )
-    GNUNET_CONTAINER_multihashmap_iterate (peers,
-                                          &try_add_peers,
-                                          NULL);
+  {
+    friend_count--;
+    GNUNET_STATISTICS_set (stats,
+                           gettext_noop ("# friends connected"),
+                           friend_count,
+                           GNUNET_NO);
+  }
+  if ( ( (connection_count < target_connection_count) ||
+         (friend_count < minimum_friend_count)) &&
+       (NULL == add_task) )
+    add_task = GNUNET_SCHEDULER_add_now (&add_peer_task,
+                                         NULL);
   if ( (friend_count < minimum_friend_count) &&
   if ( (friend_count < minimum_friend_count) &&
-       (blacklist == NULL) )
-    blacklist = GNUNET_TRANSPORT_blacklist (sched, cfg,
-                                           &blacklist_check, NULL);
+       (NULL == blacklist))
+    blacklist = GNUNET_TRANSPORT_blacklist (cfg,
+                                            &blacklist_check,
+                                            NULL);
 }
 
 
 }
 
 
@@ -832,20 +739,17 @@ disconnect_notify (void *cls,
  * Iterator called on each address.
  *
  * @param cls flag that we will set if we see any addresses
  * Iterator called on each address.
  *
  * @param cls flag that we will set if we see any addresses
- * @param tname name of the transport
+ * @param address the address of the peer
  * @param expiration when will the given address expire
  * @param expiration when will the given address expire
- * @param addr the address of the peer
- * @param addrlen number of bytes in addr
- * @return GNUNET_SYSERR always, to terminate iteration
+ * @return #GNUNET_SYSERR always, to terminate iteration
  */
 static int
 address_iterator (void *cls,
  */
 static int
 address_iterator (void *cls,
-                 const char *tname,
-                 struct GNUNET_TIME_Absolute expiration,
-                 const void *addr, 
-                 uint16_t addrlen)
+                  const struct GNUNET_HELLO_Address *address,
+                  struct GNUNET_TIME_Absolute expiration)
 {
   int *flag = cls;
 {
   int *flag = cls;
+
   *flag = GNUNET_YES;
   return GNUNET_SYSERR;
 }
   *flag = GNUNET_YES;
   return GNUNET_SYSERR;
 }
@@ -868,62 +772,65 @@ consider_for_advertising (const struct GNUNET_HELLO_Message *hello)
   uint16_t size;
 
   if (GNUNET_OK != GNUNET_HELLO_get_id (hello, &pid))
   uint16_t size;
 
   if (GNUNET_OK != GNUNET_HELLO_get_id (hello, &pid))
-    {
-       GNUNET_break (0);
-       return;
-    }
+  {
+    GNUNET_break (0);
+    return;
+  }
   if (0 == memcmp (&pid,
   if (0 == memcmp (&pid,
-                  &my_identity,
-                  sizeof (struct GNUNET_PeerIdentity)))
-    return; /* that's me! */
+                   &my_identity,
+                   sizeof (struct GNUNET_PeerIdentity)))
+    return;                     /* that's me! */
   have_address = GNUNET_NO;
   GNUNET_HELLO_iterate_addresses (hello,
   have_address = GNUNET_NO;
   GNUNET_HELLO_iterate_addresses (hello,
-                                 GNUNET_NO,
-                                 &address_iterator,
-                                 &have_address);
+                                  GNUNET_NO,
+                                  &address_iterator,
+                                  &have_address);
   if (GNUNET_NO == have_address)
   if (GNUNET_NO == have_address)
-    return; /* no point in advertising this one... */
-  peer = GNUNET_CONTAINER_multihashmap_get (peers,
-                                           &pid.hashPubKey);
-  if (peer == NULL)
-    {
-      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.value == GNUNET_TIME_UNIT_FOREVER_ABS.value)
-       return; /* nothing new here */
-    }
-#if DEBUG_TOPOLOGY
+    return;                     /* no point in advertising this one... */
+  peer = GNUNET_CONTAINER_multipeermap_get (peers, &pid);
+  if (NULL == peer)
+  {
+    peer = make_peer (&pid,
+                      hello,
+                      GNUNET_NO);
+  }
+  else if (NULL != peer->hello)
+  {
+    dt = GNUNET_HELLO_equals (peer->hello,
+                              hello,
+                              GNUNET_TIME_absolute_get ());
+    if (dt.abs_value_us == GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us)
+      return;                   /* nothing new here */
+  }
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Found `%s' from peer `%s' for advertising\n",
-             "HELLO",
-             GNUNET_i2s (&pid));
-#endif 
-  if (peer->hello != NULL)
-    {
-      nh = GNUNET_HELLO_merge (peer->hello,
-                              hello);
-      GNUNET_free (peer->hello);
-      peer->hello = nh;
-    }
+              "Found HELLO from peer `%s' for advertising\n",
+              GNUNET_i2s (&pid));
+  if (NULL != peer->hello)
+  {
+    nh = GNUNET_HELLO_merge (peer->hello,
+                             hello);
+    GNUNET_free (peer->hello);
+    peer->hello = nh;
+  }
   else
   else
-    {
-      size = GNUNET_HELLO_size (hello);
-      peer->hello = GNUNET_malloc (size);
-      memcpy (peer->hello, hello, size);
-    }
-  if (peer->filter != NULL)
+  {
+    size = GNUNET_HELLO_size (hello);
+    peer->hello = GNUNET_malloc (size);
+    GNUNET_memcpy (peer->hello,
+            hello,
+            size);
+  }
+  if (NULL != peer->filter)
+  {
     GNUNET_CONTAINER_bloomfilter_free (peer->filter);
     GNUNET_CONTAINER_bloomfilter_free (peer->filter);
+    peer->filter = NULL;
+  }
   setup_filter (peer);
   /* since we have a new HELLO to pick from, re-schedule all
   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! */
-  GNUNET_CONTAINER_multihashmap_iterate (peers,
-                                        &reschedule_hellos,
-                                        peer);
+   * HELLO requests that are not bound by the HELLO send rate! */
+  GNUNET_CONTAINER_multipeermap_iterate (peers,
+                                         &reschedule_hellos,
+                                         peer);
 }
 
 
 }
 
 
@@ -934,109 +841,122 @@ consider_for_advertising (const struct GNUNET_HELLO_Message *hello)
  * @param cls closure (not used)
  * @param peer potential peer to connect to
  * @param hello HELLO for this peer (or NULL)
  * @param cls closure (not used)
  * @param peer potential peer to connect to
  * @param hello HELLO for this peer (or NULL)
- * @param trust how much we trust the peer (not used)
+ * @param err_msg NULL if successful, otherwise contains error message
  */
 static void
 process_peer (void *cls,
  */
 static void
 process_peer (void *cls,
-             const struct GNUNET_PeerIdentity *peer,
-             const struct GNUNET_HELLO_Message *hello,
-             uint32_t trust)
+              const struct GNUNET_PeerIdentity *peer,
+              const struct GNUNET_HELLO_Message *hello,
+              const char *err_msg)
 {
   struct Peer *pos;
 
 {
   struct Peer *pos;
 
-  GNUNET_assert (peer != NULL);
+  if (NULL != err_msg)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                _("Error in communication with PEERINFO service: %s\n"),
+                err_msg);
+    GNUNET_PEERINFO_notify_cancel (peerinfo_notify);
+    peerinfo_notify = GNUNET_PEERINFO_notify (cfg,
+                                              GNUNET_NO,
+                                              &process_peer,
+                                              NULL);
+    return;
+  }
+  GNUNET_assert (NULL != peer);
   if (0 == memcmp (&my_identity,
   if (0 == memcmp (&my_identity,
-                   peer, sizeof (struct GNUNET_PeerIdentity)))
-    return;  /* that's me! */
-  if (hello == NULL)
+                   peer,
+                   sizeof (struct GNUNET_PeerIdentity)))
+    return;                     /* that's me! */
+  if (NULL == hello)
+  {
+    /* free existing HELLO, if any */
+    pos = GNUNET_CONTAINER_multipeermap_get (peers,
+                                             peer);
+    if (NULL != pos)
     {
     {
-      /* free existing HELLO, if any */
-      pos = GNUNET_CONTAINER_multihashmap_get (peers,
-                                              &peer->hashPubKey);
-      if (NULL != pos)
-       {
-         GNUNET_free_non_null (pos->hello);
-         pos->hello = NULL;
-         if (pos->filter != NULL)
-           {
-             GNUNET_CONTAINER_bloomfilter_free (pos->filter);
-             pos->filter = NULL;
-           }
-         if ( (! pos->is_connected) &&
-              (! pos->is_friend) &&
-              (0 == GNUNET_TIME_absolute_get_remaining (pos->greylisted_until).value) )
-           free_peer (NULL, &pos->pid.hashPubKey, pos);
-       }
-      return;
+      GNUNET_free_non_null (pos->hello);
+      pos->hello = NULL;
+      if (NULL != pos->filter)
+      {
+        GNUNET_CONTAINER_bloomfilter_free (pos->filter);
+        pos->filter = NULL;
+      }
+      if ( (NULL == pos->mq) &&
+           (GNUNET_NO == pos->is_friend) )
+        free_peer (NULL,
+                   &pos->pid,
+                   pos);
     }
     }
+    return;
+  }
   consider_for_advertising (hello);
   consider_for_advertising (hello);
-  pos = GNUNET_CONTAINER_multihashmap_get (peers,
-                                          &peer->hashPubKey);
-  if (pos == NULL)
-    pos = make_peer (peer, hello, GNUNET_NO);
-  GNUNET_assert (NULL != pos);
-  if (GNUNET_YES == pos->is_connected)
-    {
-#if DEBUG_TOPOLOGY
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                 "Already connected to peer `%s'\n",
-                 GNUNET_i2s (peer));
-#endif 
-      return;
-    }
-  if (GNUNET_TIME_absolute_get_remaining (pos->greylisted_until).value > 0)
-    {
-#if DEBUG_TOPOLOGY
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                 "Already tried peer `%s' recently\n",
-                 GNUNET_i2s (peer));
-#endif 
-      return; /* peer still greylisted */
-    }
-#if DEBUG_TOPOLOGY
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Considering connecting to peer `%s'\n",
-             GNUNET_i2s (peer));
-#endif 
+  pos = GNUNET_CONTAINER_multipeermap_get (peers,
+                                           peer);
+  if (NULL == pos)
+    pos = make_peer (peer,
+                     hello,
+                     GNUNET_NO);
   attempt_connect (pos);
 }
 
 
 /**
   attempt_connect (pos);
 }
 
 
 /**
- * Function called after GNUNET_CORE_connect has succeeded
+ * Function called after #GNUNET_CORE_connect has succeeded
  * (or failed for good).
  *
  * @param cls closure
  * (or failed for good).
  *
  * @param cls closure
- * @param server handle to the server, NULL if we failed
  * @param my_id ID of this peer, NULL if we failed
  * @param my_id ID of this peer, NULL if we failed
- * @param publicKey public key of this peer, NULL if we failed
  */
 static void
 core_init (void *cls,
  */
 static void
 core_init (void *cls,
-          struct GNUNET_CORE_Handle * server,
-          const struct GNUNET_PeerIdentity *
-          my_id,
-          const struct
-          GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *
-          publicKey)
+           const struct GNUNET_PeerIdentity *my_id)
 {
 {
-  if (server == NULL)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                 _("Failed to connect to core service, can not manage topology!\n"));
-      GNUNET_SCHEDULER_shutdown (sched);
-      return;
-    }
-  handle = server;
+  if (NULL == my_id)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                _("Failed to connect to core service, can not manage topology!\n"));
+    GNUNET_SCHEDULER_shutdown ();
+    return;
+  }
   my_identity = *my_id;
   my_identity = *my_id;
-#if DEBUG_TOPOLOGY
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "I am peer `%s'\n",
              GNUNET_i2s (my_id));
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "I am peer `%s'\n",
              GNUNET_i2s (my_id));
-#endif         
-  peerinfo_notify = GNUNET_PEERINFO_notify (cfg, sched,
+  peerinfo_notify = GNUNET_PEERINFO_notify (cfg,
+                                            GNUNET_NO,
                                            &process_peer,
                                            &process_peer,
-                                           NULL);
+                                            NULL);
+}
+
+
+/**
+ * Process friend found in FRIENDS file.
+ *
+ * @param cls pointer to an `unsigned int` to be incremented per friend found
+ * @param pid identity of the friend
+ */
+static void
+handle_friend (void *cls,
+               const struct GNUNET_PeerIdentity *pid)
+{
+  unsigned int *entries_found = cls;
+  struct Peer *fl;
+
+  if (0 == memcmp (pid,
+                   &my_identity,
+                   sizeof (struct GNUNET_PeerIdentity)))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                _("Found myself `%s' in friend list (useless, ignored)\n"),
+                GNUNET_i2s (pid));
+    return;
+  }
+  (*entries_found)++;
+  fl = make_peer (pid, NULL, GNUNET_YES);
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              _("Found friend `%s' in configuration\n"),
+              GNUNET_i2s (&fl->pid));
 }
 
 
 }
 
 
@@ -1046,127 +966,45 @@ core_init (void *cls,
 static void
 read_friends_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
 {
 static void
 read_friends_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
 {
-  char *fn;
-  char *data;
-  size_t pos;
-  struct GNUNET_PeerIdentity pid;
-  struct stat frstat;
-  struct GNUNET_CRYPTO_HashAsciiEncoded enc;
   unsigned int entries_found;
   unsigned int entries_found;
-  struct Peer *fl;
 
 
+  entries_found = 0;
   if (GNUNET_OK !=
   if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_filename (cfg,
-                                              "TOPOLOGY",
-                                              "FRIENDS",
-                                              &fn))
-    {
+      GNUNET_FRIENDS_parse (cfg,
+                            &handle_friend,
+                            &entries_found))
+  {
+    if ( (GNUNET_YES == friends_only) ||
+         (minimum_friend_count > 0))
       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                 _("Option `%s' in section `%s' not specified!\n"),
-                 "FRIENDS",
-                 "TOPOLOGY");
-      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);
-  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;
-        }
-    }
-  if (frstat.st_size == 0)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                 _("Friends file `%s' is empty.\n"),
-                 fn);
-      GNUNET_free (fn);
-      return;
-    }
-  data = GNUNET_malloc_large (frstat.st_size);
-  if (frstat.st_size !=
-      GNUNET_DISK_fn_read (fn, data, frstat.st_size))
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                 _("Failed to read friends list from `%s'\n"), fn);
-      GNUNET_free (fn);
-      GNUNET_free (data);
-      return;
-    }
-  entries_found = 0;
-  pos = 0;
-  while ((pos < frstat.st_size) && isspace (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));
-      if (!isspace (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++;
-         while ((pos < frstat.st_size) && (!isspace (data[pos])))
-           pos++;
-         continue;
-       }
-      enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
-      if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &pid.hashPubKey))
-       {
-         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                     _("Syntax error in topology specification at offset %llu, skipping bytes `%s'.\n"),
-                     (unsigned long long) pos,
-                     &enc);
-       }
-      else
-       {
-         if (0 != memcmp (&pid,
-                          &my_identity,
-                          sizeof (struct GNUNET_PeerIdentity)))
-           {
-             entries_found++;
-             fl = make_peer (&pid,
-                             NULL,
-                             GNUNET_YES);
-             GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                         _("Found friend `%s' in configuration\n"),
-                         GNUNET_i2s (&fl->pid));
-           }
-         else
-           {
-             GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                         _("Found myself `%s' in friend list (useless, ignored)\n"),
-                         GNUNET_i2s (&pid));
-           }
-       }
-      pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
-      while ((pos < frstat.st_size) && isspace (data[pos]))
-       pos++;
-    }
-  GNUNET_free (data);
-  GNUNET_free (fn);
+                  _("Encountered errors parsing friends list!\n"));
+  }
   GNUNET_STATISTICS_update (stats,
   GNUNET_STATISTICS_update (stats,
-                           gettext_noop ("# friends in configuration"),
-                           entries_found,
-                           GNUNET_NO);
+                            gettext_noop ("# friends in configuration"),
+                            entries_found,
+                            GNUNET_NO);
   if ( (minimum_friend_count > entries_found) &&
   if ( (minimum_friend_count > entries_found) &&
-       (friends_only == GNUNET_NO) )
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                 _("Fewer friends specified than required by minimum friend count. Will only connect to friends.\n"));
-    }
+       (GNUNET_NO == friends_only) )
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                _("Fewer friends specified than required by minimum friend count. Will only connect to friends.\n"));
+  }
   if ( (minimum_friend_count > target_connection_count) &&
   if ( (minimum_friend_count > target_connection_count) &&
-       (friends_only == GNUNET_NO) )
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                 _("More friendly connections required than target total number of connections.\n"));
-    }
+       (GNUNET_NO == friends_only))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                _("More friendly connections required than target total number of connections.\n"));
+  }
+}
+
+
+/**
+ * Hello offer complete. Clean up.
+ */
+static void
+done_offer_hello (void *cls)
+{
+  oh = NULL;
 }
 
 
 }
 
 
@@ -1174,118 +1012,76 @@ read_friends_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
  * This function is called whenever an encrypted HELLO message is
  * received.
  *
  * This function is called whenever an encrypted HELLO message is
  * received.
  *
- * @param cls closure
- * @param other the other peer involved (sender or receiver, NULL
- *        for loopback messages where we are both sender and receiver)
+ * @param cls closure with the peer identity of the sender
  * @param message the actual HELLO message
  * @param message the actual HELLO message
- * @param latency reported latency of the connection with 'other'
- * @param distance reported distance (DV) to 'other' 
- * @return GNUNET_OK to keep the connection open,
- *         GNUNET_SYSERR to close it (signal serious error)
+ * @return #GNUNET_OK if @a message is well-formed
+ *         #GNUNET_SYSERR if @a message is invalid
  */
 static int
  */
 static int
-handle_encrypted_hello (void *cls,
-                       const struct GNUNET_PeerIdentity * other,
-                       const struct GNUNET_MessageHeader *
-                       message,
-                       struct GNUNET_TIME_Relative latency,
-                       uint32_t distance)
+check_hello (void *cls,
+            const struct GNUNET_HELLO_Message *message)
 {
 {
-  struct Peer *peer;
   struct GNUNET_PeerIdentity pid;
 
   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 (GNUNET_OK !=
   if (GNUNET_OK !=
-      GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message*) message,
+      GNUNET_HELLO_get_id (message,
                           &pid))
                           &pid))
-    {
-      GNUNET_break_op (0);
-      return GNUNET_SYSERR;
-    }
-  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);
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
   return GNUNET_OK;
 }
 
 
 /**
   return GNUNET_OK;
 }
 
 
 /**
- * Function to fill send buffer with HELLO.
+ * This function is called whenever an encrypted HELLO message is
+ * received.
  *
  *
- * @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 cls closure with the peer identity of the sender
+ * @param message the actual HELLO message
  */
  */
-static size_t
-hello_advertising_ready (void *cls,
-                        size_t size,
-                        void *buf)
+static void
+handle_hello (void *cls,
+             const struct GNUNET_HELLO_Message *message)
 {
 {
-  struct Peer *pl = cls;
-  struct FindAdvHelloContext fah;
-  size_t want;
+  const struct GNUNET_PeerIdentity *other = cls;
+  struct Peer *peer;
+  struct GNUNET_PeerIdentity pid;
 
 
-  pl->hello_req = NULL;
-  /* find applicable HELLOs */
-  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;
-  if (fah.result != NULL)
-    {
-      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
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                 "Sending `%s' with %u bytes",
-                 "HELLO"
-                 (unsigned int) want);
-#endif         
-      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 
-    = GNUNET_SCHEDULER_add_now (sched,
-                               &schedule_next_hello,
-                               pl);
-  return want;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Received encrypted HELLO from peer `%s'",
+              GNUNET_i2s (other));
+  GNUNET_assert (GNUNET_OK ==
+                GNUNET_HELLO_get_id (message,
+                                     &pid));
+  GNUNET_STATISTICS_update (stats,
+                            gettext_noop ("# HELLO messages received"),
+                            1,
+                            GNUNET_NO);
+  peer = GNUNET_CONTAINER_multipeermap_get (peers,
+                                           &pid);
+  if (NULL == peer)
+  {
+    if ( (GNUNET_YES == friends_only) ||
+         (friend_count < minimum_friend_count) )
+      return;
+  }
+  else
+  {
+    if ( (GNUNET_YES != peer->is_friend) &&
+         (GNUNET_YES == friends_only) )
+      return;
+    if ((GNUNET_YES != peer->is_friend) &&
+        (friend_count < minimum_friend_count))
+      return;
+  }
+  if (NULL != oh)
+    GNUNET_TRANSPORT_offer_hello_cancel (oh);
+  oh = GNUNET_TRANSPORT_offer_hello (cfg,
+                                     &message->header,
+                                     &done_offer_hello,
+                                     NULL);
 }
 
 
 }
 
 
@@ -1294,34 +1090,46 @@ hello_advertising_ready (void *cls,
  * the transport and core.
  *
  * @param cls unused, NULL
  * 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)
 {
   if (NULL != peerinfo_notify)
 {
   if (NULL != peerinfo_notify)
-    {
-      GNUNET_PEERINFO_notify_cancel (peerinfo_notify);
-      peerinfo_notify = NULL;
-    }
-  GNUNET_TRANSPORT_disconnect (transport);
-  transport = NULL;
-  GNUNET_CONTAINER_multihashmap_iterate (peers,
-                                        &free_peer,
-                                        NULL);
-  GNUNET_CONTAINER_multihashmap_destroy (peers);
-  if (handle != NULL)
-    {
-      GNUNET_CORE_disconnect (handle);
-      handle = NULL;
-    }
+  {
+    GNUNET_PEERINFO_notify_cancel (peerinfo_notify);
+    peerinfo_notify = NULL;
+  }
+  if (NULL != handle)
+  {
+    GNUNET_CORE_disconnect (handle);
+    handle = NULL;
+  }
   whitelist_peers ();
   whitelist_peers ();
-  if (stats != NULL)
-    {
-      GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
-      stats = NULL;
-    }
+  if (NULL != add_task)
+  {
+    GNUNET_SCHEDULER_cancel (add_task);
+    add_task = NULL;
+  }
+  if (NULL != oh)
+  {
+    GNUNET_TRANSPORT_offer_hello_cancel (oh);
+    oh = NULL;
+  }
+  GNUNET_CONTAINER_multipeermap_iterate (peers,
+                                         &free_peer,
+                                         NULL);
+  GNUNET_CONTAINER_multipeermap_destroy (peers);
+  peers = NULL;
+  if (NULL != ats)
+  {
+    GNUNET_ATS_connectivity_done (ats);
+    ats = NULL;
+  }
+  if (NULL != stats)
+  {
+    GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
+    stats = NULL;
+  }
 }
 
 
 }
 
 
@@ -1329,109 +1137,77 @@ cleaning_task (void *cls,
  * 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,
      char *const *args,
      const char *cfgfile,
-     const struct GNUNET_CONFIGURATION_Handle * c)
+     const struct GNUNET_CONFIGURATION_Handle *c)
 {
 {
-  struct GNUNET_CORE_MessageHandler handlers[] =
-    {
-      { &handle_encrypted_hello, GNUNET_MESSAGE_TYPE_HELLO, 0},
-      { NULL, 0, 0 }
-    };
+  struct GNUNET_MQ_MessageHandler handlers[] = {
+    GNUNET_MQ_hd_var_size (hello,
+                           GNUNET_MESSAGE_TYPE_HELLO,
+                           struct GNUNET_HELLO_Message,
+                           NULL),
+    GNUNET_MQ_handler_end ()
+  };
   unsigned long long opt;
 
   unsigned long long opt;
 
-  sched = s;
   cfg = c;
   cfg = c;
-  stats = GNUNET_STATISTICS_create (sched, "topology", cfg);
-  autoconnect = GNUNET_CONFIGURATION_get_value_yesno (cfg,
-                                                     "TOPOLOGY",
-                                                     "AUTOCONNECT");
-  friends_only = GNUNET_CONFIGURATION_get_value_yesno (cfg,
-                                                      "TOPOLOGY",
-                                                      "FRIENDS-ONLY");
+  stats = GNUNET_STATISTICS_create ("topology", cfg);
+  friends_only =
+      GNUNET_CONFIGURATION_get_value_yesno (cfg,
+                                            "TOPOLOGY",
+                                            "FRIENDS-ONLY");
   if (GNUNET_OK !=
       GNUNET_CONFIGURATION_get_value_number (cfg,
   if (GNUNET_OK !=
       GNUNET_CONFIGURATION_get_value_number (cfg,
-                                            "TOPOLOGY",
-                                            "MINIMUM-FRIENDS",
-                                            &opt))
+                                             "TOPOLOGY",
+                                             "MINIMUM-FRIENDS",
+                                             &opt))
     opt = 0;
   minimum_friend_count = (unsigned int) opt;
   if (GNUNET_OK !=
       GNUNET_CONFIGURATION_get_value_number (cfg,
     opt = 0;
   minimum_friend_count = (unsigned int) opt;
   if (GNUNET_OK !=
       GNUNET_CONFIGURATION_get_value_number (cfg,
-                                            "TOPOLOGY",
-                                            "TARGET-CONNECTION-COUNT",
-                                            &opt))
+                                             "TOPOLOGY",
+                                             "TARGET-CONNECTION-COUNT",
+                                             &opt))
     opt = 16;
   target_connection_count = (unsigned int) 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) )
-    read_friends_file (cfg);
-#if DEBUG_TOPOLOGY
+  peers = GNUNET_CONTAINER_multipeermap_create (target_connection_count * 2,
+                                                GNUNET_NO);
+  read_friends_file (cfg);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Topology would like %u connections with at least %u friends (%s)\n",
-             target_connection_count,
-             minimum_friend_count,
-             autoconnect ? "autoconnect enabled" : "autoconnect disabled");
-#endif       
-  if (friend_count < minimum_friend_count) 
-    blacklist = GNUNET_TRANSPORT_blacklist (sched, cfg,
-                                           &blacklist_check, NULL);
-  transport = GNUNET_TRANSPORT_connect (sched,
-                                       cfg,
-                                       NULL,
-                                       NULL,
-                                       NULL,
-                                       NULL);
-  handle = GNUNET_CORE_connect (sched,
-                               cfg,
-                               GNUNET_TIME_UNIT_FOREVER_REL,
+              "Topology would like %u connections with at least %u friends\n",
+              target_connection_count,
+              minimum_friend_count);
+  if ( (friend_count < minimum_friend_count) &&
+       (NULL == blacklist))
+    blacklist = GNUNET_TRANSPORT_blacklist (cfg,
+                                            &blacklist_check,
+                                            NULL);
+  ats = GNUNET_ATS_connectivity_init (cfg);
+  handle = GNUNET_CORE_connect (cfg,
                                NULL,
                                &core_init,
                                &connect_notify,
                                &disconnect_notify,
                                NULL,
                                &core_init,
                                &connect_notify,
                                &disconnect_notify,
-                               NULL, GNUNET_NO,
-                               NULL, GNUNET_NO,
                                handlers);
                                handlers);
-  GNUNET_SCHEDULER_add_delayed (sched,
-                                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");
-      GNUNET_SCHEDULER_shutdown (sched);
-      return;
-    }
+  GNUNET_SCHEDULER_add_shutdown (&cleaning_task,
+                                NULL);
   if (NULL == handle)
   if (NULL == handle)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                 _("Failed to connect to `%s' service.\n"),
-                 "core");
-      GNUNET_SCHEDULER_shutdown (sched);
-      return;
-    }
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                _("Failed to connect to `%s' service.\n"),
+                "core");
+    GNUNET_SCHEDULER_shutdown ();
+    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.
  *
@@ -1442,16 +1218,38 @@ 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;
 
   int ret;
 
-  ret = (GNUNET_OK ==
-         GNUNET_PROGRAM_run (argc,
-                             argv,
-                             "topology",
-                            _("GNUnet topology control (maintaining P2P mesh and F2F constraints)"),
-                            options,
-                            &run, NULL)) ? 0 : 1;
+  if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
+    return 2;
+
+  ret =
+      (GNUNET_OK ==
+       GNUNET_PROGRAM_run (argc, argv,
+                           "gnunet-daemon-topology",
+                           _("GNUnet topology control"),
+                           options, &run, NULL)) ? 0 : 1;
+  GNUNET_free ((void*) argv);
   return ret;
 }
 
   return ret;
 }
 
+
+#if defined(LINUX) && defined(__GLIBC__)
+#include <malloc.h>
+
+/**
+ * MINIMIZE heap size (way below 128k) since this process doesn't need much.
+ */
+void __attribute__ ((constructor))
+GNUNET_ARM_memory_init ()
+{
+  mallopt (M_TRIM_THRESHOLD, 4 * 1024);
+  mallopt (M_TOP_PAD, 1 * 1024);
+  malloc_trim (0);
+}
+#endif
+
 /* end of gnunet-daemon-topology.c */
 /* end of gnunet-daemon-topology.c */