gnunet-svn
[Top][All Lists]
Advanced

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

[gnunet] 07/20: -more work on DHTU integration


From: gnunet
Subject: [gnunet] 07/20: -more work on DHTU integration
Date: Sat, 19 Feb 2022 16:20:47 +0100

This is an automated email from the git hooks/post-receive script.

grothoff pushed a commit to branch master
in repository gnunet.

commit b0abdf7127f2403ff583d224e0d9d4e68c1c5bfc
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Sat Jan 15 19:24:33 2022 +0100

    -more work on DHTU integration
---
 src/datacache/datacache.c                 |   86 ++-
 src/datacache/plugin_datacache_heap.c     |    8 +
 src/datacache/plugin_datacache_postgres.c |   16 +-
 src/datacache/plugin_datacache_sqlite.c   |   52 +-
 src/datacache/plugin_datacache_template.c |    2 +
 src/dht/Makefile.am                       |    1 -
 src/dht/dht_api.c                         |   11 +-
 src/dht/gnunet-service-dht.c              |  149 +++-
 src/dht/gnunet-service-dht.h              |   60 +-
 src/dht/gnunet-service-dht_clients.c      |    2 +-
 src/dht/gnunet-service-dht_datacache.c    |  124 ++--
 src/dht/gnunet-service-dht_datacache.h    |   11 +-
 src/dht/gnunet-service-dht_hello.c        |  154 ----
 src/dht/gnunet-service-dht_hello.h        |   55 --
 src/dht/gnunet-service-dht_neighbours.c   | 1108 ++++++++++++++---------------
 src/dht/gnunet-service-dht_neighbours.h   |   17 +-
 src/dht/gnunet-service-dht_routing.c      |    2 +-
 src/dhtu/plugin_dhtu_gnunet.c             |   13 +-
 src/dhtu/plugin_dhtu_ip.c                 |    5 +-
 src/hello/hello-uri.c                     |  149 +++-
 src/include/gnunet_datacache_lib.h        |    2 +
 src/include/gnunet_datacache_plugin.h     |    2 +
 src/include/gnunet_dht_service.h          |   10 +-
 src/include/gnunet_dhtu_plugin.h          |    5 +-
 src/include/gnunet_hello_uri_lib.h        |   44 +-
 src/include/gnunet_protocols.h            |    8 +-
 26 files changed, 1145 insertions(+), 951 deletions(-)

diff --git a/src/datacache/datacache.c b/src/datacache/datacache.c
index 944a99aad..761ab801f 100644
--- a/src/datacache/datacache.c
+++ b/src/datacache/datacache.c
@@ -114,11 +114,11 @@ env_delete_notify (void *cls,
   h->utilization -= size;
   GNUNET_CONTAINER_bloomfilter_remove (h->filter, key);
   GNUNET_STATISTICS_update (h->stats,
-                            gettext_noop ("# bytes stored"),
+                            "# bytes stored",
                             -(long long) size,
                             GNUNET_NO);
   GNUNET_STATISTICS_update (h->stats,
-                            gettext_noop ("# items stored"),
+                            "# items stored",
                             -1,
                             GNUNET_NO);
 }
@@ -136,15 +136,25 @@ GNUNET_DATACACHE_create (const struct 
GNUNET_CONFIGURATION_Handle *cfg,
   const struct GNUNET_OS_ProjectData *pd;
 
   if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_size (cfg, section, "QUOTA", &quota))
+      GNUNET_CONFIGURATION_get_value_size (cfg,
+                                           section,
+                                           "QUOTA",
+                                           &quota))
   {
-    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, section, "QUOTA");
+    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+                               section,
+                               "QUOTA");
     return NULL;
   }
   if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_string (cfg, section, "DATABASE", &name))
+      GNUNET_CONFIGURATION_get_value_string (cfg,
+                                             section,
+                                             "DATABASE",
+                                             &name))
   {
-    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, section, "DATABASE");
+    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+                               section,
+                               "DATABASE");
     return NULL;
   }
   bf_size = quota / 32; /* 8 bit per entry, 1 bit per 32 kb in DB */
@@ -152,10 +162,14 @@ GNUNET_DATACACHE_create (const struct 
GNUNET_CONFIGURATION_Handle *cfg,
   ret = GNUNET_new (struct GNUNET_DATACACHE_Handle);
 
   if (GNUNET_YES !=
-      GNUNET_CONFIGURATION_get_value_yesno (cfg, section, "DISABLE_BF"))
+      GNUNET_CONFIGURATION_get_value_yesno (cfg,
+                                            section,
+                                            "DISABLE_BF"))
   {
     if (GNUNET_YES !=
-        GNUNET_CONFIGURATION_get_value_yesno (cfg, section, "DISABLE_BF_RC"))
+        GNUNET_CONFIGURATION_get_value_yesno (cfg,
+                                              section,
+                                              "DISABLE_BF_RC"))
     {
       ret->bloom_name = GNUNET_DISK_mktemp ("gnunet-datacachebloom");
     }
@@ -174,7 +188,8 @@ GNUNET_DATACACHE_create (const struct 
GNUNET_CONFIGURATION_Handle *cfg,
                                            5);    /* approx. 3% false 
positives at max use */
     }
   }
-  ret->stats = GNUNET_STATISTICS_create ("datacache", cfg);
+  ret->stats = GNUNET_STATISTICS_create ("datacache",
+                                         cfg);
   ret->section = GNUNET_strdup (section);
   ret->env.cfg = cfg;
   ret->env.delete_notify = &env_delete_notify;
@@ -182,25 +197,31 @@ GNUNET_DATACACHE_create (const struct 
GNUNET_CONFIGURATION_Handle *cfg,
   ret->env.cls = ret;
   ret->env.delete_notify = &env_delete_notify;
   ret->env.quota = quota;
-  LOG (GNUNET_ERROR_TYPE_INFO, _ ("Loading `%s' datacache plugin\n"), name);
-  GNUNET_asprintf (&libname, "libgnunet_plugin_datacache_%s", name);
+  LOG (GNUNET_ERROR_TYPE_INFO,
+       "Loading `%s' datacache plugin\n",
+       name);
+  GNUNET_asprintf (&libname,
+                   "libgnunet_plugin_datacache_%s",
+                   name);
   ret->short_name = name;
   ret->lib_name = libname;
   /* Load the plugin within GNUnet's default context */
   pd = GNUNET_OS_project_data_get ();
   GNUNET_OS_init (GNUNET_OS_project_data_default ());
-  ret->api = GNUNET_PLUGIN_load (libname, &ret->env);
+  ret->api = GNUNET_PLUGIN_load (libname,
+                                 &ret->env);
   GNUNET_OS_init (pd);
   if (NULL == ret->api)
   {
     /* Try to load the plugin within the application's context
        This normally happens when the application is not GNUnet itself but a
        third party; inside GNUnet this is effectively a double failure. */
-    ret->api = GNUNET_PLUGIN_load (libname, &ret->env);
+    ret->api = GNUNET_PLUGIN_load (libname,
+                                   &ret->env);
     if (NULL == ret->api)
     {
       LOG (GNUNET_ERROR_TYPE_ERROR,
-           _ ("Failed to load datacache plugin for `%s'\n"),
+           "Failed to load datacache plugin for `%s'\n",
            name);
       GNUNET_DATACACHE_destroy (ret);
       return NULL;
@@ -216,7 +237,9 @@ GNUNET_DATACACHE_destroy (struct GNUNET_DATACACHE_Handle *h)
   if (NULL != h->filter)
     GNUNET_CONTAINER_bloomfilter_free (h->filter);
   if (NULL != h->api)
-    GNUNET_break (NULL == GNUNET_PLUGIN_unload (h->lib_name, h->api));
+    GNUNET_break (NULL ==
+                  GNUNET_PLUGIN_unload (h->lib_name,
+                                        h->api));
   GNUNET_free (h->lib_name);
   GNUNET_free (h->short_name);
   GNUNET_free (h->section);
@@ -270,17 +293,19 @@ GNUNET_DATACACHE_put (struct GNUNET_DATACACHE_Handle *h,
        "Stored data under key `%s' in cache\n",
        GNUNET_h2s (key));
   if (NULL != h->filter)
-    GNUNET_CONTAINER_bloomfilter_add (h->filter, key);
+    GNUNET_CONTAINER_bloomfilter_add (h->filter,
+                                      key);
   GNUNET_STATISTICS_update (h->stats,
-                            gettext_noop ("# bytes stored"),
+                            "# bytes stored",
                             used,
                             GNUNET_NO);
   GNUNET_STATISTICS_update (h->stats,
-                            gettext_noop ("# items stored"),
+                            "# items stored",
                             1,
                             GNUNET_NO);
   while (h->utilization + used > h->env.quota)
-    GNUNET_assert (GNUNET_OK == h->api->del (h->api->cls));
+    GNUNET_assert (GNUNET_OK ==
+                   h->api->del (h->api->cls));
   h->utilization += used;
   return GNUNET_OK;
 }
@@ -294,18 +319,18 @@ GNUNET_DATACACHE_get (struct GNUNET_DATACACHE_Handle *h,
                       void *iter_cls)
 {
   GNUNET_STATISTICS_update (h->stats,
-                            gettext_noop ("# requests received"),
+                            "# requests received",
                             1,
                             GNUNET_NO);
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Processing request for key `%s'\n",
        GNUNET_h2s (key));
   if ((NULL != h->filter) &&
-      (GNUNET_OK != GNUNET_CONTAINER_bloomfilter_test (h->filter, key)))
+      (GNUNET_OK !=
+       GNUNET_CONTAINER_bloomfilter_test (h->filter, key)))
   {
     GNUNET_STATISTICS_update (h->stats,
-                              gettext_noop (
-                                "# requests filtered by bloom filter"),
+                              "# requests filtered by bloom filter",
                               1,
                               GNUNET_NO);
     LOG (GNUNET_ERROR_TYPE_DEBUG,
@@ -313,26 +338,33 @@ GNUNET_DATACACHE_get (struct GNUNET_DATACACHE_Handle *h,
          GNUNET_h2s (key));
     return 0;   /* can not be present */
   }
-  return h->api->get (h->api->cls, key, type, iter, iter_cls);
+  return h->api->get (h->api->cls,
+                      key,
+                      type,
+                      iter, iter_cls);
 }
 
 
 unsigned int
 GNUNET_DATACACHE_get_closest (struct GNUNET_DATACACHE_Handle *h,
                               const struct GNUNET_HashCode *key,
+                              enum GNUNET_BLOCK_Type type,
                               unsigned int num_results,
                               GNUNET_DATACACHE_Iterator iter,
                               void *iter_cls)
 {
   GNUNET_STATISTICS_update (h->stats,
-                            gettext_noop (
-                              "# proximity search requests received"),
+                            "# proximity search requests received",
                             1,
                             GNUNET_NO);
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Processing proximity search at `%s'\n",
        GNUNET_h2s (key));
-  return h->api->get_closest (h->api->cls, key, num_results, iter, iter_cls);
+  return h->api->get_closest (h->api->cls,
+                              key,
+                              type,
+                              num_results,
+                              iter, iter_cls);
 }
 
 
diff --git a/src/datacache/plugin_datacache_heap.c 
b/src/datacache/plugin_datacache_heap.c
index fbd3aea9a..2756315fb 100644
--- a/src/datacache/plugin_datacache_heap.c
+++ b/src/datacache/plugin_datacache_heap.c
@@ -409,6 +409,8 @@ struct GetClosestContext
 {
   struct Value **values;
 
+  enum GNUNET_BLOCK_Type type;
+
   unsigned int num_results;
 
   const struct GNUNET_HashCode *key;
@@ -427,6 +429,9 @@ find_closest (void *cls,
   if (1 != GNUNET_CRYPTO_hash_cmp (key,
                                    gcc->key))
     return GNUNET_OK; /* useless */
+  if ( (val->type != gcc->type) &&
+       (GNUNET_BLOCK_TYPE_ANY != gcc->type) )
+    return GNUNET_OK; /* useless */
   j = gcc->num_results;
   for (unsigned int i = 0; i < gcc->num_results; i++)
   {
@@ -457,6 +462,7 @@ find_closest (void *cls,
  *
  * @param cls closure (internal context for the plugin)
  * @param key area of the keyspace to look into
+ * @param type desired block type for the replies
  * @param num_results number of results that should be returned to @a iter
  * @param iter maybe NULL (to just count)
  * @param iter_cls closure for @a iter
@@ -465,6 +471,7 @@ find_closest (void *cls,
 static unsigned int
 heap_plugin_get_closest (void *cls,
                          const struct GNUNET_HashCode *key,
+                         enum GNUNET_BLOCK_Type type,
                          unsigned int num_results,
                          GNUNET_DATACACHE_Iterator iter,
                          void *iter_cls)
@@ -473,6 +480,7 @@ heap_plugin_get_closest (void *cls,
   struct Value *values[num_results];
   struct GetClosestContext gcc = {
     .values = values,
+    .type = type,
     .num_results = num_results,
     .key = key
   };
diff --git a/src/datacache/plugin_datacache_postgres.c 
b/src/datacache/plugin_datacache_postgres.c
index 6a44c44a5..61b699c8d 100644
--- a/src/datacache/plugin_datacache_postgres.c
+++ b/src/datacache/plugin_datacache_postgres.c
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet
-     Copyright (C) 2006, 2009, 2010, 2012, 2015, 2017, 2018 GNUnet e.V.
+     Copyright (C) 2006, 2009, 2010, 2012, 2015, 2017, 2018, 2022 GNUnet e.V.
 
      GNUnet is free software: you can redistribute it and/or modify it
      under the terms of the GNU Affero General Public License as published
@@ -109,9 +109,13 @@ init_connection (struct Plugin *plugin)
                             " ORDER BY prox ASC, discard_time ASC LIMIT 1",
                             0),
     GNUNET_PQ_make_prepare ("get_closest",
-                            "SELECT discard_time,type,value,path,key FROM 
gn011dc "
-                            "WHERE key>=$1 AND discard_time >= $2 ORDER BY key 
ASC LIMIT $3",
-                            3),
+                            "SELECT discard_time,type,value,path,key FROM 
gn011dc"
+                            " WHERE key >= $1"
+                            "   AND discard_time >= $2"
+                            "   AND ( (type = $3) OR ( 0 = $3) )"
+                            " ORDER BY key ASC"
+                            " LIMIT $4",
+                            4),
     GNUNET_PQ_make_prepare ("delrow",
                             "DELETE FROM gn011dc WHERE oid=$1",
                             1),
@@ -511,6 +515,7 @@ extract_result_cb (void *cls,
  *
  * @param cls closure (internal context for the plugin)
  * @param key area of the keyspace to look into
+ * @param type desired block type for the replies
  * @param num_results number of results that should be returned to @a iter
  * @param iter maybe NULL (to just count)
  * @param iter_cls closure for @a iter
@@ -519,16 +524,19 @@ extract_result_cb (void *cls,
 static unsigned int
 postgres_plugin_get_closest (void *cls,
                              const struct GNUNET_HashCode *key,
+                             enum GNUNET_BLOCK_Type type,
                              unsigned int num_results,
                              GNUNET_DATACACHE_Iterator iter,
                              void *iter_cls)
 {
   struct Plugin *plugin = cls;
   uint32_t num_results32 = (uint32_t) num_results;
+  uint32_t type32 = (uint32_t) type;
   struct GNUNET_TIME_Absolute now;
   struct GNUNET_PQ_QueryParam params[] = {
     GNUNET_PQ_query_param_auto_from_type (key),
     GNUNET_PQ_query_param_absolute_time (&now),
+    GNUNET_PQ_query_param_uint32 (&type32),
     GNUNET_PQ_query_param_uint32 (&num_results32),
     GNUNET_PQ_query_param_end
   };
diff --git a/src/datacache/plugin_datacache_sqlite.c 
b/src/datacache/plugin_datacache_sqlite.c
index d08b32caf..46ff66dce 100644
--- a/src/datacache/plugin_datacache_sqlite.c
+++ b/src/datacache/plugin_datacache_sqlite.c
@@ -454,6 +454,7 @@ sqlite_plugin_del (void *cls)
  *
  * @param cls closure (internal context for the plugin)
  * @param key area of the keyspace to look into
+ * @param type desired block type for the replies
  * @param num_results number of results that should be returned to @a iter
  * @param iter maybe NULL (to just count)
  * @param iter_cls closure for @a iter
@@ -462,11 +463,13 @@ sqlite_plugin_del (void *cls)
 static unsigned int
 sqlite_plugin_get_closest (void *cls,
                            const struct GNUNET_HashCode *key,
+                           enum GNUNET_BLOCK_Type type,
                            unsigned int num_results,
                            GNUNET_DATACACHE_Iterator iter,
                            void *iter_cls)
 {
   struct Plugin *plugin = cls;
+  uint32_t type32 = type;
   uint32_t num_results32 = num_results;
   struct GNUNET_TIME_Absolute now;
   struct GNUNET_TIME_Absolute exp;
@@ -474,38 +477,46 @@ sqlite_plugin_get_closest (void *cls,
   void *dat;
   unsigned int cnt;
   size_t psize;
-  uint32_t type;
+  uint32_t rtype;
   struct GNUNET_HashCode hc;
   struct GNUNET_DHT_PathElement *path;
-  struct GNUNET_SQ_QueryParam params[] =
-  { GNUNET_SQ_query_param_auto_from_type (key),
+  struct GNUNET_SQ_QueryParam params[] = {
+    GNUNET_SQ_query_param_auto_from_type (key),
     GNUNET_SQ_query_param_absolute_time (&now),
+    GNUNET_SQ_query_param_uint32 (&type32),
     GNUNET_SQ_query_param_uint32 (&num_results32),
-    GNUNET_SQ_query_param_end };
-  struct GNUNET_SQ_ResultSpec rs[] =
-  { GNUNET_SQ_result_spec_variable_size (&dat, &size),
+    GNUNET_SQ_query_param_end
+  };
+  struct GNUNET_SQ_ResultSpec rs[] = {
+    GNUNET_SQ_result_spec_variable_size (&dat, &size),
     GNUNET_SQ_result_spec_absolute_time (&exp),
     GNUNET_SQ_result_spec_variable_size ((void **) &path, &psize),
-    GNUNET_SQ_result_spec_uint32 (&type),
+    GNUNET_SQ_result_spec_uint32 (&rtype),
     GNUNET_SQ_result_spec_auto_from_type (&hc),
-    GNUNET_SQ_result_spec_end };
+    GNUNET_SQ_result_spec_end
+  };
 
   now = GNUNET_TIME_absolute_get ();
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Processing GET_CLOSEST for key `%s'\n",
        GNUNET_h2s (key));
-  if (GNUNET_OK != GNUNET_SQ_bind (plugin->get_closest_stmt, params))
+  if (GNUNET_OK !=
+      GNUNET_SQ_bind (plugin->get_closest_stmt,
+                      params))
   {
     LOG_SQLITE (plugin->dbh,
                 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                 "sqlite3_bind_xxx");
-    GNUNET_SQ_reset (plugin->dbh, plugin->get_closest_stmt);
+    GNUNET_SQ_reset (plugin->dbh,
+                     plugin->get_closest_stmt);
     return 0;
   }
   cnt = 0;
   while (SQLITE_ROW == sqlite3_step (plugin->get_closest_stmt))
   {
-    if (GNUNET_OK != GNUNET_SQ_extract_result (plugin->get_closest_stmt, rs))
+    if (GNUNET_OK !=
+        GNUNET_SQ_extract_result (plugin->get_closest_stmt,
+                                  rs))
     {
       GNUNET_break (0);
       break;
@@ -522,14 +533,22 @@ sqlite_plugin_get_closest (void *cls,
          "Found %u-byte result at %s when processing GET_CLOSE\n",
          (unsigned int) size,
          GNUNET_h2s (&hc));
-    if (GNUNET_OK != iter (iter_cls, &hc, size, dat, type, exp, psize, path))
+    if (GNUNET_OK != iter (iter_cls,
+                           &hc,
+                           size,
+                           dat,
+                           rtype,
+                           exp,
+                           psize,
+                           path))
     {
       GNUNET_SQ_cleanup_result (rs);
       break;
     }
     GNUNET_SQ_cleanup_result (rs);
   }
-  GNUNET_SQ_reset (plugin->dbh, plugin->get_closest_stmt);
+  GNUNET_SQ_reset (plugin->dbh,
+                   plugin->get_closest_stmt);
   return cnt;
 }
 
@@ -620,7 +639,7 @@ libgnunet_plugin_datacache_sqlite_init (void *cls)
                    &plugin->get_stmt)) ||
       (SQLITE_OK != sq_prepare (plugin->dbh,
                                 "SELECT _ROWID_,key,value FROM ds091"
-                                " WHERE expire < ?"
+                                " WHERE expire < ?1"
                                 " ORDER BY expire ASC LIMIT 1",
                                 &plugin->del_expired_stmt)) ||
       (SQLITE_OK != sq_prepare (plugin->dbh,
@@ -633,7 +652,10 @@ libgnunet_plugin_datacache_sqlite_init (void *cls)
       (SQLITE_OK !=
        sq_prepare (plugin->dbh,
                    "SELECT value,expire,path,type,key FROM ds091 "
-                   "WHERE key>=? AND expire >= ? ORDER BY KEY ASC LIMIT ?",
+                   " WHERE key>=?1 "
+                   "  AND expire >= ?2"
+                   "  AND ( (type=?3) or (0 == ?3) )"
+                   " ORDER BY KEY ASC LIMIT ?4",
                    &plugin->get_closest_stmt)))
   {
     LOG_SQLITE (plugin->dbh,
diff --git a/src/datacache/plugin_datacache_template.c 
b/src/datacache/plugin_datacache_template.c
index 231413ce9..2f7b41dbe 100644
--- a/src/datacache/plugin_datacache_template.c
+++ b/src/datacache/plugin_datacache_template.c
@@ -116,6 +116,7 @@ template_plugin_del (void *cls)
  *
  * @param cls closure (internal context for the plugin)
  * @param key area of the keyspace to look into
+ * @param type desired block type for the replies
  * @param num_results number of results that should be returned to @a iter
  * @param iter maybe NULL (to just count)
  * @param iter_cls closure for @a iter
@@ -124,6 +125,7 @@ template_plugin_del (void *cls)
 static unsigned int
 template_plugin_get_closest (void *cls,
                              const struct GNUNET_HashCode *key,
+                             enum GNUNET_BLOCK_Type type,
                              unsigned int num_results,
                              GNUNET_DATACACHE_Iterator iter,
                              void *iter_cls)
diff --git a/src/dht/Makefile.am b/src/dht/Makefile.am
index 44439f66f..ab4ec1b3c 100644
--- a/src/dht/Makefile.am
+++ b/src/dht/Makefile.am
@@ -58,7 +58,6 @@ noinst_PROGRAMS = \
 gnunet_service_dht_SOURCES = \
  gnunet-service-dht.c gnunet-service-dht.h \
  gnunet-service-dht_datacache.c gnunet-service-dht_datacache.h \
- gnunet-service-dht_hello.c gnunet-service-dht_hello.h \
  gnunet-service-dht_neighbours.c gnunet-service-dht_neighbours.h \
  gnunet-service-dht_routing.c gnunet-service-dht_routing.h
 gnunet_service_dht_LDADD = \
diff --git a/src/dht/dht_api.c b/src/dht/dht_api.c
index 8389bbb95..a0c30d5e7 100644
--- a/src/dht/dht_api.c
+++ b/src/dht/dht_api.c
@@ -726,6 +726,7 @@ process_client_result (void *cls,
   const struct GNUNET_DHT_ClientResultMessage *crm = cls;
   struct GNUNET_DHT_GetHandle *get_handle = value;
   size_t msize = ntohs (crm->header.size) - sizeof(*crm);
+  uint16_t type = ntohl (crm->type);
   uint32_t put_path_length = ntohl (crm->put_path_length);
   uint32_t get_path_length = ntohl (crm->get_path_length);
   const struct GNUNET_DHT_PathElement *put_path;
@@ -745,7 +746,13 @@ process_client_result (void *cls,
          (unsigned long long) get_handle->unique_id);
     return GNUNET_YES;
   }
-  /* FIXME: might want to check that type matches */
+  if ( (get_handle->type != GNUNET_BLOCK_TYPE_ANY) &&
+       (get_handle->type != type) )
+  {
+    /* type mismatch */
+    GNUNET_break (0);
+    return GNUNET_YES;
+  }
   meta_length =
     sizeof(struct GNUNET_DHT_PathElement) * (get_path_length + 
put_path_length);
   data_length = msize - meta_length;
@@ -786,7 +793,7 @@ process_client_result (void *cls,
                     get_path_length,
                     put_path,
                     put_path_length,
-                    ntohl (crm->type),
+                    type,
                     data_length,
                     data);
   return GNUNET_YES;
diff --git a/src/dht/gnunet-service-dht.c b/src/dht/gnunet-service-dht.c
index 6f2573d26..35e219926 100644
--- a/src/dht/gnunet-service-dht.c
+++ b/src/dht/gnunet-service-dht.c
@@ -28,14 +28,20 @@
 #include "gnunet_block_lib.h"
 #include "gnunet_util_lib.h"
 #include "gnunet_hello_lib.h"
+#include "gnunet_hello_uri_lib.h"
 #include "gnunet_dht_service.h"
 #include "gnunet_statistics_service.h"
 #include "gnunet-service-dht.h"
 #include "gnunet-service-dht_datacache.h"
-#include "gnunet-service-dht_hello.h"
 #include "gnunet-service-dht_neighbours.h"
 #include "gnunet-service-dht_routing.h"
 
+/**
+ * How often do we broadcast our HELLO to neighbours if
+ * nothing special happens?
+ */
+#define HELLO_FREQUENCY GNUNET_TIME_UNIT_HOURS
+
 
 /**
  * Information we keep per underlay.
@@ -110,7 +116,27 @@ struct MyAddress
 /**
  * Our HELLO
  */
-struct GNUNET_MessageHeader *GDS_my_hello;
+struct GNUNET_HELLO_Builder *GDS_my_hello;
+
+/**
+ * Identity of this peer.
+ */
+struct GNUNET_PeerIdentity GDS_my_identity;
+
+/**
+ * Hash of the identity of this peer.
+ */
+struct GNUNET_HashCode GDS_my_identity_hash;
+
+/**
+ * Our private key.
+ */
+struct GNUNET_CRYPTO_EddsaPrivateKey GDS_my_private_key;
+
+/**
+ * Task broadcasting our HELLO.
+ */
+static struct GNUNET_SCHEDULER_Task *hello_task;
 
 /**
  * Handles for the DHT underlays.
@@ -132,11 +158,6 @@ static struct MyAddress *a_head;
  */
 static struct MyAddress *a_tail;
 
-/**
- * Hello address expiration
- */
-struct GNUNET_TIME_Relative hello_expiration;
-
 /**
  * log of the current network size estimate, used as the point where
  * we switch between random and deterministic routing.
@@ -195,13 +216,29 @@ GDS_NSE_get (void)
 
 
 /**
- * Update our HELLO with all of our our addresses.
+ * Task run periodically to broadcast our HELLO.
+ *
+ * @param cls NULL
  */
 static void
-update_hello (void)
+broadcast_hello (void *cls)
 {
-  GNUNET_free (GDS_my_hello);
-  // FIXME: build new HELLO properly!
+  struct GNUNET_MessageHeader *hello;
+
+  (void) cls;
+  /* TODO: randomize! */
+  hello_task = GNUNET_SCHEDULER_add_delayed (HELLO_FREQUENCY,
+                                             &broadcast_hello,
+                                             NULL);
+  hello = GNUNET_HELLO_builder_to_dht_hello_msg (GDS_my_hello,
+                                                 &GDS_my_private_key);
+  if (NULL == hello)
+  {
+    GNUNET_break (0);
+    return;
+  }
+  GDS_NEIGHBOURS_broadcast (hello);
+  GNUNET_free (hello);
 }
 
 
@@ -231,7 +268,12 @@ u_address_add (void *cls,
                                a_tail,
                                a);
   *ctx = a;
-  update_hello ();
+  GNUNET_HELLO_builder_add_address (GDS_my_hello,
+                                    address);
+  if (NULL != hello_task)
+    GNUNET_SCHEDULER_cancel (hello_task);
+  hello_task = GNUNET_SCHEDULER_add_now (&broadcast_hello,
+                                         NULL);
 }
 
 
@@ -245,12 +287,47 @@ u_address_del (void *ctx)
 {
   struct MyAddress *a = ctx;
 
+  GNUNET_HELLO_builder_del_address (GDS_my_hello,
+                                    a->url);
   GNUNET_CONTAINER_DLL_remove (a_head,
                                a_tail,
                                a);
   GNUNET_free (a->url);
   GNUNET_free (a);
-  update_hello ();
+  if (NULL != hello_task)
+    GNUNET_SCHEDULER_cancel (hello_task);
+  hello_task = GNUNET_SCHEDULER_add_now (&broadcast_hello,
+                                         NULL);
+}
+
+
+void
+GDS_u_try_connect (const struct GNUNET_PeerIdentity *pid,
+                   const char *address)
+{
+  for (struct Underlay *u = u_head;
+       NULL != u;
+       u = u->next)
+    u->dhtu->try_connect (u->dhtu->cls,
+                          pid,
+                          address);
+}
+
+
+void
+GDS_u_send (struct Underlay *u,
+            struct GNUNET_DHTU_Target *target,
+            const void *msg,
+            size_t msg_size,
+            GNUNET_SCHEDULER_TaskCallback finished_cb,
+            void *finished_cb_cls)
+{
+  u->dhtu->send (u->dhtu->cls,
+                 target,
+                 msg,
+                 msg_size,
+                 finished_cb,
+                 finished_cb_cls);
 }
 
 
@@ -265,7 +342,6 @@ shutdown_task (void *cls)
   GDS_NEIGHBOURS_done ();
   GDS_DATACACHE_done ();
   GDS_ROUTING_done ();
-  GDS_HELLO_done ();
   if (NULL != GDS_block_context)
   {
     GNUNET_BLOCK_context_destroy (GDS_block_context);
@@ -277,7 +353,7 @@ shutdown_task (void *cls)
                                GNUNET_YES);
     GDS_stats = NULL;
   }
-  GNUNET_free (GDS_my_hello);
+  GNUNET_HELLO_builder_free (GDS_my_hello);
   GDS_my_hello = NULL;
   GDS_CLIENTS_stop ();
 }
@@ -348,14 +424,39 @@ run (void *cls,
 {
   GDS_cfg = c;
   GDS_service = service;
-  if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_time (c,
-                                           "transport",
-                                           "HELLO_EXPIRATION",
-                                           &hello_expiration))
   {
-    hello_expiration = GNUNET_CONSTANTS_HELLO_ADDRESS_EXPIRATION;
+    char *keyfile;
+
+    if (GNUNET_OK !=
+        GNUNET_CONFIGURATION_get_value_filename (GDS_cfg,
+                                                 "PEER",
+                                                 "PRIVATE_KEY",
+                                                 &keyfile))
+    {
+      GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+                                 "PEER",
+                                 "PRIVATE_KEY");
+      GNUNET_SCHEDULER_shutdown ();
+      return;
+    }
+    if (GNUNET_SYSERR ==
+        GNUNET_CRYPTO_eddsa_key_from_file (keyfile,
+                                           GNUNET_YES,
+                                           &GDS_my_private_key))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "Failed to setup peer's private key\n");
+      GNUNET_free (keyfile);
+      GNUNET_SCHEDULER_shutdown ();
+      return;
+    }
+    GNUNET_free (keyfile);
   }
+  GNUNET_CRYPTO_eddsa_key_get_public (&GDS_my_private_key,
+                                      &GDS_my_identity.public_key);
+  GNUNET_CRYPTO_hash (&GDS_my_identity,
+                      sizeof(struct GNUNET_PeerIdentity),
+                      &GDS_my_identity_hash);
   GDS_block_context = GNUNET_BLOCK_context_create (GDS_cfg);
   GDS_stats = GNUNET_STATISTICS_create ("dht",
                                         GDS_cfg);
@@ -364,6 +465,12 @@ run (void *cls,
   GDS_DATACACHE_init ();
   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
                                  NULL);
+  if (GNUNET_OK !=
+      GDS_NEIGHBOURS_init ())
+  {
+    GNUNET_SCHEDULER_shutdown ();
+    return;
+  }
   GNUNET_CONFIGURATION_iterate_sections (GDS_cfg,
                                          &load_underlay,
                                          NULL);
diff --git a/src/dht/gnunet-service-dht.h b/src/dht/gnunet-service-dht.h
index 687e2d4d3..403b3f5a1 100644
--- a/src/dht/gnunet-service-dht.h
+++ b/src/dht/gnunet-service-dht.h
@@ -27,12 +27,18 @@
 #define GNUNET_SERVICE_DHT_H
 
 #include "gnunet-service-dht_datacache.h"
+#include "gnunet-service-dht_neighbours.h"
 #include "gnunet_statistics_service.h"
 #include "gnunet_transport_service.h"
 
 
 #define DEBUG_DHT GNUNET_EXTRA_LOGGING
 
+/**
+ * Information we keep per underlay.
+ */
+struct Underlay;
+
 /**
  * Configuration we use.
  */
@@ -54,9 +60,59 @@ extern struct GNUNET_BLOCK_Context *GDS_block_context;
 extern struct GNUNET_STATISTICS_Handle *GDS_stats;
 
 /**
- * Our HELLO
+ * Our HELLO builder.
+ */
+extern struct GNUNET_HELLO_Builder *GDS_my_hello;
+
+/**
+ * Identity of this peer.
+ */
+extern struct GNUNET_PeerIdentity GDS_my_identity;
+
+/**
+ * Hash of the identity of this peer.
+ */
+extern struct GNUNET_HashCode GDS_my_identity_hash;
+
+/**
+ * Our private key.
  */
-extern struct GNUNET_MessageHeader *GDS_my_hello;
+extern struct GNUNET_CRYPTO_EddsaPrivateKey GDS_my_private_key;
+
+
+/**
+ * Ask all underlays to connect to peer @a pid at @a address.
+ *
+ * @param pid identity of the peer we would connect to
+ * @param address an address of @a pid
+ */
+void
+GDS_u_try_connect (const struct GNUNET_PeerIdentity *pid,
+                   const char *address);
+
+
+/**
+ * Send message to some other participant over the network.  Note that
+ * sending is not guaranteeing that the other peer actually received the
+ * message.  For any given @a target, the DHT must wait for the @a
+ * finished_cb to be called before calling send() again.
+ *
+ * @param u underlay to use for transmission
+ * @param target receiver identification
+ * @param msg message
+ * @param msg_size number of bytes in @a msg
+ * @param finished_cb function called once transmission is done
+ *        (not called if @a target disconnects, then only the
+ *         disconnect_cb is called).
+ * @param finished_cb_cls closure for @a finished_cb
+ */
+void
+GDS_u_send (struct Underlay *u,
+            struct GNUNET_DHTU_Target *target,
+            const void *msg,
+            size_t msg_size,
+            GNUNET_SCHEDULER_TaskCallback finished_cb,
+            void *finished_cb_cls);
 
 
 /**
diff --git a/src/dht/gnunet-service-dht_clients.c 
b/src/dht/gnunet-service-dht_clients.c
index a1c3024de..bc39e004a 100644
--- a/src/dht/gnunet-service-dht_clients.c
+++ b/src/dht/gnunet-service-dht_clients.c
@@ -917,7 +917,7 @@ forward_reply (void *cls,
                               GNUNET_NO);
     return GNUNET_YES;          /* type mismatch */
   }
-  if ( (0 == (record->msg_options & GNUNET_DHT_RO_FIND_PEER)) &&
+  if ( (0 == (record->msg_options & GNUNET_DHT_RO_FIND_APPROXIMATE)) &&
        (0 != GNUNET_memcmp (&frc->bd->key,
                             query_hash)) )
   {
diff --git a/src/dht/gnunet-service-dht_datacache.c 
b/src/dht/gnunet-service-dht_datacache.c
index cb778717b..880c72cb2 100644
--- a/src/dht/gnunet-service-dht_datacache.c
+++ b/src/dht/gnunet-service-dht_datacache.c
@@ -68,7 +68,7 @@ GDS_DATACACHE_handle_put (const struct 
GDS_DATACACHE_BlockData *bd)
                             1,
                             GNUNET_NO);
   GNUNET_CRYPTO_hash_xor (&bd->key,
-                          &my_identity_hash,
+                          &GDS_my_identity_hash,
                           &xor);
   r = GNUNET_DATACACHE_put (datacache,
                             &bd->key,
@@ -231,7 +231,15 @@ GDS_DATACACHE_handle_get (const struct GNUNET_HashCode 
*key,
                           GDS_DATACACHE_GetCallback gc,
                           void *gc_cls)
 {
-  struct GetRequestContext ctx;
+  struct GetRequestContext ctx = {
+    .eval = GNUNET_BLOCK_EVALUATION_REQUEST_VALID,
+    .key = *key,
+    .xquery = xquery,
+    .xquery_size = xquery_size,
+    .bg = bg,
+    .gc = gc,
+    .gc_cls = gc_cls
+  };
   unsigned int r;
 
   if (NULL == datacache)
@@ -240,13 +248,6 @@ GDS_DATACACHE_handle_get (const struct GNUNET_HashCode 
*key,
                             "# GET requests given to datacache",
                             1,
                             GNUNET_NO);
-  ctx.eval = GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
-  ctx.key = *key;
-  ctx.xquery = xquery;
-  ctx.xquery_size = xquery_size;
-  ctx.bg = bg;
-  ctx.gc = gc;
-  ctx.gc_cls = gc_cls;
   r = GNUNET_DATACACHE_get (datacache,
                             key,
                             type,
@@ -261,85 +262,44 @@ GDS_DATACACHE_handle_get (const struct GNUNET_HashCode 
*key,
 }
 
 
-/**
- * Closure for #datacache_get_successors_iterator().
- */
-struct SuccContext
-{
-  /**
-   * Function to call on the result
-   */
-  GDS_DATACACHE_GetCallback cb;
-
-  /**
-   * Closure for @e cb.
-   */
-  void *cb_cls;
-
-};
-
-
-/**
- * Iterator for local get request results,
- *
- * @param cls closure with the `struct GNUNET_HashCode *` with the trail ID
- * @param key the key this data is stored under
- * @param size the size of the data identified by key
- * @param data the actual data
- * @param type the type of the data
- * @param exp when does this value expire?
- * @param put_path_length number of peers in @a put_path
- * @param put_path path the reply took on put
- * @return #GNUNET_OK to continue iteration, anything else
- * to stop iteration.
- */
-static enum GNUNET_GenericReturnValue
-datacache_get_successors_iterator (void *cls,
-                                   const struct GNUNET_HashCode *key,
-                                   size_t size,
-                                   const char *data,
-                                   enum GNUNET_BLOCK_Type type,
-                                   struct GNUNET_TIME_Absolute exp,
-                                   unsigned int put_path_length,
-                                   const struct
-                                   GNUNET_DHT_PathElement *put_path)
-{
-  const struct SuccContext *sc = cls;
-  struct GDS_DATACACHE_BlockData bd = {
-    .key = *key,
-    .expiration_time = exp,
-    .put_path = put_path,
-    .data = data,
-    .data_size = size,
-    .put_path_length = put_path_length,
-    .type = type
-  };
-
-  /* NOTE: The datacache currently does not store the RO from
-     the original 'put', so we don't know the 'correct' option
-     at this point anymore.  Thus, we conservatively assume
-     that recording is desired (for now). */
-  sc->cb (sc->cb_cls,
-          &bd);
-  return GNUNET_OK;
-}
-
-
-void
+enum GNUNET_BLOCK_EvaluationResult
 GDS_DATACACHE_get_closest (const struct GNUNET_HashCode *key,
+                           enum GNUNET_BLOCK_Type type,
+                           const void *xquery,
+                           size_t xquery_size,
+                           struct GNUNET_BLOCK_Group *bg,
                            GDS_DATACACHE_GetCallback cb,
                            void *cb_cls)
 {
-  struct SuccContext sc = {
-    .cb = cb,
-    .cb_cls = cb_cls
+  struct GetRequestContext ctx = {
+    .eval = GNUNET_BLOCK_EVALUATION_REQUEST_VALID,
+    .key = *key,
+    .xquery = xquery,
+    .xquery_size = xquery_size,
+    .bg = bg,
+    .gc = cb,
+    .gc_cls = cb_cls
   };
+  unsigned int r;
 
-  (void) GNUNET_DATACACHE_get_closest (datacache,
-                                       key,
-                                       NUM_CLOSEST,
-                                       &datacache_get_successors_iterator,
-                                       &sc);
+  if (NULL == datacache)
+    return GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
+  GNUNET_STATISTICS_update (GDS_stats,
+                            "# GET closest requests given to datacache",
+                            1,
+                            GNUNET_NO);
+  r = GNUNET_DATACACHE_get_closest (datacache,
+                                    key,
+                                    type,
+                                    NUM_CLOSEST,
+                                    &datacache_get_iterator,
+                                    &ctx);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "DATACACHE approximate GET for key %s completed (%d). %u results 
found.\n",
+       GNUNET_h2s (key),
+       ctx.eval,
+       r);
+  return ctx.eval;
 }
 
 
diff --git a/src/dht/gnunet-service-dht_datacache.h 
b/src/dht/gnunet-service-dht_datacache.h
index 691a51e0e..69a18c605 100644
--- a/src/dht/gnunet-service-dht_datacache.h
+++ b/src/dht/gnunet-service-dht_datacache.h
@@ -122,11 +122,20 @@ GDS_DATACACHE_handle_get (const struct GNUNET_HashCode 
*key,
  * another peer.
  *
  * @param key the location at which the peer is looking for data that is close
+ * @param type requested data type
+ * @param xquery extended query
+ * @param xquery_size number of bytes in xquery
+ * @param bg block group to use for evaluation of replies
  * @param cb function to call with the result
  * @param cb_cls closure for @a cb
+ * @return evaluation result for the local replies
  */
-void
+enum GNUNET_BLOCK_EvaluationResult
 GDS_DATACACHE_get_closest (const struct GNUNET_HashCode *key,
+                           enum GNUNET_BLOCK_Type type,
+                           const void *xquery,
+                           size_t xquery_size,
+                           struct GNUNET_BLOCK_Group *bg,
                            GDS_DATACACHE_GetCallback cb,
                            void *cb_cls);
 
diff --git a/src/dht/gnunet-service-dht_hello.c 
b/src/dht/gnunet-service-dht_hello.c
deleted file mode 100644
index 949456575..000000000
--- a/src/dht/gnunet-service-dht_hello.c
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2011 GNUnet e.V.
-
-     GNUnet is free software: you can redistribute it and/or modify it
-     under the terms of the GNU Affero General Public License as published
-     by the Free Software Foundation, either version 3 of the License,
-     or (at your option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     Affero General Public License for more details.
-
-     You should have received a copy of the GNU Affero General Public License
-     along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-     SPDX-License-Identifier: AGPL3.0-or-later
- */
-
-/**
- * @file dht/gnunet-service-dht_hello.c
- * @brief GNUnet DHT integration with peerinfo
- * @author Christian Grothoff
- *
- * TODO:
- * - consider adding mechanism to remove expired HELLOs
- */
-#include "platform.h"
-#include "gnunet-service-dht.h"
-#include "gnunet-service-dht_hello.h"
-#include "gnunet_peerinfo_service.h"
-
-
-/**
- * Handle for peerinfo notifications.
- */
-static struct GNUNET_PEERINFO_NotifyContext *pnc;
-
-/**
- * Hash map of peers to HELLOs.
- */
-static struct GNUNET_CONTAINER_MultiPeerMap *peer_to_hello;
-
-
-/**
- * Obtain a peer's HELLO if available
- *
- * @param peer peer to look for a HELLO from
- * @return HELLO for the given peer
- */
-const struct GNUNET_HELLO_Message *
-GDS_HELLO_get (const struct GNUNET_PeerIdentity *peer)
-{
-  if (NULL == peer_to_hello)
-    return NULL;
-  return GNUNET_CONTAINER_multipeermap_get (peer_to_hello,
-                                            peer);
-}
-
-
-/**
- * Function called for each HELLO known to PEERINFO.
- *
- * @param cls closure
- * @param peer id of the peer, NULL for last call
- * @param hello hello message for the peer (can be NULL)
- * @param err_msg error message (not used)
- *
- * FIXME this is called once per address. Merge instead of replacing?
- */
-static void
-process_hello (void *cls,
-               const struct GNUNET_PeerIdentity *peer,
-               const struct GNUNET_HELLO_Message *hello,
-               const char *err_msg)
-{
-  struct GNUNET_TIME_Absolute ex;
-  struct GNUNET_HELLO_Message *hm;
-
-  if (NULL == hello)
-    return;
-  ex = GNUNET_HELLO_get_last_expiration (hello);
-  if (0 == GNUNET_TIME_absolute_get_remaining (ex).rel_value_us)
-    return;
-  GNUNET_STATISTICS_update (GDS_stats,
-                            "# HELLOs obtained from peerinfo",
-                            1,
-                            GNUNET_NO);
-  hm = GNUNET_CONTAINER_multipeermap_get (peer_to_hello,
-                                          peer);
-  GNUNET_free (hm);
-  hm = GNUNET_malloc (GNUNET_HELLO_size (hello));
-  GNUNET_memcpy (hm,
-                 hello,
-                 GNUNET_HELLO_size (hello));
-  GNUNET_assert (GNUNET_SYSERR !=
-                 GNUNET_CONTAINER_multipeermap_put (peer_to_hello,
-                                                    peer,
-                                                    hm,
-                                                    
GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE));
-}
-
-
-/**
- * Initialize HELLO subsystem.
- */
-void
-GDS_HELLO_init ()
-{
-  pnc = GNUNET_PEERINFO_notify (GDS_cfg,
-                                GNUNET_NO,
-                                &process_hello,
-                                NULL);
-  peer_to_hello = GNUNET_CONTAINER_multipeermap_create (256,
-                                                        GNUNET_NO);
-}
-
-
-/**
- * Free memory occopied by the HELLO.
- */
-static enum GNUNET_GenericReturnValue
-free_hello (void *cls,
-            const struct GNUNET_PeerIdentity *key,
-            void *hello)
-{
-  GNUNET_free (hello);
-  return GNUNET_OK;
-}
-
-
-/**
- * Shutdown HELLO subsystem.
- */
-void
-GDS_HELLO_done ()
-{
-  if (NULL != pnc)
-  {
-    GNUNET_PEERINFO_notify_cancel (pnc);
-    pnc = NULL;
-  }
-  if (NULL != peer_to_hello)
-  {
-    GNUNET_CONTAINER_multipeermap_iterate (peer_to_hello,
-                                           &free_hello,
-                                           NULL);
-    GNUNET_CONTAINER_multipeermap_destroy (peer_to_hello);
-  }
-}
-
-
-/* end of gnunet-service-dht_hello.c */
diff --git a/src/dht/gnunet-service-dht_hello.h 
b/src/dht/gnunet-service-dht_hello.h
deleted file mode 100644
index f8b90862d..000000000
--- a/src/dht/gnunet-service-dht_hello.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2011 GNUnet e.V.
-
-     GNUnet is free software: you can redistribute it and/or modify it
-     under the terms of the GNU Affero General Public License as published
-     by the Free Software Foundation, either version 3 of the License,
-     or (at your option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     Affero General Public License for more details.
-
-     You should have received a copy of the GNU Affero General Public License
-     along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-     SPDX-License-Identifier: AGPL3.0-or-later
- */
-
-/**
- * @file dht/gnunet-service-dht_hello.h
- * @brief GNUnet DHT integration with peerinfo
- * @author Christian Grothoff
- */
-#ifndef GNUNET_SERVICE_DHT_HELLO_H
-#define GNUNET_SERVICE_DHT_HELLO_H
-
-#include "gnunet_util_lib.h"
-#include "gnunet_hello_lib.h"
-
-/**
- * Obtain a peer's HELLO if available
- *
- * @param peer peer to look for a HELLO from
- * @return HELLO for the given peer
- */
-const struct GNUNET_HELLO_Message *
-GDS_HELLO_get (const struct GNUNET_PeerIdentity *peer);
-
-
-/**
- * Initialize HELLO subsystem.
- */
-void
-GDS_HELLO_init (void);
-
-
-/**
- * Shutdown HELLO subsystem.
- */
-void
-GDS_HELLO_done (void);
-
-#endif
diff --git a/src/dht/gnunet-service-dht_neighbours.c 
b/src/dht/gnunet-service-dht_neighbours.c
index bc473df69..b7b5e8097 100644
--- a/src/dht/gnunet-service-dht_neighbours.c
+++ b/src/dht/gnunet-service-dht_neighbours.c
@@ -29,8 +29,8 @@
 #include "gnunet_protocols.h"
 #include "gnunet_signatures.h"
 #include "gnunet_hello_lib.h"
+#include "gnunet_hello_uri_lib.h"
 #include "gnunet-service-dht.h"
-#include "gnunet-service-dht_hello.h"
 #include "gnunet-service-dht_neighbours.h"
 #include "gnunet-service-dht_routing.h"
 #include "dht.h"
@@ -88,11 +88,6 @@
  */
 #define GET_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 2)
 
-/**
- * Hello address expiration
- */
-extern struct GNUNET_TIME_Relative hello_expiration;
-
 
 GNUNET_NETWORK_STRUCT_BEGIN
 
@@ -260,81 +255,129 @@ GNUNET_NETWORK_STRUCT_END
 /**
  * Entry for a peer in a bucket.
  */
-struct PeerInfo
+struct PeerInfo;
+
+
+/**
+ * List of targets that we can use to reach this peer.
+ */
+struct Target
 {
   /**
-   * Next peer entry (DLL)
+   * Kept in a DLL.
    */
-  struct PeerInfo *next;
+  struct Target *next;
 
   /**
-   *  Prev peer entry (DLL)
+   * Kept in a DLL.
    */
-  struct PeerInfo *prev;
+  struct Target *prev;
 
   /**
    * Handle for sending messages to this peer.
    */
-  struct GNUNET_DHTU_Target *target;
+  struct GNUNET_DHTU_Target *utarget;
 
   /**
-   * What is the identity of the peer?
+   * Underlay providing this target.
    */
-  struct GNUNET_PeerIdentity id;
+  struct Underlay *u;
 
   /**
-   * Hash of @e id.
+   * Peer this is a target for.
    */
-  struct GNUNET_HashCode phash;
+  struct PeerInfo *pi;
 
   /**
-   * Which bucket is this peer in?
+   * Set to number of messages are waiting for the transmission to finish.
    */
-  int peer_bucket;
+  unsigned int load;
+
+  /**
+   * Set to @a true if the target was dropped, but we could not clean
+   * up yet because @e busy was also true.
+   */
+  bool dropped;
+
 };
 
 
 /**
- * Peers are grouped into buckets.
+ * Entry for a peer in a bucket.
  */
-struct PeerBucket
+struct PeerInfo
 {
   /**
-   * Head of DLL
+   * What is the identity of the peer?
    */
-  struct PeerInfo *head;
+  struct GNUNET_PeerIdentity id;
 
   /**
-   * Tail of DLL
+   * Hash of @e id.
    */
-  struct PeerInfo *tail;
+  struct GNUNET_HashCode phash;
 
   /**
-   * Number of peers in the bucket.
+   * When does our HELLO from this peer expire?
    */
-  unsigned int peers_size;
+  struct GNUNET_TIME_Absolute hello_expiration;
+
+  /**
+   * Next peer entry (DLL)
+   */
+  struct PeerInfo *next;
+
+  /**
+   *  Prev peer entry (DLL)
+   */
+  struct PeerInfo *prev;
+
+  /**
+   * Head of DLL of targets for this peer.
+   */
+  struct Target *t_head;
+
+  /**
+   * Tail of DLL of targets for this peer.
+   */
+  struct Target *t_tail;
+
+  /**
+   * Block with a HELLO of this peer.
+   */
+  void *hello;
+
+  /**
+   * Number of bytes in @e hello.
+   */
+  size_t hello_size;
+
+  /**
+   * Which bucket is this peer in?
+   */
+  int peer_bucket;
 };
 
 
 /**
- * Information about a peer that we would like to connect to.
+ * Peers are grouped into buckets.
  */
-struct ConnectInfo
+struct PeerBucket
 {
   /**
-   * Handle to active HELLO offer operation, or NULL.
+   * Head of DLL
    */
-  struct GNUNET_TRANSPORT_OfferHelloHandle *oh;
+  struct PeerInfo *head;
 
   /**
-   * Handle to active connectivity suggestion operation, or NULL.
+   * Tail of DLL
    */
-  struct GNUNET_DHTU_PreferenceHandle *ph;
+  struct PeerInfo *tail;
 
   /**
-   * How much would we like to connect to this peer?
+   * Number of peers in the bucket.
    */
-  uint32_t strength;
+  unsigned int peers_size;
 };
 
 
@@ -370,12 +413,6 @@ static struct PeerBucket k_buckets[MAX_BUCKETS];
  */
 static struct GNUNET_CONTAINER_MultiPeerMap *all_connected_peers;
 
-/**
- * Hash map of all peers we would like to be connected to.
- * Values are of type `struct ConnectInfo`.
- */
-static struct GNUNET_CONTAINER_MultiPeerMap *all_desired_peers;
-
 /**
  * Maximum size for each bucket.
  */
@@ -386,20 +423,83 @@ static unsigned int bucket_size = DEFAULT_BUCKET_SIZE;
  */
 static struct GNUNET_SCHEDULER_Task *find_peer_task;
 
-/**
- * Identity of this peer.
- */
-static struct GNUNET_PeerIdentity my_identity;
 
 /**
- * Hash of the identity of this peer.
+ * Function called whenever we finished sending to a target.
+ * Marks the transmission as finished (and the target as ready
+ * for the next message).
+ *
+ * @param cls a `struct Target *`
  */
-struct GNUNET_HashCode my_identity_hash;
+static void
+send_done_cb (void *cls)
+{
+  struct Target *t = cls;
+  struct PeerInfo *pi = t->pi; /* NULL if t->dropped! */
+
+  GNUNET_assert (t->load > 0);
+  t->load--;
+  if (0 < t->load)
+    return;
+  if (t->dropped)
+  {
+    GNUNET_free (t);
+    return;
+  }
+  /* move target back to the front */
+  GNUNET_CONTAINER_DLL_remove (pi->t_head,
+                               pi->t_tail,
+                               t);
+  GNUNET_CONTAINER_DLL_insert (pi->t_head,
+                               pi->t_tail,
+                               t);
+}
+
 
 /**
- * Our private key.
+ * Send @a msg to @a pi.
+ *
+ * @param pi where to send the message
+ * @param msg message to send
  */
-static struct GNUNET_CRYPTO_EddsaPrivateKey my_private_key;
+static void
+do_send (struct PeerInfo *pi,
+         const struct GNUNET_MessageHeader *msg)
+{
+  struct Target *t;
+
+  for (t = pi->t_head;
+       NULL != t;
+       t = t->next)
+    if (t->load < MAXIMUM_PENDING_PER_PEER)
+      break;
+  if (NULL == t)
+  {
+    /* all targets busy, drop message */
+    GNUNET_STATISTICS_update (GDS_stats,
+                              "# messages dropped (underlays busy)",
+                              1,
+                              GNUNET_NO);
+    return;
+  }
+  t->load++;
+  /* rotate busy targets to the end */
+  if (MAXIMUM_PENDING_PER_PEER == t->load)
+  {
+    GNUNET_CONTAINER_DLL_remove (pi->t_head,
+                                 pi->t_tail,
+                                 t);
+    GNUNET_CONTAINER_DLL_insert_tail (pi->t_head,
+                                      pi->t_tail,
+                                      t);
+  }
+  GDS_u_send (t->u,
+              t->utarget,
+              msg,
+              ntohs (msg->size),
+              &send_done_cb,
+              t);
+}
 
 
 /**
@@ -436,7 +536,7 @@ sign_path (const struct GNUNET_HashCode *key,
   GNUNET_CRYPTO_hash (data,
                       data_size,
                       &hs.h_data);
-  GNUNET_CRYPTO_eddsa_sign (&my_private_key,
+  GNUNET_CRYPTO_eddsa_sign (&GDS_my_private_key,
                             &hs,
                             sig);
 }
@@ -456,7 +556,7 @@ find_bucket (const struct GNUNET_HashCode *hc)
   unsigned int bits;
 
   GNUNET_CRYPTO_hash_xor (hc,
-                          &my_identity_hash,
+                          &GDS_my_identity_hash,
                           &xor);
   bits = GNUNET_CRYPTO_hash_count_leading_zeros (&xor);
   if (bits == MAX_BUCKETS)
@@ -469,175 +569,6 @@ find_bucket (const struct GNUNET_HashCode *hc)
 }
 
 
-/**
- * Function called when #GNUNET_TRANSPORT_offer_hello() is done.
- * Clean up the "oh" field in the @a cls
- *
- * @param cls a `struct ConnectInfo`
- */
-static void
-offer_hello_done (void *cls)
-{
-  struct ConnectInfo *ci = cls;
-
-  ci->oh = NULL;
-}
-
-
-/**
- * Function called for all entries in #all_desired_peers to clean up.
- *
- * @param cls NULL
- * @param peer peer the entry is for
- * @param value the value to remove
- * @return #GNUNET_YES
- */
-static enum GNUNET_GenericReturnValue
-free_connect_info (void *cls,
-                   const struct GNUNET_PeerIdentity *peer,
-                   void *value)
-{
-  struct ConnectInfo *ci = value;
-
-  (void) cls;
-  GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multipeermap_remove (all_desired_peers,
-                                                       peer,
-                                                       ci));
-  if (NULL != ci->ph)
-  {
-    // ci->u->drop (ci->ph); // FIXME!
-    ci->ph = NULL;
-  }
-  if (NULL != ci->oh)
-  {
-    GNUNET_TRANSPORT_offer_hello_cancel (ci->oh);
-    ci->oh = NULL;
-  }
-  GNUNET_free (ci);
-  return GNUNET_YES;
-}
-
-
-/**
- * Consider if we want to connect to a given peer, and if so
- * let ATS know.  If applicable, the HELLO is offered to the
- * TRANSPORT service.
- *
- * @param pid peer to consider connectivity requirements for
- * @param h a HELLO message, or NULL
- */
-static void
-try_connect (const struct GNUNET_PeerIdentity *pid,
-             const struct GNUNET_MessageHeader *h)
-{
-  int bucket_idx;
-  struct GNUNET_HashCode pid_hash;
-  struct ConnectInfo *ci;
-  uint32_t strength;
-  struct PeerBucket *bucket;
-
-  GNUNET_CRYPTO_hash (pid,
-                      sizeof(struct GNUNET_PeerIdentity),
-                      &pid_hash);
-  bucket_idx = find_bucket (&pid_hash);
-  if (bucket_idx < 0)
-  {
-    GNUNET_break (0);
-    return; /* self!? */
-  }
-  bucket = &k_buckets[bucket_idx];
-  ci = GNUNET_CONTAINER_multipeermap_get (all_desired_peers,
-                                          pid);
-  if (bucket->peers_size < bucket_size)
-    strength = (bucket_size - bucket->peers_size) * bucket_idx;
-  else
-    strength = 0;
-  if (GNUNET_YES ==
-      GNUNET_CONTAINER_multipeermap_contains (all_connected_peers,
-                                              pid))
-    strength *= 2; /* double for connected peers */
-  if ( (0 == strength) &&
-       (NULL != ci) )
-  {
-    /* release request */
-    GNUNET_assert (GNUNET_YES ==
-                   free_connect_info (NULL,
-                                      pid,
-                                      ci));
-    return;
-  }
-  if (NULL == ci)
-  {
-    ci = GNUNET_new (struct ConnectInfo);
-    GNUNET_assert (GNUNET_OK ==
-                   GNUNET_CONTAINER_multipeermap_put (all_desired_peers,
-                                                      pid,
-                                                      ci,
-                                                      
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
-  }
-  if ( (NULL != ci->oh) &&
-       (NULL != h) )
-    GNUNET_TRANSPORT_offer_hello_cancel (ci->oh);
-  if (NULL != h)
-    ci->oh = GNUNET_TRANSPORT_offer_hello (GDS_cfg,
-                                           h,
-                                           &offer_hello_done,
-                                           ci);
-  if ( (NULL != ci->ph) &&
-       (ci->strength != strength) )
-  {
-    // ci->u_api->drop (ci->ph);
-    ci->ph = NULL;
-  }
-  if (ci->strength != strength)
-  {
-#if FIXME
-    ci->ph = ci->u_api->hold (ci->u_api->cls,
-                              TARGET);
-#endif
-    ci->strength = strength;
-  }
-}
-
-
-/**
- * Function called for each peer in #all_desired_peers during
- * #update_connect_preferences() if we have reason to adjust
- * the strength of our desire to keep connections to certain
- * peers.  Calls #try_connect() to update the calculations for
- * the given @a pid.
- *
- * @param cls NULL
- * @param pid peer to update
- * @param value unused
- * @return #GNUNET_YES (continue to iterate)
- */
-static enum GNUNET_GenericReturnValue
-update_desire_strength (void *cls,
-                        const struct GNUNET_PeerIdentity *pid,
-                        void *value)
-{
-  (void) cls;
-  (void) value;
-  try_connect (pid,
-               NULL);
-  return GNUNET_YES;
-}
-
-
-/**
- * Update our preferences for connectivity as given to ATS.
- */
-static void
-update_connect_preferences (void)
-{
-  GNUNET_CONTAINER_multipeermap_iterate (all_desired_peers,
-                                         &update_desire_strength,
-                                         NULL);
-}
-
-
 /**
  * Add each of the peers we already know to the Bloom filter of
  * the request so that we don't get duplicate HELLOs.
@@ -728,11 +659,11 @@ send_find_peer_message (void *cls)
                                            GNUNET_CONSTANTS_BLOOMFILTER_K);
     if (GNUNET_OK !=
         GDS_NEIGHBOURS_handle_get (GNUNET_BLOCK_TYPE_DHT_URL_HELLO,
-                                   GNUNET_DHT_RO_FIND_PEER
+                                   GNUNET_DHT_RO_FIND_APPROXIMATE
                                    | GNUNET_DHT_RO_RECORD_ROUTE,
                                    FIND_PEER_REPLICATION_LEVEL,
                                    0, /* hop count */
-                                   &my_identity_hash,
+                                   &GDS_my_identity_hash,
                                    NULL, 0, /* xquery */
                                    bg,
                                    peer_bf))
@@ -761,106 +692,131 @@ GDS_u_connect (void *cls,
                const struct GNUNET_PeerIdentity *pid,
                void **ctx)
 {
+  struct Underlay *u = cls;
   struct PeerInfo *pi;
   struct PeerBucket *bucket;
 
-  (void) cls;
   /* Check for connect to self message */
-  if (0 == GNUNET_memcmp (&my_identity,
+  if (0 == GNUNET_memcmp (&GDS_my_identity,
                           pid))
     return;
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Connected to peer %s\n",
               GNUNET_i2s (pid));
-  GNUNET_assert (NULL ==
-                 GNUNET_CONTAINER_multipeermap_get (all_connected_peers,
-                                                    pid));
-  GNUNET_STATISTICS_update (GDS_stats,
-                            "# peers connected",
-                            1,
-                            GNUNET_NO);
-  pi = GNUNET_new (struct PeerInfo);
-  pi->id = *pid;
-  pi->target = target;
-  GNUNET_CRYPTO_hash (pid,
-                      sizeof(*pid),
-                      &pi->phash);
-  pi->peer_bucket = find_bucket (&pi->phash);
-  GNUNET_assert ( (pi->peer_bucket >= 0) &&
-                  ((unsigned int) pi->peer_bucket < MAX_BUCKETS));
-  bucket = &k_buckets[pi->peer_bucket];
-  GNUNET_CONTAINER_DLL_insert_tail (bucket->head,
-                                    bucket->tail,
-                                    pi);
-  bucket->peers_size++;
-  closest_bucket = GNUNET_MAX (closest_bucket,
-                               (unsigned int) pi->peer_bucket + 1);
-  GNUNET_assert (GNUNET_OK ==
-                 GNUNET_CONTAINER_multipeermap_put (all_connected_peers,
-                                                    &pi->id,
-                                                    pi,
-                                                    
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
-  if (bucket->peers_size <= bucket_size)
+  pi = GNUNET_CONTAINER_multipeermap_get (all_connected_peers,
+                                          pid);
+  if (NULL == pi)
   {
-    update_connect_preferences ();
-    newly_found_peers++;
+    GNUNET_STATISTICS_update (GDS_stats,
+                              "# peers connected",
+                              1,
+                              GNUNET_NO);
+    pi = GNUNET_new (struct PeerInfo);
+    pi->id = *pid;
+    GNUNET_CRYPTO_hash (pid,
+                        sizeof(*pid),
+                        &pi->phash);
+    pi->peer_bucket = find_bucket (&pi->phash);
+    GNUNET_assert ( (pi->peer_bucket >= 0) &&
+                    ((unsigned int) pi->peer_bucket < MAX_BUCKETS));
+    bucket = &k_buckets[pi->peer_bucket];
+    GNUNET_CONTAINER_DLL_insert_tail (bucket->head,
+                                      bucket->tail,
+                                      pi);
+    bucket->peers_size++;
+    closest_bucket = GNUNET_MAX (closest_bucket,
+                                 (unsigned int) pi->peer_bucket + 1);
+    GNUNET_assert (GNUNET_OK ==
+                   GNUNET_CONTAINER_multipeermap_put (all_connected_peers,
+                                                      &pi->id,
+                                                      pi,
+                                                      
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+    if (bucket->peers_size <= bucket_size)
+    {
+      newly_found_peers++;
+      // FIXME: call 'hold'!
+    }
+    if ( (1 == GNUNET_CONTAINER_multipeermap_size (all_connected_peers)) &&
+         (GNUNET_YES != disable_try_connect) )
+    {
+      /* got a first connection, good time to start with FIND PEER requests... 
*/
+      GNUNET_assert (NULL == find_peer_task);
+      find_peer_task = GNUNET_SCHEDULER_add_now (&send_find_peer_message,
+                                                 NULL);
+    }
   }
-  if ( (1 == GNUNET_CONTAINER_multipeermap_size (all_connected_peers)) &&
-       (GNUNET_YES != disable_try_connect) )
   {
-    /* got a first connection, good time to start with FIND PEER requests... */
-    GNUNET_assert (NULL == find_peer_task);
-    find_peer_task = GNUNET_SCHEDULER_add_now (&send_find_peer_message,
-                                               NULL);
+    struct Target *t;
+
+    t = GNUNET_new (struct Target);
+    t->u = u;
+    t->utarget = target;
+    t->pi = pi;
+    GNUNET_CONTAINER_DLL_insert (pi->t_head,
+                                 pi->t_tail,
+                                 t);
+    *ctx = t;
+
   }
-  *ctx = pi;
 }
 
 
-/**
- * Method called whenever a peer disconnects.
- *
- * @param ctx context
- */
 void
 GDS_u_disconnect (void *ctx)
 {
-  struct PeerInfo *to_remove = ctx;
+  struct Target *t = ctx;
+  struct PeerInfo *pi;
   struct PeerBucket *bucket;
 
   /* Check for disconnect from self message (on shutdown) */
-  if (NULL == to_remove)
+  if (NULL == t)
     return;
+  pi = t->pi;
+  GNUNET_CONTAINER_DLL_remove (pi->t_head,
+                               pi->t_tail,
+                               t);
+  if (t->load > 0)
+  {
+    t->dropped = true;
+    t->pi = NULL;
+  }
+  else
+  {
+    GNUNET_free (t);
+  }
+  if (NULL != pi->t_head)
+    return; /* got other connections still */
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Disconnected from peer %s\n",
-              GNUNET_i2s (&to_remove->id));
+              GNUNET_i2s (&pi->id));
   GNUNET_STATISTICS_update (GDS_stats,
                             "# peers connected",
                             -1,
                             GNUNET_NO);
   GNUNET_assert (GNUNET_YES ==
                  GNUNET_CONTAINER_multipeermap_remove (all_connected_peers,
-                                                       &to_remove->id,
-                                                       to_remove));
+                                                       &pi->id,
+                                                       pi));
   if ( (0 == GNUNET_CONTAINER_multipeermap_size (all_connected_peers)) &&
        (GNUNET_YES != disable_try_connect))
   {
     GNUNET_SCHEDULER_cancel (find_peer_task);
     find_peer_task = NULL;
   }
-  GNUNET_assert (to_remove->peer_bucket >= 0);
-  bucket = &k_buckets[to_remove->peer_bucket];
+  GNUNET_assert (pi->peer_bucket >= 0);
+  bucket = &k_buckets[pi->peer_bucket];
   GNUNET_CONTAINER_DLL_remove (bucket->head,
                                bucket->tail,
-                               to_remove);
+                               pi);
   GNUNET_assert (bucket->peers_size > 0);
   bucket->peers_size--;
+  // FIXME: check if this peer was in one of the first 'bucket_size'
+  // peers, and call 'hold' on the next peer if there is any!
   while ( (closest_bucket > 0) &&
           (0 == k_buckets[closest_bucket - 1].peers_size))
     closest_bucket--;
-  if (bucket->peers_size < bucket_size)
-    update_connect_preferences ();
-  GNUNET_free (to_remove);
+  GNUNET_free (pi->hello);
+  GNUNET_free (pi);
 }
 
 
@@ -935,7 +891,7 @@ enum GNUNET_GenericReturnValue
 GDS_am_closest_peer (const struct GNUNET_HashCode *key,
                      const struct GNUNET_CONTAINER_BloomFilter *bloom)
 {
-  if (0 == GNUNET_memcmp (&my_identity_hash,
+  if (0 == GNUNET_memcmp (&GDS_my_identity_hash,
                           key))
     return GNUNET_YES;
   for (int bucket_num = find_bucket (key);
@@ -962,7 +918,7 @@ GDS_am_closest_peer (const struct GNUNET_HashCode *key,
          because an unfiltered peer exists, we are not the
          closest. */
       int delta = GNUNET_CRYPTO_hash_xorcmp (&pos->phash,
-                                             &my_identity_hash,
+                                             &GDS_my_identity_hash,
                                              key);
       switch (delta)
       {
@@ -1026,7 +982,7 @@ select_peer (const struct GNUNET_HashCode *key,
       struct GNUNET_HashCode xor;
 
       GNUNET_CRYPTO_hash_xor (key,
-                              &my_identity_hash,
+                              &GDS_my_identity_hash,
                               &xor);
       best_bucket = GNUNET_CRYPTO_hash_count_leading_zeros (&xor);
     }
@@ -1046,9 +1002,10 @@ select_peer (const struct GNUNET_HashCode *key,
         if (count >= bucket_size)
           break; /* we only consider first #bucket_size entries per bucket */
         count++;
-        if (GNUNET_YES ==
-            GNUNET_CONTAINER_bloomfilter_test (bloom,
-                                               &pos->phash))
+        if ( (NULL != bloom) &&
+             (GNUNET_YES ==
+              GNUNET_CONTAINER_bloomfilter_test (bloom,
+                                                 &pos->phash)) )
         {
           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                       "Excluded peer `%s' due to BF match in greedy routing 
for %s\n",
@@ -1134,18 +1091,20 @@ select_peer (const struct GNUNET_HashCode *key,
 
     for (unsigned int bc = 0; bc < closest_bucket; bc++)
     {
+      struct PeerBucket *bucket = &k_buckets[bc];
       unsigned int count = 0;
 
-      for (struct PeerInfo *pos = k_buckets[bc].head;
+      for (struct PeerInfo *pos = bucket->head;
            NULL != pos;
            pos = pos->next)
       {
         count++;
         if (count > bucket_size)
           break; /* limits search to #bucket_size peers per bucket */
-        if (GNUNET_YES ==
-            GNUNET_CONTAINER_bloomfilter_test (bloom,
-                                               &pos->phash))
+        if ( (NULL != bloom) &&
+             (GNUNET_YES ==
+              GNUNET_CONTAINER_bloomfilter_test (bloom,
+                                                 &pos->phash)) )
         {
           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                       "Excluded peer `%s' due to BF match in random routing 
for %s\n",
@@ -1180,9 +1139,10 @@ select_peer (const struct GNUNET_HashCode *key,
         if (count > bucket_size)
           break; /* limits search to #bucket_size peers per bucket */
 
-        if (GNUNET_YES ==
-            GNUNET_CONTAINER_bloomfilter_test (bloom,
-                                               &pos->phash))
+        if ( (NULL != bloom) &&
+             (GNUNET_YES ==
+              GNUNET_CONTAINER_bloomfilter_test (bloom,
+                                                 &pos->phash)) )
           continue;             /* Ignore bloomfiltered peers */
         if (0 == selected--)
         {
@@ -1296,7 +1256,7 @@ GDS_NEIGHBOURS_handle_put (const struct 
GDS_DATACACHE_BlockData *bd,
                               bd->put_path,
                               bd->put_path_length,
                               NULL, 0, /* get_path */
-                              &my_identity))
+                              &GDS_my_identity))
   {
     GNUNET_break_op (0);
     put_path_length = 0;
@@ -1304,10 +1264,10 @@ GDS_NEIGHBOURS_handle_put (const struct 
GDS_DATACACHE_BlockData *bd,
 #endif
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Adding myself (%s) to PUT bloomfilter for %s\n",
-              GNUNET_i2s (&my_identity),
+              GNUNET_i2s (&GDS_my_identity),
               GNUNET_h2s (&bd->key));
   GNUNET_CONTAINER_bloomfilter_add (bf,
-                                    &my_identity_hash);
+                                    &GDS_my_identity_hash);
   GNUNET_STATISTICS_update (GDS_stats,
                             "# PUT requests routed",
                             1,
@@ -1324,7 +1284,7 @@ GDS_NEIGHBOURS_handle_put (const struct 
GDS_DATACACHE_BlockData *bd,
                 "Routing PUT for %s terminates after %u hops at %s\n",
                 GNUNET_h2s (&bd->key),
                 (unsigned int) hop_count,
-                GNUNET_i2s (&my_identity));
+                GNUNET_i2s (&GDS_my_identity));
     return GNUNET_NO;
   }
   msize = bd->put_path_length * sizeof(struct GNUNET_DHT_PathElement)
@@ -1346,30 +1306,18 @@ GDS_NEIGHBOURS_handle_put (const struct 
GDS_DATACACHE_BlockData *bd,
   for (unsigned int i = 0; i < target_count; i++)
   {
     struct PeerInfo *target = targets[i];
-    struct GNUNET_MQ_Envelope *env;
     struct PeerPutMessage *ppm;
+    char buf[sizeof (*ppm) + msize] GNUNET_ALIGN;
     struct GNUNET_DHT_PathElement *pp;
 
-#if FIXME_LEGACY
-    if (GNUNET_MQ_get_length (target->mq) >= MAXIMUM_PENDING_PER_PEER)
-    {
-      /* skip */
-      GNUNET_STATISTICS_update (GDS_stats,
-                                "# P2P messages dropped due to full queue",
-                                1,
-                                GNUNET_NO);
-      skip_count++;
-      continue;
-    }
-#endif
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "Routing PUT for %s after %u hops to %s\n",
                 GNUNET_h2s (&bd->key),
                 (unsigned int) hop_count,
                 GNUNET_i2s (&target->id));
-    env = GNUNET_MQ_msg_extra (ppm,
-                               msize,
-                               GNUNET_MESSAGE_TYPE_DHT_P2P_PUT);
+    ppm = (struct PeerPutMessage *) buf;
+    ppm->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_P2P_PUT);
+    ppm->header.size = htons (sizeof (buf));
     ppm->options = htonl (options);
     ppm->type = htonl (bd->type);
     ppm->hop_count = htonl (hop_count + 1);
@@ -1405,10 +1353,8 @@ GDS_NEIGHBOURS_handle_put (const struct 
GDS_DATACACHE_BlockData *bd,
     GNUNET_memcpy (&pp[put_path_length],
                    bd->data,
                    bd->data_size);
-#if FIXME
-    GNUNET_MQ_send (target->mq,
-                    env);
-#endif
+    do_send (target,
+             &ppm->header);
   }
   GNUNET_free (targets);
   GNUNET_STATISTICS_update (GDS_stats,
@@ -1450,17 +1396,17 @@ GDS_NEIGHBOURS_handle_get (enum GNUNET_BLOCK_Type type,
                                    &targets);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Adding myself (%s) to GET bloomfilter for %s\n",
-              GNUNET_i2s (&my_identity),
+              GNUNET_i2s (&GDS_my_identity),
               GNUNET_h2s (key));
   GNUNET_CONTAINER_bloomfilter_add (peer_bf,
-                                    &my_identity_hash);
+                                    &GDS_my_identity_hash);
   if (0 == target_count)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "Routing GET for %s terminates after %u hops at %s\n",
                 GNUNET_h2s (key),
                 (unsigned int) hop_count,
-                GNUNET_i2s (&my_identity));
+                GNUNET_i2s (&GDS_my_identity));
     return GNUNET_NO;
   }
   if (GNUNET_OK !=
@@ -1487,30 +1433,18 @@ GDS_NEIGHBOURS_handle_get (enum GNUNET_BLOCK_Type type,
   for (unsigned int i = 0; i < target_count; i++)
   {
     struct PeerInfo *target = targets[i];
-    struct GNUNET_MQ_Envelope *env;
     struct PeerGetMessage *pgm;
+    char buf[sizeof (*pgm) + msize] GNUNET_ALIGN;
     char *xq;
 
-#if FIXME
-    if (GNUNET_MQ_get_length (target->mq) >= MAXIMUM_PENDING_PER_PEER)
-    {
-      /* skip */
-      GNUNET_STATISTICS_update (GDS_stats,
-                                "# P2P messages dropped due to full queue",
-                                1,
-                                GNUNET_NO);
-      skip_count++;
-      continue;
-    }
-#endif
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "Routing GET for %s after %u hops to %s\n",
                 GNUNET_h2s (key),
                 (unsigned int) hop_count,
                 GNUNET_i2s (&target->id));
-    env = GNUNET_MQ_msg_extra (pgm,
-                               msize,
-                               GNUNET_MESSAGE_TYPE_DHT_P2P_GET);
+    pgm = (struct PeerGetMessage *) buf;
+    pgm->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_P2P_GET);
+    pgm->header.size = htons (sizeof (buf));
     pgm->options = htonl (options);
     pgm->type = htonl (type);
     pgm->hop_count = htonl (hop_count + 1);
@@ -1532,10 +1466,8 @@ GDS_NEIGHBOURS_handle_get (enum GNUNET_BLOCK_Type type,
     GNUNET_memcpy (&xq[xquery_size],
                    reply_bf,
                    reply_bf_size);
-#if FIXME
-    GNUNET_MQ_send (target->mq,
-                    env);
-#endif
+    do_send (target,
+             &pgm->header);
   }
   GNUNET_STATISTICS_update (GDS_stats,
                             "# GET messages queued for transmission",
@@ -1562,8 +1494,6 @@ GDS_NEIGHBOURS_handle_reply (struct PeerInfo *pi,
                              unsigned int get_path_length,
                              const struct GNUNET_DHT_PathElement *get_path)
 {
-  struct GNUNET_MQ_Envelope *env;
-  struct PeerResultMessage *prm;
   struct GNUNET_DHT_PathElement *paths;
   size_t msize;
   unsigned int ppl = bd->put_path_length;
@@ -1578,7 +1508,7 @@ GDS_NEIGHBOURS_handle_reply (struct PeerInfo *pi,
                               bd->put_path_length,
                               get_path,
                               get_path_length,
-                              &my_identity))
+                              &GDS_my_identity))
   {
     GNUNET_break_op (0);
     get_path_length = 0;
@@ -1609,20 +1539,6 @@ GDS_NEIGHBOURS_handle_reply (struct PeerInfo *pi,
     GNUNET_break (0);
     return;
   }
-#if FIXME
-  if (GNUNET_MQ_get_length (pi->mq) >= MAXIMUM_PENDING_PER_PEER)
-  {
-    /* skip */
-    GNUNET_STATISTICS_update (GDS_stats,
-                              "# P2P messages dropped due to full queue",
-                              1,
-                              GNUNET_NO);
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Peer queue full, ignoring reply for key %s\n",
-                GNUNET_h2s (&bd->key));
-    return;
-  }
-#endif
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Forwarding reply for key %s to peer %s\n",
               GNUNET_h2s (query_hash),
@@ -1631,41 +1547,44 @@ GDS_NEIGHBOURS_handle_reply (struct PeerInfo *pi,
                             "# RESULT messages queued for transmission",
                             1,
                             GNUNET_NO);
-  env = GNUNET_MQ_msg_extra (prm,
-                             msize,
-                             GNUNET_MESSAGE_TYPE_DHT_P2P_RESULT);
-  prm->type = htonl (bd->type);
-  prm->put_path_length = htonl (ppl);
-  prm->get_path_length = htonl (get_path_length);
-  prm->expiration_time = GNUNET_TIME_absolute_hton (bd->expiration_time);
-  prm->key = *query_hash;
-  paths = (struct GNUNET_DHT_PathElement *) &prm[1];
-  GNUNET_memcpy (paths,
-                 bd->put_path,
-                 ppl * sizeof(struct GNUNET_DHT_PathElement));
-  GNUNET_memcpy (&paths[ppl],
-                 get_path,
-                 get_path_length * sizeof(struct GNUNET_DHT_PathElement));
-  /* 0 == get_path_length means path is not being tracked */
-  if (0 != get_path_length)
   {
-    /* Note that the signature in 'get_path' was not initialized before,
-       so this is crucial to avoid sending garbage. */
-    sign_path (&bd->key,
-               bd->data,
-               bd->data_size,
-               bd->expiration_time,
-               &paths[ppl + get_path_length - 1].pred,
-               &pi->id,
-               &paths[ppl + get_path_length - 1].sig);
-  }
-  GNUNET_memcpy (&paths[ppl + get_path_length],
+    struct PeerResultMessage *prm;
+    char buf[sizeof (*prm) + msize] GNUNET_ALIGN;
+
+    prm = (struct PeerResultMessage *) buf;
+    prm->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_P2P_RESULT);
+    prm->header.size = htons (sizeof (buf));
+    prm->type = htonl (bd->type);
+    prm->put_path_length = htonl (ppl);
+    prm->get_path_length = htonl (get_path_length);
+    prm->expiration_time = GNUNET_TIME_absolute_hton (bd->expiration_time);
+    prm->key = *query_hash;
+    paths = (struct GNUNET_DHT_PathElement *) &prm[1];
+    GNUNET_memcpy (paths,
+                   bd->put_path,
+                   ppl * sizeof(struct GNUNET_DHT_PathElement));
+    GNUNET_memcpy (&paths[ppl],
+                   get_path,
+                   get_path_length * sizeof(struct GNUNET_DHT_PathElement));
+    /* 0 == get_path_length means path is not being tracked */
+    if (0 != get_path_length)
+    {
+      /* Note that the signature in 'get_path' was not initialized before,
+         so this is crucial to avoid sending garbage. */
+      sign_path (&bd->key,
                  bd->data,
-                 bd->data_size);
-#if FIXME
-  GNUNET_MQ_send (pi->mq,
-                  env);
-#endif
+                 bd->data_size,
+                 bd->expiration_time,
+                 &paths[ppl + get_path_length - 1].pred,
+                 &pi->id,
+                 &paths[ppl + get_path_length - 1].sig);
+    }
+    GNUNET_memcpy (&paths[ppl + get_path_length],
+                   bd->data,
+                   bd->data_size);
+    do_send (pi,
+             &prm->header);
+  }
 }
 
 
@@ -1819,7 +1738,7 @@ handle_dht_p2p_put (void *cls,
                                   bd.put_path,
                                   putlen,
                                   NULL, 0, /* get_path */
-                                  &my_identity))
+                                  &GDS_my_identity))
       {
         GNUNET_break_op (0);
         putlen = 0;
@@ -1875,45 +1794,60 @@ handle_dht_p2p_put (void *cls,
 
 
 /**
- * We have received a FIND PEER request.  Send matching
- * HELLOs back.
+ * We have received a request for a HELLO.  Sends our
+ * HELLO back.
  *
- * @param pi sender of the FIND PEER request
+ * @param pi sender of the request
  * @param key peers close to this key are desired
  * @param bg group for filtering peers
  */
 static void
-handle_find_peer (struct PeerInfo *pi,
-                  const struct GNUNET_HashCode *query_hash,
-                  struct GNUNET_BLOCK_Group *bg)
+handle_find_my_hello (struct PeerInfo *pi,
+                      const struct GNUNET_HashCode *query_hash,
+                      struct GNUNET_BLOCK_Group *bg)
 {
-  int bucket_idx;
-  struct PeerBucket *bucket;
-  struct PeerInfo *peer;
-  unsigned int choice;
-  struct GDS_DATACACHE_BlockData bd = {
-    .type = GNUNET_BLOCK_TYPE_DHT_URL_HELLO
-  };
-
-  /* first, check about our own HELLO */
-  if (NULL != GDS_my_hello)
+  size_t block_size = 0;
+
+  /* TODO: consider caching our HELLO block for a bit, to
+     avoid signing too often here... */
+  GNUNET_break (GNUNET_NO ==
+                GNUNET_HELLO_builder_to_block (GDS_my_hello,
+                                               &GDS_my_private_key,
+                                               NULL,
+                                               &block_size));
   {
-    bd.expiration_time = GNUNET_TIME_relative_to_absolute (
-      hello_expiration),
-    bd.key = my_identity_hash,
-    bd.data = GDS_my_hello;
-    bd.data_size = GNUNET_HELLO_size (
-      (const struct GNUNET_HELLO_Message *) GDS_my_hello);
-    GNUNET_break (bd.data_size >= sizeof(struct GNUNET_MessageHeader));
-    if (GNUNET_BLOCK_REPLY_OK_MORE ==
-        GNUNET_BLOCK_check_reply (GDS_block_context,
-                                  GNUNET_BLOCK_TYPE_DHT_URL_HELLO,
-                                  bg,
-                                  &my_identity_hash,
-                                  NULL, 0,
-                                  bd.data,
-                                  bd.data_size))
+    char block[block_size];
+
+    if (GNUNET_OK !=
+        GNUNET_HELLO_builder_to_block (GDS_my_hello,
+                                       &GDS_my_private_key,
+                                       block,
+                                       &block_size))
     {
+      GNUNET_STATISTICS_update (GDS_stats,
+                                "# FIND PEER requests ignored due to lack of 
HELLO",
+                                1,
+                                GNUNET_NO);
+    }
+    else if (GNUNET_BLOCK_REPLY_OK_MORE ==
+             GNUNET_BLOCK_check_reply (GDS_block_context,
+                                       GNUNET_BLOCK_TYPE_DHT_URL_HELLO,
+                                       bg,
+                                       &GDS_my_identity_hash,
+                                       NULL, 0,
+                                       block,
+                                       block_size))
+    {
+      struct GDS_DATACACHE_BlockData bd = {
+        .type = GNUNET_BLOCK_TYPE_DHT_URL_HELLO,
+        .expiration_time
+          = GNUNET_TIME_relative_to_absolute (
+              GNUNET_HELLO_ADDRESS_EXPIRATION),
+        .key = GDS_my_identity_hash,
+        .data = block,
+        .data_size = block_size
+      };
+
       GDS_NEIGHBOURS_handle_reply (pi,
                                    &bd,
                                    query_hash,
@@ -1927,66 +1861,48 @@ handle_find_peer (struct PeerInfo *pi,
                                 GNUNET_NO);
     }
   }
-  else
-  {
-    GNUNET_STATISTICS_update (GDS_stats,
-                              "# FIND PEER requests ignored due to lack of 
HELLO",
-                              1,
-                              GNUNET_NO);
-  }
+}
 
-  /* then, also consider sending a random HELLO from the closest bucket */
-  /* FIXME: How can this be true? Shouldnt we just do find_bucket() ? */
-  if (0 ==
-      GNUNET_memcmp (&my_identity_hash,
-                     query_hash))
-    bucket_idx = closest_bucket - 1;
-  else
-    bucket_idx = GNUNET_MIN ((int) closest_bucket - 1,
-                             find_bucket (query_hash));
-  if (bucket_idx < 0)
-    return;
-  bucket = &k_buckets[bucket_idx];
-  if (bucket->peers_size == 0)
-    return;
-  choice = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
-                                     bucket->peers_size);
-  peer = bucket->head;
-  while (choice > 0)
-  {
-    GNUNET_assert (NULL != peer);
-    peer = peer->next;
-    choice--;
-  }
-  choice = bucket->peers_size;
 
+/**
+ * We have received a request for nearby HELLOs.  Sends matching
+ * HELLOs back.
+ *
+ * @param pi sender of the request
+ * @param key peers close to this key are desired
+ * @param bg group for filtering peers
+ */
+static void
+handle_find_local_hello (struct PeerInfo *pi,
+                         const struct GNUNET_HashCode *query_hash,
+                         struct GNUNET_BLOCK_Group *bg)
+{
+  /* Force non-random selection by hop count */
+  struct PeerInfo *peer;
+
+  peer = select_peer (query_hash,
+                      NULL,
+                      GDS_NSE_get () + 1);
+  if ( (NULL != peer->hello) &&
+       (! GNUNET_TIME_absolute_is_past (peer->hello_expiration)) &&
+       (GNUNET_BLOCK_REPLY_OK_MORE ==
+        GNUNET_BLOCK_check_reply (
+          GDS_block_context,
+          GNUNET_BLOCK_TYPE_DHT_URL_HELLO,
+          bg,
+          &peer->phash,
+          NULL, 0,        /* xquery */
+          peer->hello,
+          peer->hello_size)) )
   {
-    const struct GNUNET_HELLO_Message *hello;
-    size_t hello_size;
+    struct GDS_DATACACHE_BlockData bd = {
+      .type = GNUNET_BLOCK_TYPE_DHT_URL_HELLO,
+      .expiration_time = peer->hello_expiration,
+      .key = peer->phash,
+      .data = peer->hello,
+      .data_size = peer->hello_size
+    };
 
-    do
-    {
-      peer = peer->next;
-      if (0 == choice--)
-        return;                 /* no non-masked peer available */
-      if (NULL == peer)
-        peer = bucket->head;
-      hello = GDS_HELLO_get (&peer->id);
-    } while ( (NULL == hello) ||
-              (GNUNET_BLOCK_REPLY_OK_MORE !=
-               GNUNET_BLOCK_check_reply (
-                 GDS_block_context,
-                 GNUNET_BLOCK_TYPE_DHT_URL_HELLO,
-                 bg,
-                 &peer->phash,
-                 NULL, 0, /* xquery */
-                 hello,
-                 (hello_size = GNUNET_HELLO_size (hello)))));
-    bd.expiration_time = GNUNET_TIME_relative_to_absolute (
-      GNUNET_CONSTANTS_HELLO_ADDRESS_EXPIRATION);
-    bd.key = peer->phash;
-    bd.data = hello;
-    bd.data_size = hello_size;
     GDS_NEIGHBOURS_handle_reply (pi,
                                  &bd,
                                  query_hash,
@@ -2101,32 +2017,45 @@ handle_dht_p2p_get (void *cls,
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "GET for %s at %s after %u hops\n",
                 GNUNET_h2s (&get->key),
-                GNUNET_i2s (&my_identity),
+                GNUNET_i2s (&GDS_my_identity),
                 (unsigned int) hop_count);
-    /* local lookup (this may update the reply_bf) */
+    /* local lookup (this may update the bg) */
     if ( (0 != (options & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE)) ||
          (GDS_am_closest_peer (&get->key,
                                peer_bf)) )
     {
-      if ((0 != (options & GNUNET_DHT_RO_FIND_PEER)))
+      if (GNUNET_BLOCK_TYPE_DHT_URL_HELLO == type)
       {
         GNUNET_STATISTICS_update (GDS_stats,
-                                  "# P2P FIND PEER requests processed",
+                                  "# P2P HELLO lookup requests processed",
                                   1,
                                   GNUNET_NO);
-        handle_find_peer (peer,
-                          &get->key,
-                          bg);
+        handle_find_my_hello (peer,
+                              &get->key,
+                              bg);
+        if (0 != (options & GNUNET_DHT_RO_FIND_APPROXIMATE))
+          handle_find_local_hello (peer,
+                                   &get->key,
+                                   bg);
       }
       else
       {
-        eval = GDS_DATACACHE_handle_get (&get->key,
-                                         type,
-                                         xquery,
-                                         xquery_size,
-                                         bg,
-                                         &handle_local_result,
-                                         peer);
+        if (0 != (options & GNUNET_DHT_RO_FIND_APPROXIMATE))
+          eval = GDS_DATACACHE_get_closest (&get->key,
+                                            type,
+                                            xquery,
+                                            xquery_size,
+                                            bg,
+                                            &handle_local_result,
+                                            peer);
+        else
+          eval = GDS_DATACACHE_handle_get (&get->key,
+                                           type,
+                                           xquery,
+                                           xquery_size,
+                                           bg,
+                                           &handle_local_result,
+                                           peer);
       }
     }
     else
@@ -2137,7 +2066,9 @@ handle_dht_p2p_get (void *cls,
                                 GNUNET_NO);
     }
 
-    /* remember request for routing replies */
+    /* remember request for routing replies
+       TODO: why should we do this if GNUNET_BLOCK_REPLY_OK_LAST == eval?
+    */
     GDS_ROUTING_add (&peer->id,
                      type,
                      bg,      /* bg now owned by routing, but valid at least 
until end of this function! */
@@ -2259,6 +2190,52 @@ check_dht_p2p_result (void *cls,
 }
 
 
+/**
+ * Callback function used to extract URIs from a builder.
+ * Called when we should consider connecting to a peer.
+ *
+ * @param cls closure pointing to a `struct GNUNET_PeerIdentity *`
+ * @param uri one of the URIs
+ */
+static void
+try_connect (void *cls,
+             const char *uri)
+{
+  const struct GNUNET_PeerIdentity *pid = cls;
+  struct GNUNET_HashCode phash;
+  int peer_bucket;
+  struct PeerBucket *bucket;
+
+  if (0 == GNUNET_memcmp (&GDS_my_identity,
+                          pid))
+    return; /* that's us! */
+  GNUNET_CRYPTO_hash (pid,
+                      sizeof(*pid),
+                      &phash);
+  peer_bucket = find_bucket (&phash);
+  GNUNET_assert ( (peer_bucket >= 0) &&
+                  ((unsigned int) peer_bucket < MAX_BUCKETS));
+  bucket = &k_buckets[peer_bucket];
+  if (bucket->peers_size >= bucket_size)
+    return; /* do not care */
+  for (struct PeerInfo *pi = bucket->head;
+       NULL != pi;
+       pi = pi->next)
+    if (0 ==
+        GNUNET_memcmp (&pi->id,
+                       pid))
+    {
+      /* already connected */
+      /* TODO: maybe consider 'uri' anyway as an additional
+         alternative address??? */
+      return;
+    }
+  /* new peer that we like! */
+  GDS_u_try_connect (pid,
+                     uri);
+}
+
+
 /**
  * Core handler for p2p result messages.
  *
@@ -2333,32 +2310,17 @@ handle_dht_p2p_result (void *cls,
   /* if we got a HELLO, consider it for our own routing table */
   if (GNUNET_BLOCK_TYPE_DHT_URL_HELLO == bd.type)
   {
-    const struct GNUNET_MessageHeader *h = bd.data;
     struct GNUNET_PeerIdentity pid;
-
-    /* Should be a HELLO, validate and consider using it! */
-    if (bd.data_size < sizeof(struct GNUNET_HELLO_Message))
-    {
-      GNUNET_break (0);
-      return;
-    }
-    if (bd.data_size != ntohs (h->size))
-    {
-      GNUNET_break (0);
-      return;
-    }
-    if (GNUNET_OK !=
-        GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *) h,
-                             &pid))
-    {
-      GNUNET_break_op (0);
-      return;
-    }
-    if ( (GNUNET_YES != disable_try_connect) &&
-         (0 != GNUNET_memcmp (&my_identity,
-                              &pid)) )
-      try_connect (&pid,
-                   h);
+    struct GNUNET_HELLO_Builder *b;
+
+    b = GNUNET_HELLO_builder_from_block (bd.data,
+                                         bd.data_size);
+    if (GNUNET_YES != disable_try_connect)
+      GNUNET_HELLO_builder_iterate (b,
+                                    &pid,
+                                    &try_connect,
+                                    &pid);
+    GNUNET_HELLO_builder_free (b);
   }
 
   /* First, check if 'peer' is already on the path, and if
@@ -2391,6 +2353,50 @@ handle_dht_p2p_result (void *cls,
 }
 
 
+/**
+ * Check validity of a p2p hello message.
+ *
+ * @param cls closure
+ * @param hello message
+ * @return #GNUNET_YES if the message is well-formed
+ */
+static enum GNUNET_GenericReturnValue
+check_dht_p2p_hello (void *cls,
+                     const struct GNUNET_MessageHeader *hello)
+{
+  struct GNUNET_HELLO_Builder *b;
+  enum GNUNET_GenericReturnValue ret;
+
+  b = GNUNET_HELLO_builder_from_msg (hello);
+  ret = (NULL == b) ? GNUNET_SYSERR : GNUNET_OK;
+  GNUNET_HELLO_builder_free (b);
+  return ret;
+}
+
+
+/**
+ * Core handler for p2p HELLO messages.
+ *
+ * @param cls closure
+ * @param message message
+ */
+static void
+handle_dht_p2p_hello (void *cls,
+                      const struct GNUNET_MessageHeader *hello)
+{
+  struct PeerInfo *peer = cls;
+
+  GNUNET_free (peer->hello);
+  peer->hello_size = 0;
+  GNUNET_break (GNUNET_OK ==
+                GNUNET_HELLO_dht_msg_to_block (hello,
+                                               &peer->id,
+                                               &peer->hello,
+                                               &peer->hello_size,
+                                               &peer->hello_expiration));
+}
+
+
 void
 GDS_u_receive (void *cls,
                void **tctx,
@@ -2412,6 +2418,10 @@ GDS_u_receive (void *cls,
                            GNUNET_MESSAGE_TYPE_DHT_P2P_RESULT,
                            struct PeerResultMessage,
                            pi),
+    GNUNET_MQ_hd_var_size (dht_p2p_hello,
+                           GNUNET_MESSAGE_TYPE_DHT_P2P_HELLO,
+                           struct GNUNET_MessageHeader,
+                           pi),
     GNUNET_MQ_handler_end ()
   };
   const struct GNUNET_MessageHeader *mh = message;
@@ -2438,6 +2448,34 @@ GDS_u_receive (void *cls,
 }
 
 
+/**
+ * Send @a msg to all peers in our buckets.
+ *
+ * @param msg message to broadcast
+ */
+void
+GDS_NEIGHBOURS_broadcast (const struct GNUNET_MessageHeader *msg)
+{
+  for (unsigned int bc = 0; bc<closest_bucket; bc++)
+  {
+    struct PeerBucket *bucket = &k_buckets[bc];
+    unsigned int count = 0;
+
+    for (struct PeerInfo *pos = bucket->head;
+         NULL != pos;
+         pos = pos->next)
+    {
+      if (count >= bucket_size)
+        break;   /* we only consider first #bucket_size entries per bucket */
+      count++;
+      GNUNET_break (0);
+      do_send (pos,
+               msg);
+    }
+  }
+}
+
+
 enum GNUNET_GenericReturnValue
 GDS_NEIGHBOURS_init ()
 {
@@ -2458,41 +2496,8 @@ GDS_NEIGHBOURS_init ()
     = GNUNET_CONFIGURATION_get_value_yesno (GDS_cfg,
                                             "DHT",
                                             "CACHE_RESULTS");
-  {
-    char *keyfile;
-
-    if (GNUNET_OK !=
-        GNUNET_CONFIGURATION_get_value_filename (GDS_cfg,
-                                                 "PEER",
-                                                 "PRIVATE_KEY",
-                                                 &keyfile))
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                  "Core service is lacking HOSTKEY configuration setting.  
Exiting.\n");
-      return GNUNET_SYSERR;
-    }
-    if (GNUNET_SYSERR ==
-        GNUNET_CRYPTO_eddsa_key_from_file (keyfile,
-                                           GNUNET_YES,
-                                           &my_private_key))
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                  "Failed to setup peer's private key\n");
-      GNUNET_free (keyfile);
-      return GNUNET_SYSERR;
-    }
-    GNUNET_free (keyfile);
-  }
-  GNUNET_CRYPTO_eddsa_key_get_public (&my_private_key,
-                                      &my_identity.public_key);
-  GNUNET_CRYPTO_hash (&my_identity,
-                      sizeof(struct GNUNET_PeerIdentity),
-                      &my_identity_hash);
-
   all_connected_peers = GNUNET_CONTAINER_multipeermap_create (256,
                                                               GNUNET_YES);
-  all_desired_peers = GNUNET_CONTAINER_multipeermap_create (256,
-                                                            GNUNET_NO);
   return GNUNET_OK;
 }
 
@@ -2506,11 +2511,6 @@ GDS_NEIGHBOURS_done ()
                  GNUNET_CONTAINER_multipeermap_size (all_connected_peers));
   GNUNET_CONTAINER_multipeermap_destroy (all_connected_peers);
   all_connected_peers = NULL;
-  GNUNET_CONTAINER_multipeermap_iterate (all_desired_peers,
-                                         &free_connect_info,
-                                         NULL);
-  GNUNET_CONTAINER_multipeermap_destroy (all_desired_peers);
-  all_desired_peers = NULL;
   GNUNET_assert (NULL == find_peer_task);
 }
 
@@ -2518,7 +2518,7 @@ GDS_NEIGHBOURS_done ()
 struct GNUNET_PeerIdentity *
 GDS_NEIGHBOURS_get_id ()
 {
-  return &my_identity;
+  return &GDS_my_identity;
 }
 
 
diff --git a/src/dht/gnunet-service-dht_neighbours.h 
b/src/dht/gnunet-service-dht_neighbours.h
index e1a553f06..5a4c8c620 100644
--- a/src/dht/gnunet-service-dht_neighbours.h
+++ b/src/dht/gnunet-service-dht_neighbours.h
@@ -33,11 +33,6 @@
 #include "gnunet_dhtu_plugin.h"
 #include "gnunet-service-dht_datacache.h"
 
-/**
- * Hash of the identity of this peer.
- */
-extern struct GNUNET_HashCode my_identity_hash;
-
 
 struct PeerInfo;
 
@@ -141,7 +136,7 @@ GDS_am_closest_peer (const struct GNUNET_HashCode *key,
  * Function to call when we connect to a peer and can henceforth transmit to
  * that peer.
  *
- * @param cls the closure
+ * @param cls the closure, must be a `struct Underlay`
  * @param target handle to the target,
  *    pointer will remain valid until @e disconnect_cb is called
  * @para pid peer identity,
@@ -154,6 +149,7 @@ GDS_u_connect (void *cls,
                const struct GNUNET_PeerIdentity *pid,
                void **ctx);
 
+
 /**
  * Function to call when we disconnected from a peer and can henceforth
  * cannot transmit to that peer anymore.
@@ -182,6 +178,15 @@ GDS_u_receive (void *cls,
                size_t message_size);
 
 
+/**
+ * Send @a msg to all peers in our buckets.
+ *
+ * @param msg message to broadcast
+ */
+void
+GDS_NEIGHBOURS_broadcast (const struct GNUNET_MessageHeader *msg);
+
+
 /**
  * Initialize neighbours subsystem.
  *
diff --git a/src/dht/gnunet-service-dht_routing.c 
b/src/dht/gnunet-service-dht_routing.c
index e7b5c3571..ec3f5b46f 100644
--- a/src/dht/gnunet-service-dht_routing.c
+++ b/src/dht/gnunet-service-dht_routing.c
@@ -151,7 +151,7 @@ process (void *cls,
     bdx.put_path_length = 0;
     bdx.put_path = NULL;
   }
-  if ( (0 == (rr->options & GNUNET_DHT_RO_FIND_PEER)) &&
+  if ( (0 == (rr->options & GNUNET_DHT_RO_FIND_APPROXIMATE)) &&
        (0 != GNUNET_memcmp (query_hash,
                             &bdx.key)) )
   {
diff --git a/src/dhtu/plugin_dhtu_gnunet.c b/src/dhtu/plugin_dhtu_gnunet.c
index a75c47ce3..5cf47a850 100644
--- a/src/dhtu/plugin_dhtu_gnunet.c
+++ b/src/dhtu/plugin_dhtu_gnunet.c
@@ -235,7 +235,7 @@ hello_offered_cb (void *cls)
  */
 static void
 ip_try_connect (void *cls,
-                struct GNUNET_PeerIdentity *pid,
+                const struct GNUNET_PeerIdentity *pid,
                 const char *address)
 {
   struct Plugin *plugin = cls;
@@ -349,6 +349,17 @@ ip_send (void *cls,
   struct GNUNET_MQ_Envelope *env;
   struct GNUNET_MessageHeader *cmsg;
 
+  if (GNUNET_MQ_get_length (target->mq) >= MAXIMUM_PENDING_PER_PEER)
+  {
+    /* skip */
+#if FIXME_STATS
+    GNUNET_STATISTICS_update (GDS_stats,
+                              "# P2P messages dropped due to full queue",
+                              1,
+                              GNUNET_NO);
+#endif
+    return;
+  }
   env = GNUNET_MQ_msg_extra (cmsg,
                              msg_size,
                              GNUNET_MESSAGE_TYPE_DHT_CORE);
diff --git a/src/dhtu/plugin_dhtu_ip.c b/src/dhtu/plugin_dhtu_ip.c
index 7c01e5baf..998a7903b 100644
--- a/src/dhtu/plugin_dhtu_ip.c
+++ b/src/dhtu/plugin_dhtu_ip.c
@@ -354,7 +354,7 @@ find_target (struct Plugin *plugin,
  */
 static void
 ip_try_connect (void *cls,
-                struct GNUNET_PeerIdentity *pid,
+                const struct GNUNET_PeerIdentity *pid,
                 const char *address)
 {
   struct Plugin *plugin = cls;
@@ -365,7 +365,6 @@ ip_try_connect (void *cls,
     .ai_flags = AI_NUMERICHOST | AI_NUMERICSERV
   };
   struct addrinfo *result = NULL;
-  char *epid;
 
   if (0 !=
       strncmp (address,
@@ -507,7 +506,6 @@ create_source (struct Plugin *plugin,
                socklen_t addrlen)
 {
   struct GNUNET_DHTU_Source *src;
-  char *pid;
 
   src = GNUNET_new (struct GNUNET_DHTU_Source);
   src->addrlen = addrlen;
@@ -549,7 +547,6 @@ create_source (struct Plugin *plugin,
     break;
   default:
     GNUNET_break (0);
-    GNUNET_free (pid);
     GNUNET_free (src);
     return NULL;
   }
diff --git a/src/hello/hello-uri.c b/src/hello/hello-uri.c
index 49e4f6ed3..355443455 100644
--- a/src/hello/hello-uri.c
+++ b/src/hello/hello-uri.c
@@ -40,12 +40,6 @@
 #include "gnunet_protocols.h"
 #include "gnunet_util_lib.h"
 
-/**
- * For how long are HELLO signatures valid?
- */
-#define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply ( \
-    GNUNET_TIME_UNIT_DAYS, 2)
-
 
 GNUNET_NETWORK_STRUCT_BEGIN
 
@@ -72,7 +66,7 @@ struct HelloSignaturePurpose
 };
 
 /**
- * Binary block we sign when we sign an address.
+ * Message used when gossiping HELLOs between peers.
  */
 struct HelloUriMessage
 {
@@ -117,6 +111,42 @@ struct BlockHeader
 
 };
 
+
+/**
+ * Message used when a DHT provides its HELLO to direct
+ * neighbours.
+ */
+struct DhtHelloMessage
+{
+  /**
+   * Type must be #GNUNET_MESSAGE_TYPE_DHT_P2P_HELLO
+   */
+  struct GNUNET_MessageHeader header;
+
+  /**
+   * Reserved. 0.
+   */
+  uint16_t reserved GNUNET_PACKED;
+
+  /**
+   * Number of URLs encoded after the end of the struct, in NBO.
+   */
+  uint16_t url_counter GNUNET_PACKED;
+
+  /**
+   * Signature over the block, of purpose #GNUNET_SIGNATURE_PURPOSE_HELLO.
+   */
+  struct GNUNET_CRYPTO_EddsaSignature sig;
+
+  /**
+   * When does the HELLO expire?
+   */
+  struct GNUNET_TIME_AbsoluteNBO expiration_time;
+
+  /* followed by the serialized addresses of the 'block' */
+};
+
+
 GNUNET_NETWORK_STRUCT_END
 
 
@@ -521,6 +551,11 @@ GNUNET_HELLO_builder_to_env (const struct 
GNUNET_HELLO_Builder *builder,
   struct HelloUriMessage *msg;
   size_t blen;
 
+  if (builder->a_length > UINT16_MAX)
+  {
+    GNUNET_break (0);
+    return NULL;
+  }
   blen = 0;
   GNUNET_assert (GNUNET_NO ==
                  GNUNET_HELLO_builder_to_block (builder,
@@ -530,6 +565,7 @@ GNUNET_HELLO_builder_to_env (const struct 
GNUNET_HELLO_Builder *builder,
   env = GNUNET_MQ_msg_extra (msg,
                              blen,
                              GNUNET_MESSAGE_TYPE_HELLO_URI);
+  msg->url_counter = htonl ((uint16_t) builder->a_length);
   GNUNET_assert (GNUNET_OK ==
                  GNUNET_HELLO_builder_to_block (builder,
                                                 priv,
@@ -539,6 +575,50 @@ GNUNET_HELLO_builder_to_env (const struct 
GNUNET_HELLO_Builder *builder,
 }
 
 
+struct GNUNET_MessageHeader *
+GNUNET_HELLO_builder_to_dht_hello_msg (
+  const struct GNUNET_HELLO_Builder *builder,
+  const struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
+{
+  struct DhtHelloMessage *msg;
+  size_t blen;
+
+  if (builder->a_length > UINT16_MAX)
+  {
+    GNUNET_break (0);
+    return NULL;
+  }
+  blen = 0;
+  GNUNET_assert (GNUNET_NO ==
+                 GNUNET_HELLO_builder_to_block (builder,
+                                                priv,
+                                                NULL,
+                                                &blen));
+  GNUNET_assert (blen < UINT16_MAX);
+  GNUNET_assert (blen >= sizeof (struct BlockHeader));
+  {
+    char buf[blen] GNUNET_ALIGN;
+    const struct BlockHeader *block = (const struct BlockHeader *) buf;
+
+    GNUNET_assert (GNUNET_OK ==
+                   GNUNET_HELLO_builder_to_block (builder,
+                                                  priv,
+                                                  buf,
+                                                  &blen));
+    msg = GNUNET_malloc (sizeof (*msg) + blen);
+    msg->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_P2P_HELLO);
+    msg->header.size = htons (sizeof (*msg) + blen);
+    memcpy (&msg[1],
+            &block[1],
+            blen - sizeof (*block));
+    msg->sig = block->sig;
+    msg->expiration_time = block->expiration_time;
+  }
+  msg->url_counter = htonl ((uint16_t) builder->a_length);
+  return &msg->header;
+}
+
+
 char *
 GNUNET_HELLO_builder_to_url (const struct GNUNET_HELLO_Builder *builder,
                              const struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
@@ -550,7 +630,7 @@ GNUNET_HELLO_builder_to_url (const struct 
GNUNET_HELLO_Builder *builder,
   char *sigs;
   const char *sep = "?";
 
-  et = GNUNET_TIME_relative_to_timestamp (HELLO_ADDRESS_EXPIRATION);
+  et = GNUNET_TIME_relative_to_timestamp (GNUNET_HELLO_ADDRESS_EXPIRATION);
   sign_hello (builder,
               et,
               priv,
@@ -629,7 +709,7 @@ GNUNET_HELLO_builder_to_block (const struct 
GNUNET_HELLO_Builder *builder,
     return GNUNET_NO;
   }
   bh.pid = builder->pid;
-  et = GNUNET_TIME_relative_to_timestamp (HELLO_ADDRESS_EXPIRATION);
+  et = GNUNET_TIME_relative_to_timestamp (GNUNET_HELLO_ADDRESS_EXPIRATION);
   bh.expiration_time = GNUNET_TIME_absolute_hton (et.abs_time);
   sign_hello (builder,
               et,
@@ -742,3 +822,54 @@ GNUNET_HELLO_builder_iterate (const struct 
GNUNET_HELLO_Builder *builder,
         a->uri);
   }
 }
+
+
+enum GNUNET_GenericReturnValue
+GNUNET_HELLO_dht_msg_to_block (const struct GNUNET_MessageHeader *hello,
+                               const struct GNUNET_PeerIdentity *pid,
+                               void **block,
+                               size_t *block_size,
+                               struct GNUNET_TIME_Absolute *block_expiration)
+{
+  const struct DhtHelloMessage *msg
+    = (const struct DhtHelloMessage *) hello;
+  uint16_t len = ntohs (hello->size);
+  struct BlockHeader *bh;
+  struct GNUNET_HELLO_Builder *b;
+  enum GNUNET_GenericReturnValue ret;
+
+  if (GNUNET_MESSAGE_TYPE_DHT_P2P_HELLO != ntohs (hello->type))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  if (len < sizeof (*msg))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  len -= sizeof (*msg);
+  *block_size = len + sizeof (*bh);
+  *block = GNUNET_malloc (*block_size);
+  bh = *block;
+  bh->pid = *pid;
+  bh->sig = msg->sig;
+  bh->expiration_time = msg->expiration_time;
+  *block_expiration = GNUNET_TIME_absolute_ntoh (msg->expiration_time);
+  memcpy (&bh[1],
+          &msg[1],
+          len);
+  b = GNUNET_HELLO_builder_from_block (*block,
+                                       *block_size);
+  ret = verify_hello (b,
+                      *block_expiration,
+                      &msg->sig);
+  GNUNET_HELLO_builder_free (b);
+  if (GNUNET_SYSERR == ret)
+  {
+    GNUNET_free (*block);
+    *block_size = 0;
+    return GNUNET_SYSERR;
+  }
+  return ret;
+}
diff --git a/src/include/gnunet_datacache_lib.h 
b/src/include/gnunet_datacache_lib.h
index 11076e3e7..737a5c845 100644
--- a/src/include/gnunet_datacache_lib.h
+++ b/src/include/gnunet_datacache_lib.h
@@ -154,6 +154,7 @@ GNUNET_DATACACHE_get (struct GNUNET_DATACACHE_Handle *h,
  *
  * @param h handle to the datacache
  * @param key area of the keyspace to look into
+ * @param type entries of which type are relevant?
  * @param num_results number of results that should be returned to @a iter
  * @param iter maybe NULL (to just count)
  * @param iter_cls closure for @a iter
@@ -162,6 +163,7 @@ GNUNET_DATACACHE_get (struct GNUNET_DATACACHE_Handle *h,
 unsigned int
 GNUNET_DATACACHE_get_closest (struct GNUNET_DATACACHE_Handle *h,
                               const struct GNUNET_HashCode *key,
+                              enum GNUNET_BLOCK_Type type,
                               unsigned int num_results,
                               GNUNET_DATACACHE_Iterator iter,
                               void *iter_cls);
diff --git a/src/include/gnunet_datacache_plugin.h 
b/src/include/gnunet_datacache_plugin.h
index 24570be72..914aaf15c 100644
--- a/src/include/gnunet_datacache_plugin.h
+++ b/src/include/gnunet_datacache_plugin.h
@@ -165,6 +165,7 @@ struct GNUNET_DATACACHE_PluginFunctions
    *
    * @param cls closure (internal context for the plugin)
    * @param key area of the keyspace to look into
+   * @param type desired block type for the replies
    * @param num_results number of results that should be returned to @a iter
    * @param iter maybe NULL (to just count)
    * @param iter_cls closure for @a iter
@@ -173,6 +174,7 @@ struct GNUNET_DATACACHE_PluginFunctions
   unsigned int
   (*get_closest) (void *cls,
                   const struct GNUNET_HashCode *key,
+                  enum GNUNET_BLOCK_Type type,
                   unsigned int num_results,
                   GNUNET_DATACACHE_Iterator iter,
                   void *iter_cls);
diff --git a/src/include/gnunet_dht_service.h b/src/include/gnunet_dht_service.h
index 768b19fb1..abe5a03e4 100644
--- a/src/include/gnunet_dht_service.h
+++ b/src/include/gnunet_dht_service.h
@@ -101,14 +101,14 @@ enum GNUNET_DHT_RouteOption
   GNUNET_DHT_RO_RECORD_ROUTE = 2,
 
   /**
-   * This is a 'FIND-PEER' request, so approximate results are fine.
+   * Approximate results are fine.
    */
-  GNUNET_DHT_RO_FIND_PEER = 4,
+  GNUNET_DHT_RO_FIND_APPROXIMATE = 4,
 
   /**
-    * Flag given to monitors if this was the last hop for a GET/PUT.
-    * This is only used for internal processing.
-    */
+   * Flag given to monitors if this was the last hop for a GET/PUT.
+   * This is only used for internal processing.
+   */
   GNUNET_DHT_RO_LAST_HOP = 65535
 };
 
diff --git a/src/include/gnunet_dhtu_plugin.h b/src/include/gnunet_dhtu_plugin.h
index b709ce9ae..fa0b5f667 100644
--- a/src/include/gnunet_dhtu_plugin.h
+++ b/src/include/gnunet_dhtu_plugin.h
@@ -129,6 +129,7 @@ struct GNUNET_DHTU_PluginEnvironment
                 const struct GNUNET_PeerIdentity *pid,
                 void **ctx);
 
+
   /**
    * Function to call when we disconnected from a peer and can henceforth
    * cannot transmit to that peer anymore.
@@ -177,7 +178,7 @@ struct GNUNET_DHTU_PluginFunctions
    */
   void
   (*try_connect) (void *cls,
-                  struct GNUNET_PeerIdentity *pid,
+                  const struct GNUNET_PeerIdentity *pid,
                   const char *address);
 
 
@@ -194,7 +195,7 @@ struct GNUNET_DHTU_PluginFunctions
           struct GNUNET_DHTU_Target *target);
 
   /**
-   * Do no long request underlay to keep the connection alive.
+   * Do no longer request underlay to keep the connection alive.
    *
    * @param cls closure
    * @param target connection to keep alive
diff --git a/src/include/gnunet_hello_uri_lib.h 
b/src/include/gnunet_hello_uri_lib.h
index ec9cdfa5e..c109a151a 100644
--- a/src/include/gnunet_hello_uri_lib.h
+++ b/src/include/gnunet_hello_uri_lib.h
@@ -48,6 +48,13 @@ extern "C" {
 struct GNUNET_HELLO_Builder;
 
 
+/**
+ * For how long are HELLO signatures valid?
+ */
+#define GNUNET_HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply ( \
+    GNUNET_TIME_UNIT_DAYS, 2)
+
+
 /**
  * Allocate builder.
  *
@@ -100,7 +107,8 @@ GNUNET_HELLO_builder_from_url (const char *url);
 
 
 /**
- * Generate HELLO message from a @a builder
+ * Generate envelope with GNUnet HELLO message (including
+ * peer ID) from a @a builder
  *
  * @param builder builder to serialize
  * @param priv private key to use to sign the result
@@ -111,6 +119,19 @@ GNUNET_HELLO_builder_to_env (const struct 
GNUNET_HELLO_Builder *builder,
                              const struct GNUNET_CRYPTO_EddsaPrivateKey *priv);
 
 
+/**
+ * Generate DHT HELLO message (without peer ID) from a @a builder
+ *
+ * @param builder builder to serialize
+ * @param priv private key to use to sign the result
+ * @return HELLO message matching @a builder
+ */
+struct GNUNET_MessageHeader *
+GNUNET_HELLO_builder_to_dht_hello_msg (
+  const struct GNUNET_HELLO_Builder *builder,
+  const struct GNUNET_CRYPTO_EddsaPrivateKey *priv);
+
+
 /**
  * Generate GNUnet HELLO URI from a @a builder
  *
@@ -191,6 +212,27 @@ GNUNET_HELLO_builder_iterate (const struct 
GNUNET_HELLO_Builder *builder,
                               GNUNET_HELLO_UriCallback uc,
                               void *uc_cls);
 
+
+/**
+ * Convert a DHT @a hello message to a HELLO @a block.
+ *
+ * @param hello the HELLO message
+ * @param pid peer that created the @a hello
+ * @param[out] block set to the HELLO block
+ * @param[out] block_size set to number of bytes in @a block
+ * @param[out] block_expiration set to expiration time of @a block
+ * @return #GNUNET_OK on success,
+ *         #GNUNET_NO if the @a hello is expired (@a block is set!)
+ *         #GNUNET_SYSERR if @a hello is invalid (@a block will be set to NULL)
+ */
+enum GNUNET_GenericReturnValue
+GNUNET_HELLO_dht_msg_to_block (const struct GNUNET_MessageHeader *hello,
+                               const struct GNUNET_PeerIdentity *pid,
+                               void **block,
+                               size_t *block_size,
+                               struct GNUNET_TIME_Absolute *block_expiration);
+
+
 #if 0 /* keep Emacsens' auto-indent happy */
 {
 #endif
diff --git a/src/include/gnunet_protocols.h b/src/include/gnunet_protocols.h
index f5ccd2971..cddacc8a6 100644
--- a/src/include/gnunet_protocols.h
+++ b/src/include/gnunet_protocols.h
@@ -660,13 +660,15 @@ extern "C" {
 #define GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET_RESULTS_KNOWN 156
 
 /**
- * DHT wants to use CORE to transmit data.
+ * HELLO advertising a neighbours addresses.
  */
-#define GNUNET_MESSAGE_TYPE_DHT_CORE 143
+#define GNUNET_MESSAGE_TYPE_DHT_P2P_HELLO 157
 
 /**
- * Further X-VINE DHT messages continued from 880
+ * DHT wants to use CORE to transmit data.
  */
+#define GNUNET_MESSAGE_TYPE_DHT_CORE 143
+
 
 
/*******************************************************************************
  * HOSTLIST message types

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

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