From 0f8b71280614e9a69d7703d88cc35108e6cec052 Mon Sep 17 00:00:00 2001 From: t3sserakt Date: Thu, 3 Aug 2023 10:48:39 +0200 Subject: NEWS: Added api to store hellos with peerstore service. --- src/hello/hello-uri.c | 121 +++++++++++++++++ src/include/gnunet_hello_uri_lib.h | 17 +++ src/include/gnunet_peerstore_service.h | 31 +++++ src/peerstore/peerstore_api.c | 238 +++++++++++++++++++++++++++++++++ 4 files changed, 407 insertions(+) diff --git a/src/hello/hello-uri.c b/src/hello/hello-uri.c index 8f8f699e9..9e8d6909d 100644 --- a/src/hello/hello-uri.c +++ b/src/hello/hello-uri.c @@ -204,6 +204,32 @@ struct GNUNET_HELLO_Builder }; +/** + * Struct to wrap data to do the merge of to hello uris. + */ +struct AddressUriMergeResult +{ + /** + * The builder of the hello uri we merge with. + */ + struct GNUNET_HELLO_Builder *builder; + + /** + * The actual address to check, if it is allready in the hello uri we merge with. + */ + const char *address_uri; + + /** + * Did we found the actual address to check. + */ + unsigned int found; + + /** + * Did we found at least one address to merge. + */ + unsigned int merged; +}; + /** * Compute @a hash over addresses in @a builder. @@ -315,6 +341,13 @@ GNUNET_HELLO_builder_new (const struct GNUNET_PeerIdentity *pid) } +struct GNUNET_PeerIdentity * +GNUNET_HELLO_builder_get_id (struct GNUNET_HELLO_Builder *builder) +{ + return &builder->pid; +} + + void GNUNET_HELLO_builder_free (struct GNUNET_HELLO_Builder *builder) { @@ -412,6 +445,94 @@ GNUNET_HELLO_builder_from_block (const void *block, } +static void +merge_hellos2 (void *cls, const char *address_uri2) +{ + struct AddressUriMergeResult *aumr = cls; + const char *address_uri1 = aumr->address_uri; + + if (GNUNET_NO == aumr->found && 0 != GNUNET_memcmp (address_uri1, + address_uri2)) + { + aumr->found = GNUNET_YES; + } +} + + +static void +merge_hellos1 (void *cls, const char *address_uri1) +{ + struct AddressUriMergeResult *aumr = cls; + struct GNUNET_HELLO_Builder *builder2 = aumr->builder; + struct GNUNET_PeerIdentity *peer2 = GNUNET_HELLO_builder_get_id (builder2); + + aumr->address_uri = address_uri1; + GNUNET_HELLO_builder_iterate (builder2, peer2, &merge_hellos2, aumr); + if (GNUNET_YES == aumr->found) + { + GNUNET_HELLO_builder_add_address (builder2, address_uri1); + aumr->merged = GNUNET_YES; + } + aumr->found = GNUNET_NO; +} + + +struct GNUNET_MQ_Envelope * +GNUNET_HELLO_builder_merge_hellos (const struct GNUNET_MessageHeader *msg1, + const struct GNUNET_MessageHeader *msg2, + const struct + GNUNET_CRYPTO_EddsaPrivateKey *priv) +{ + struct HelloUriMessage *hum1 = (struct HelloUriMessage *) msg1; + struct BlockHeader *bh1 = (struct BlockHeader *) &msg1[1]; + struct GNUNET_TIME_Absolute expiration_time1 = GNUNET_TIME_absolute_ntoh ( + bh1->expiration_time); + struct HelloUriMessage *hum2 = (struct HelloUriMessage *) msg2; + struct BlockHeader *bh2 = (struct BlockHeader *) &msg2[1]; + struct GNUNET_TIME_Absolute expiration_time2 = GNUNET_TIME_absolute_ntoh ( + bh1->expiration_time); + struct GNUNET_HELLO_Builder *builder1 = GNUNET_HELLO_builder_from_msg (msg1); + struct GNUNET_HELLO_Builder *builder2 = GNUNET_HELLO_builder_from_msg (msg2); + struct AddressUriMergeResult *aumr = GNUNET_new (struct + AddressUriMergeResult); + struct GNUNET_PeerIdentity *peer1 = GNUNET_HELLO_builder_get_id (builder1); + struct GNUNET_MQ_Envelope *env; + struct GNUNET_TIME_Absolute expiration_time; + + aumr->builder = builder2; + GNUNET_HELLO_builder_iterate (builder1, peer1, &merge_hellos1, aumr); + + if (GNUNET_YES == aumr->merged) + { + if (expiration_time1.abs_value_us < expiration_time2.abs_value_us) + expiration_time = expiration_time1; + else + expiration_time = expiration_time2; + env = GNUNET_HELLO_builder_to_env (builder2, + priv, + GNUNET_TIME_absolute_get_remaining ( + expiration_time)); + } + else if (expiration_time1.abs_value_us != expiration_time2.abs_value_us) + { + if (expiration_time1.abs_value_us < expiration_time2.abs_value_us) + expiration_time = expiration_time2; + else + expiration_time = expiration_time1; + env = GNUNET_HELLO_builder_to_env (builder2, + priv, + GNUNET_TIME_absolute_get_remaining ( + expiration_time)); + } + + GNUNET_HELLO_builder_free (builder1); + GNUNET_HELLO_builder_free (builder2); + GNUNET_free (aumr); + + return env; +} + + struct GNUNET_HELLO_Builder * GNUNET_HELLO_builder_from_url (const char *url) { diff --git a/src/include/gnunet_hello_uri_lib.h b/src/include/gnunet_hello_uri_lib.h index 4e48bc1a0..3aa07d760 100644 --- a/src/include/gnunet_hello_uri_lib.h +++ b/src/include/gnunet_hello_uri_lib.h @@ -69,6 +69,13 @@ struct GNUNET_HELLO_Builder * GNUNET_HELLO_builder_new (const struct GNUNET_PeerIdentity *pid); +/** + * Get the PeerIdentity for this builder. + */ +struct GNUNET_PeerIdentity * +GNUNET_HELLO_builder_get_id (struct GNUNET_HELLO_Builder *builder); + + /** * Release resources of a @a builder. * @@ -110,6 +117,16 @@ struct GNUNET_HELLO_Builder * GNUNET_HELLO_builder_from_url (const char *url); +/** + * Merge to hello uris. + */ +struct GNUNET_MQ_Envelope * +GNUNET_HELLO_builder_merge_hellos (const struct GNUNET_MessageHeader *msg1, + const struct GNUNET_MessageHeader *msg2, + const struct + GNUNET_CRYPTO_EddsaPrivateKey *priv); + + /** * Generate envelope with GNUnet HELLO message (including * peer ID) from a @a builder diff --git a/src/include/gnunet_peerstore_service.h b/src/include/gnunet_peerstore_service.h index c4000c680..37d3ca7fe 100644 --- a/src/include/gnunet_peerstore_service.h +++ b/src/include/gnunet_peerstore_service.h @@ -46,6 +46,10 @@ extern "C" { #endif #endif +/** + * Key used for storing HELLO in the peerstore + */ +#define GNUNET_PEERSTORE_HELLO_KEY "peerstore-peer-hello-uri" /** * Key used for storing addresses in URL format in the peerstore @@ -182,6 +186,33 @@ typedef void (*GNUNET_PEERSTORE_Processor) ( const char *emsg); + +/** + * Add hello to peerstore. + * + * @param h handle for peerstore. + * @param msg The hello to add. + * @param cont The continuation function to execute after storing. + * @param cont_cls The continuation function closure. + * @return The context for storing. + */ +struct GNUNET_PEERSTORE_StoreHelloContext * +GNUNET_PEERSTORE_hello_add (struct GNUNET_PEERSTORE_Handle *h, + const struct GNUNET_MessageHeader *msg, + const struct GNUNET_CRYPTO_EddsaPrivateKey *priv, + GNUNET_PEERSTORE_Continuation cont, + void *cont_cls); + + +/** + * Cancel the request to add a hello. + * + * @param huc The context for storing a hello. + */ +void +GNUNET_PEERSTORE_hello_add_cancel (struct GNUNET_PEERSTORE_StoreHelloContext *huc); + + /** * Connect to the PEERSTORE service. * diff --git a/src/peerstore/peerstore_api.c b/src/peerstore/peerstore_api.c index 1c13369cf..3905b14e4 100644 --- a/src/peerstore/peerstore_api.c +++ b/src/peerstore/peerstore_api.c @@ -25,8 +25,10 @@ */ #include "platform.h" #include "gnunet_util_lib.h" +#include "gnunet_hello_uri_lib.h" #include "peerstore.h" #include "peerstore_common.h" +#include "gnunet_peerstore_service.h" #define LOG(kind, ...) GNUNET_log_from (kind, "peerstore-api", __VA_ARGS__) @@ -156,6 +158,22 @@ struct GNUNET_PEERSTORE_StoreContext enum GNUNET_PEERSTORE_StoreOption options; }; +/** + * Closure for store callback when storing hello uris. + */ +struct StoreHelloCls +{ + /** + * The corresponding store context. + */ + struct GNUNET_PEERSTORE_StoreContext *sc; + + /** + * The corresponding hello uri add request. + */ + struct GNUNET_PEERSTORE_StoreHelloContext *huc; +}; + /** * Context for a iterate request */ @@ -243,6 +261,62 @@ struct GNUNET_PEERSTORE_WatchContext struct GNUNET_HashCode keyhash; }; +/** + * Context for a add hello uri request. + */ +struct GNUNET_PEERSTORE_StoreHelloContext +{ + /** + * Peerstore handle. + */ + struct GNUNET_PEERSTORE_Handle *h; + + /** + * Function to call with information. + */ + GNUNET_PEERSTORE_Continuation cont; + + /** + * Closure for @e callback. + */ + void *cont_cls; + + /** + * Head of active STORE requests. + */ + struct GNUNET_PEERSTORE_StoreContext *sc_head; + + /** + * Tail of active STORE requests. + */ + struct GNUNET_PEERSTORE_StoreContext *sc_tail; + + /** + * Iteration context to iterate through all the stored hellos. + */ + struct GNUNET_PEERSTORE_IterateContext *ic; + + /** + * Active watch to be notified about conflicting hello uri add requests. + */ + struct GNUNET_PEERSTORE_WatchContext *wc; + + /** + * Hello uri which was request for storing. + */ + const struct GNUNET_MessageHeader *hello; + + /** + * Key to sign merged hello. + */ + const struct GNUNET_CRYPTO_EddsaPrivateKey *priv; + + /** + * Was this request successful. + */ + int success; +}; + /******************************************************************************/ /******************* DECLARATIONS *********************/ /******************************************************************************/ @@ -935,4 +1009,168 @@ GNUNET_PEERSTORE_watch (struct GNUNET_PEERSTORE_Handle *h, } + + +static void +merge_success (void *cls, int success) +{ + struct StoreHelloCls *shu_cls = cls; + struct GNUNET_PEERSTORE_StoreHelloContext *huc = shu_cls->huc; + struct GNUNET_PEERSTORE_Handle *h = huc->h; + + if (GNUNET_OK != success) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Storing hello uri failed\n"); + huc->cont (huc->cont_cls, success); + return; + } + GNUNET_CONTAINER_DLL_remove (huc->sc_head, huc->sc_tail, shu_cls->sc); + if (NULL == huc->sc_head) + { + GNUNET_PEERSTORE_watch_cancel (huc->wc); + huc->wc = NULL; + huc->cont (huc->cont_cls, GNUNET_OK); + huc->success = GNUNET_OK; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Storing hello uri succeeded!\n"); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Got notified during storing hello uri!\n"); +} + + +static void +store_hello (struct GNUNET_PEERSTORE_StoreHelloContext *huc, + const struct GNUNET_MessageHeader *hello) +{ + struct GNUNET_PEERSTORE_Handle *h = huc->h; + struct GNUNET_HELLO_Builder *builder; + struct GNUNET_PeerIdentity *pid; + struct GNUNET_PEERSTORE_StoreContext *sc; + struct StoreHelloCls *shu_cls = GNUNET_new (struct StoreHelloCls); + + shu_cls->huc = huc; + builder = GNUNET_HELLO_builder_from_msg (hello); + pid = GNUNET_HELLO_builder_get_id (builder); + sc = GNUNET_PEERSTORE_store (h, + "peerstore", + pid, + GNUNET_PEERSTORE_HELLO_KEY, + hello, + sizeof(hello), + GNUNET_TIME_UNIT_FOREVER_ABS, + GNUNET_PEERSTORE_STOREOPTION_REPLACE, + merge_success, + shu_cls); + shu_cls->sc = sc; + GNUNET_CONTAINER_DLL_insert (huc->sc_head, huc->sc_tail, sc); + GNUNET_HELLO_builder_free (builder); +} + + +static void +merge_uri (void *cls, + const struct GNUNET_PEERSTORE_Record *record, + const char *emsg) +{ + struct GNUNET_PEERSTORE_StoreHelloContext *huc = cls; + struct GNUNET_PEERSTORE_Handle *h = huc->h; + struct GNUNET_PEERSTORE_WatchContext *wc; + struct GNUNET_MessageHeader *hello; + const struct GNUNET_MessageHeader *merged_hello; + struct GNUNET_MQ_Envelope *env; + const char *val; + + if (NULL != emsg) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Got failure from PEERSTORE: %s\n", + emsg); + return; + } + if (NULL == record) + return; + + if (NULL == huc->wc && GNUNET_NO == huc->success) + { + wc = GNUNET_PEERSTORE_watch (h, + "peerstore", + &record->peer, + GNUNET_PEERSTORE_HELLO_KEY, + &merge_uri, + huc); + huc->wc = wc; + } + + if (NULL != record) + { + hello = record->value; + if ((0 == record->value_size) || ('\0' != val[record->value_size - 1])) + { + GNUNET_break (0); + return; + } + + env = GNUNET_HELLO_builder_merge_hellos (huc->hello, hello, huc->priv); + merged_hello = GNUNET_MQ_env_get_msg (env); + if (NULL != merged_hello) + store_hello (huc, merged_hello); + + GNUNET_free (env); + + } + else + { + store_hello (huc, huc->hello); + } +} + + +struct GNUNET_PEERSTORE_StoreHelloContext * +GNUNET_PEERSTORE_hello_add (struct GNUNET_PEERSTORE_Handle *h, + const struct GNUNET_MessageHeader *msg, + const struct GNUNET_CRYPTO_EddsaPrivateKey *priv, + GNUNET_PEERSTORE_Continuation cont, + void *cont_cls) +{ + struct GNUNET_HELLO_Builder *builder; + struct GNUNET_PEERSTORE_StoreHelloContext *huc; + struct GNUNET_PEERSTORE_IterateContext *ic; + struct GNUNET_PeerIdentity *pid; + + huc = GNUNET_new (struct GNUNET_PEERSTORE_StoreHelloContext); + huc->h = h; + huc->cont = cont; + huc->cont_cls = cont_cls; + huc->hello = msg; + huc->priv = priv; + + builder = GNUNET_HELLO_builder_from_msg (msg); + pid = GNUNET_HELLO_builder_get_id (builder); + ic = GNUNET_PEERSTORE_iterate (h, + "peerstore", + pid, + GNUNET_PEERSTORE_HELLO_KEY, + &merge_uri, + huc); + GNUNET_HELLO_builder_free (builder); + huc->ic = ic; + + return huc; +} + +void +GNUNET_PEERSTORE_hello_add_cancel (struct GNUNET_PEERSTORE_StoreHelloContext *huc) +{ + struct GNUNET_PEERSTORE_StoreContext *sc; + + GNUNET_PEERSTORE_iterate_cancel (huc->ic); + GNUNET_PEERSTORE_watch_cancel (huc->wc); + while (NULL != (sc = huc->sc_head)) + GNUNET_PEERSTORE_store_cancel (sc); + GNUNET_free (huc); +} + /* end of peerstore_api.c */ -- cgit v1.2.3