gnunet

Main GNUnet Logic
Log | Files | Refs | Submodules | README | LICENSE

commit b0abdf7127f2403ff583d224e0d9d4e68c1c5bfc
parent 3a71153405e8fc26712807b4bdb5987fb3bf2b9e
Author: Christian Grothoff <christian@grothoff.org>
Date:   Sat, 15 Jan 2022 19:24:33 +0100

-more work on DHTU integration

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

diff --git 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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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. @@ -133,11 +159,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 @@ -27,6 +27,7 @@ #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" @@ -34,6 +35,11 @@ #define DEBUG_DHT GNUNET_EXTRA_LOGGING /** + * Information we keep per underlay. + */ +struct Underlay; + +/** * Configuration we use. */ extern const struct GNUNET_CONFIGURATION_Handle *GDS_cfg; @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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; }; @@ -371,12 +414,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. */ static unsigned int bucket_size = DEFAULT_BUCKET_SIZE; @@ -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) @@ -470,175 +570,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! */ @@ -2260,6 +2191,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. * * @param cls closure @@ -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 @@ -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. @@ -183,6 +179,15 @@ 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); + + +/** * Initialize neighbours subsystem. * * @return #GNUNET_OK on success, #GNUNET_SYSERR on error diff --git 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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -49,6 +49,13 @@ 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. * * @param pid peer the builder is for @@ -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 @@ -112,6 +120,19 @@ GNUNET_HELLO_builder_to_env (const struct GNUNET_HELLO_Builder *builder, /** + * 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 * * @param builder builder to serialize @@ -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 @@ -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