libgnunetchat

library for GNUnet Messenger
Log | Files | Refs | README | LICENSE

commit 4bf5c1d2b40272db5c232bd499af4bb26ddab88e
parent 864110d3d23724a50ddc974ffb4b5de4addea958
Author: Jacki <jacki@thejackimonster.de>
Date:   Tue, 20 Feb 2024 00:41:38 +0100

Adjust blocking implementation to handle custom tag values too

Signed-off-by: Jacki <jacki@thejackimonster.de>

Diffstat:
Msrc/gnunet_chat_contact.c | 102++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
Msrc/gnunet_chat_contact_intern.c | 13+++++--------
Msrc/gnunet_chat_context.c | 24++++++++++++++----------
Msrc/gnunet_chat_context.h | 2+-
Msrc/gnunet_chat_context_intern.c | 19++++++++++++++++---
Msrc/gnunet_chat_handle_intern.c | 26++++++++++++++++++++------
Msrc/gnunet_chat_lib.c | 9+++++----
Asrc/gnunet_chat_tagging.c | 162+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/gnunet_chat_tagging.h | 107+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/meson.build | 1+
10 files changed, 398 insertions(+), 67 deletions(-)

diff --git a/src/gnunet_chat_contact.c b/src/gnunet_chat_contact.c @@ -25,6 +25,7 @@ #include "gnunet_chat_contact.h" #include "gnunet_chat_context.h" #include "gnunet_chat_handle.h" +#include "gnunet_chat_tagging.h" #include "gnunet_chat_ticket.h" #include "gnunet_chat_contact_intern.c" @@ -166,6 +167,21 @@ contact_find_context (const struct GNUNET_CHAT_Contact *contact) ); } +const struct GNUNET_HashCode* +get_contact_join_hash (const struct GNUNET_CHAT_Contact *contact, + const struct GNUNET_CHAT_Context *context) +{ + GNUNET_assert((contact) && (context)); + + if (!(context->room)) + return NULL; + + return GNUNET_CONTAINER_multihashmap_get( + contact->joined, + GNUNET_MESSENGER_room_get_key(context->room) + ); +} + enum GNUNET_GenericReturnValue contact_is_tagged (const struct GNUNET_CHAT_Contact *contact, const struct GNUNET_CHAT_Context *context, @@ -207,28 +223,34 @@ contact_is_tagged (const struct GNUNET_CHAT_Contact *contact, } skip_context_search: - if ((! context) || (!(context->room))) + if (! context) return GNUNET_NO; - const struct GNUNET_HashCode *hash; - hash = GNUNET_CONTAINER_multihashmap_get( - contact->joined, - GNUNET_MESSENGER_room_get_key(context->room) - ); + const struct GNUNET_HashCode *hash = get_contact_join_hash( + contact, context); if (! hash) return (general == GNUNET_YES? GNUNET_NO : contact_is_tagged(contact, NULL, tag) ); + + const struct GNUNET_CHAT_Tagging *tagging = GNUNET_CONTAINER_multihashmap_get( + context->taggings, + hash + ); + + if (! tagging) + return GNUNET_NO; - struct GNUNET_CHAT_ContactFindJoin find; + struct GNUNET_CHAT_ContactFindTag find; find.hash = NULL; - GNUNET_CONTAINER_multihashmap_get_multiple( - context->rejections, - hash, - it_contact_find_rejection, + tagging_iterate( + tagging, + GNUNET_NO, + tag, + it_contact_find_tag, &find ); @@ -249,25 +271,28 @@ contact_untag (struct GNUNET_CHAT_Contact *contact, (context) ); - if (!(context->room)) + const struct GNUNET_HashCode *hash = get_contact_join_hash( + contact, context); + + if (! hash) return; - const struct GNUNET_HashCode *hash; - hash = GNUNET_CONTAINER_multihashmap_get( - contact->joined, - GNUNET_MESSENGER_room_get_key(context->room) + const struct GNUNET_CHAT_Tagging *tagging = GNUNET_CONTAINER_multihashmap_get( + context->taggings, + hash ); - if (! hash) + if (! tagging) return; - struct GNUNET_CHAT_ContactFindJoin find; + struct GNUNET_CHAT_ContactFindTag find; find.hash = NULL; - GNUNET_CONTAINER_multihashmap_get_multiple( - context->rejections, - hash, - it_contact_find_rejection, + tagging_iterate( + tagging, + GNUNET_NO, + tag, + it_contact_find_tag, &find ); @@ -292,29 +317,36 @@ contact_tag (struct GNUNET_CHAT_Contact *contact, (context) ); - if (!(context->room)) + const struct GNUNET_HashCode *hash = get_contact_join_hash( + contact, context); + + if (! hash) return; - const struct GNUNET_HashCode *hash; - hash = GNUNET_CONTAINER_multihashmap_get( - contact->joined, - GNUNET_MESSENGER_room_get_key(context->room) + const struct GNUNET_CHAT_Tagging *tagging = GNUNET_CONTAINER_multihashmap_get( + context->taggings, + hash ); - if (! hash) - return; + if (! tagging) + goto skip_tag_search; - struct GNUNET_CHAT_ContactFindJoin find; + struct GNUNET_CHAT_ContactFindTag find; find.hash = NULL; - GNUNET_CONTAINER_multihashmap_get_multiple( - context->rejections, - hash, - it_contact_find_rejection, + tagging_iterate( + tagging, + GNUNET_NO, + tag, + it_contact_find_tag, &find ); - if ((find.hash) || (! context->room)) + if (find.hash) + return; + +skip_tag_search: + if (! context->room) return; char *tag_value = tag? GNUNET_strdup(tag) : NULL; diff --git a/src/gnunet_chat_contact_intern.c b/src/gnunet_chat_contact_intern.c @@ -58,21 +58,18 @@ it_contact_find_room (void *cls, return GNUNET_YES; } -struct GNUNET_CHAT_ContactFindJoin +struct GNUNET_CHAT_ContactFindTag { const struct GNUNET_HashCode *hash; }; enum GNUNET_GenericReturnValue -it_contact_find_rejection (void *cls, - const struct GNUNET_HashCode *key, - void *value) +it_contact_find_tag (void *cls, + const struct GNUNET_CHAT_Message *message) { - GNUNET_assert((cls) && (key) && (value)); + GNUNET_assert((cls) && (message)); - struct GNUNET_CHAT_ContactFindJoin *find = cls; - - const struct GNUNET_CHAT_Message *message = value; + struct GNUNET_CHAT_ContactFindTag *find = cls; if ((GNUNET_YES != message_has_msg(message)) || (message->flags & GNUNET_MESSENGER_FLAG_DELETE)) diff --git a/src/gnunet_chat_context.c b/src/gnunet_chat_context.c @@ -51,7 +51,7 @@ init_new_context (struct GNUNET_CHAT_Context *context, initial_map_size, GNUNET_NO); context->messages = GNUNET_CONTAINER_multihashmap_create( initial_map_size, GNUNET_NO); - context->rejections = GNUNET_CONTAINER_multihashmap_create( + context->taggings = GNUNET_CONTAINER_multihashmap_create( initial_map_size, GNUNET_NO); context->invites = GNUNET_CONTAINER_multihashmap_create( initial_map_size, GNUNET_NO); @@ -112,7 +112,7 @@ context_destroy (struct GNUNET_CHAT_Context *context) (context->timestamps) && (context->dependencies) && (context->messages) && - (context->rejections) && + (context->taggings) && (context->invites) && (context->files) ); @@ -129,7 +129,10 @@ context_destroy (struct GNUNET_CHAT_Context *context) context->messages, it_destroy_context_messages, NULL ); - GNUNET_CONTAINER_multihashmap_clear(context->rejections); + GNUNET_CONTAINER_multihashmap_iterate( + context->taggings, it_destroy_context_taggings, NULL + ); + GNUNET_CONTAINER_multihashmap_iterate( context->invites, it_destroy_context_invites, NULL ); @@ -139,7 +142,7 @@ context_destroy (struct GNUNET_CHAT_Context *context) GNUNET_CONTAINER_multishortmap_destroy(context->timestamps); GNUNET_CONTAINER_multihashmap_destroy(context->dependencies); GNUNET_CONTAINER_multihashmap_destroy(context->messages); - GNUNET_CONTAINER_multihashmap_destroy(context->rejections); + GNUNET_CONTAINER_multihashmap_destroy(context->taggings); GNUNET_CONTAINER_multihashmap_destroy(context->invites); GNUNET_CONTAINER_multihashmap_destroy(context->files); @@ -319,14 +322,15 @@ context_delete_message (struct GNUNET_CHAT_Context *context, } case GNUNET_MESSENGER_KIND_TAG: { - if (message->msg->body.tag.tag) - break; + struct GNUNET_CHAT_Tagging *tagging = GNUNET_CONTAINER_multihashmap_get( + context->taggings, + &(message->msg->body.tag.hash) + ); - GNUNET_CONTAINER_multihashmap_remove( - context->rejections, - &(message->msg->body.tag.hash), - message); + if (!tagging) + break; + tagging_remove(tagging, message); break; } default: diff --git a/src/gnunet_chat_context.h b/src/gnunet_chat_context.h @@ -46,7 +46,7 @@ struct GNUNET_CHAT_Context struct GNUNET_CONTAINER_MultiShortmap *timestamps; struct GNUNET_CONTAINER_MultiHashMap *dependencies; struct GNUNET_CONTAINER_MultiHashMap *messages; - struct GNUNET_CONTAINER_MultiHashMap *rejections; + struct GNUNET_CONTAINER_MultiHashMap *taggings; struct GNUNET_CONTAINER_MultiHashMap *invites; struct GNUNET_CONTAINER_MultiHashMap *files; diff --git a/src/gnunet_chat_context_intern.c b/src/gnunet_chat_context_intern.c @@ -24,13 +24,14 @@ #include "gnunet_chat_invitation.h" #include "gnunet_chat_message.h" +#include "gnunet_chat_tagging.h" #include <gnunet/gnunet_common.h> #include <gnunet/gnunet_error_codes.h> #define GNUNET_UNUSED __attribute__ ((unused)) -int +enum GNUNET_GenericReturnValue it_destroy_context_timestamps (GNUNET_UNUSED void *cls, GNUNET_UNUSED const struct GNUNET_ShortHashCode *key, void *value) @@ -42,7 +43,7 @@ it_destroy_context_timestamps (GNUNET_UNUSED void *cls, return GNUNET_YES; } -int +enum GNUNET_GenericReturnValue it_destroy_context_messages (GNUNET_UNUSED void *cls, GNUNET_UNUSED const struct GNUNET_HashCode *key, void *value) @@ -54,7 +55,19 @@ it_destroy_context_messages (GNUNET_UNUSED void *cls, return GNUNET_YES; } -int +enum GNUNET_GenericReturnValue +it_destroy_context_taggings (GNUNET_UNUSED void *cls, + GNUNET_UNUSED const struct GNUNET_HashCode *key, + void *value) +{ + GNUNET_assert(value); + + struct GNUNET_CHAT_Tagging *tagging = value; + tagging_destroy(tagging); + return GNUNET_YES; +} + +enum GNUNET_GenericReturnValue it_destroy_context_invites (GNUNET_UNUSED void *cls, GNUNET_UNUSED const struct GNUNET_HashCode *key, void *value) diff --git a/src/gnunet_chat_handle_intern.c b/src/gnunet_chat_handle_intern.c @@ -29,6 +29,7 @@ #include "gnunet_chat_handle.h" #include "gnunet_chat_invitation.h" #include "gnunet_chat_message.h" +#include "gnunet_chat_tagging.h" #include "gnunet_chat_ticket.h" #include "gnunet_chat_util.h" @@ -890,13 +891,26 @@ on_handle_message_callback(void *cls) } case GNUNET_MESSENGER_KIND_TAG: { - if (message->msg->body.tag.tag) - break; - - GNUNET_CONTAINER_multihashmap_put( - context->rejections, &(message->msg->body.tag.hash), - message, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); + struct GNUNET_CHAT_Tagging *tagging = GNUNET_CONTAINER_multihashmap_get( + context->taggings, &(message->msg->body.tag.hash)); + + if (!tagging) + { + tagging = tagging_create(); + + if (!tagging) + break; + + if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put( + context->taggings, &(message->msg->body.tag.hash), tagging, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) + { + tagging_destroy(tagging); + break; + } + } + tagging_add(tagging, message); break; } default: diff --git a/src/gnunet_chat_lib.c b/src/gnunet_chat_lib.c @@ -44,6 +44,7 @@ #include "gnunet_chat_invitation.h" #include "gnunet_chat_lobby.h" #include "gnunet_chat_message.h" +#include "gnunet_chat_tagging.h" #include "gnunet_chat_ticket.h" #include "gnunet_chat_util.h" @@ -2320,10 +2321,10 @@ GNUNET_CHAT_invitation_is_rejected (const struct GNUNET_CHAT_Invitation *invitat if (!invitation) return GNUNET_NO; - return GNUNET_CONTAINER_multihashmap_contains( - invitation->context->rejections, - &(invitation->hash) - ); + const struct GNUNET_CHAT_Tagging *tagging = GNUNET_CONTAINER_multihashmap_get( + invitation->context->taggings, &(invitation->hash)); + + return tagging_iterate(tagging, GNUNET_NO, NULL, NULL, NULL) > 0; } diff --git a/src/gnunet_chat_tagging.c b/src/gnunet_chat_tagging.c @@ -0,0 +1,162 @@ +/* + This file is part of GNUnet. + Copyright (C) 2024 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 + */ +/* + * @author Tobias Frisch + * @file gnunet_chat_tagging.c + */ + +#include "gnunet_chat_tagging.h" +#include "gnunet_chat_message.h" + +#include <gnunet/gnunet_common.h> +#include <gnunet/gnunet_messenger_service.h> +#include <string.h> + +static const unsigned int initial_map_size_of_tagging = 4; + +struct GNUNET_CHAT_Tagging* +tagging_create () +{ + struct GNUNET_CHAT_Tagging* tagging = GNUNET_new(struct GNUNET_CHAT_Tagging); + + tagging->tags = GNUNET_CONTAINER_multihashmap_create( + initial_map_size_of_tagging, GNUNET_NO); + + return tagging; +} + +void +tagging_destroy (struct GNUNET_CHAT_Tagging *tagging) +{ + GNUNET_assert( + (tagging) && + (tagging->tags) + ); + + GNUNET_CONTAINER_multihashmap_destroy(tagging->tags); + + GNUNET_free(tagging); +} + +enum GNUNET_GenericReturnValue +tagging_add (struct GNUNET_CHAT_Tagging *tagging, + struct GNUNET_CHAT_Message *message) +{ + GNUNET_assert((tagging) && (message)); + + if ((GNUNET_YES != message_has_msg(message)) || + (GNUNET_MESSENGER_KIND_TAG != message->msg->header.kind)) + return GNUNET_SYSERR; + + const char *tag = message->msg->body.tag.tag; + struct GNUNET_HashCode hash; + + if (tag) + GNUNET_CRYPTO_hash_from_string(tag, &hash); + else + memset(&hash, 0, sizeof(hash)); + + return GNUNET_CONTAINER_multihashmap_put( + tagging->tags, + &hash, + message, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE + ); +} + +enum GNUNET_GenericReturnValue +tagging_remove (struct GNUNET_CHAT_Tagging *tagging, + const struct GNUNET_CHAT_Message *message) +{ + GNUNET_assert((tagging) && (message)); + + if ((GNUNET_YES != message_has_msg(message)) || + (GNUNET_MESSENGER_KIND_TAG != message->msg->header.kind)) + return GNUNET_SYSERR; + + const char *tag = message->msg->body.tag.tag; + struct GNUNET_HashCode hash; + + if (tag) + GNUNET_CRYPTO_hash_from_string(tag, &hash); + else + memset(&hash, 0, sizeof(hash)); + + return GNUNET_CONTAINER_multihashmap_remove( + tagging->tags, + &hash, + message + ); +} + +struct GNUNET_CHAT_TaggingIterator +{ + GNUNET_CHAT_TaggingCallback cb; + void *cls; +}; + +static enum GNUNET_GenericReturnValue +tagging_iterate_message (void *cls, + const struct GNUNET_HashCode *key, + void *value) +{ + struct GNUNET_CHAT_TaggingIterator *it = cls; + const struct GNUNET_CHAT_Message *message = value; + + if (!(it->cb)) + return GNUNET_YES; + + return it->cb(it->cls, message); +} + +int +tagging_iterate (const struct GNUNET_CHAT_Tagging *tagging, + enum GNUNET_GenericReturnValue ignore_tag, + const char *tag, + GNUNET_CHAT_TaggingCallback cb, + void *cls) +{ + GNUNET_assert(tagging); + + struct GNUNET_CHAT_TaggingIterator it; + it.cb = cb; + it.cls = cls; + + if (GNUNET_YES == ignore_tag) + return GNUNET_CONTAINER_multihashmap_iterate( + tagging->tags, + tagging_iterate_message, + &it + ); + + struct GNUNET_HashCode hash; + + if (tag) + GNUNET_CRYPTO_hash_from_string(tag, &hash); + else + memset(&hash, 0, sizeof(hash)); + + return GNUNET_CONTAINER_multihashmap_get_multiple( + tagging->tags, + &hash, + tagging_iterate_message, + &it + ); +} diff --git a/src/gnunet_chat_tagging.h b/src/gnunet_chat_tagging.h @@ -0,0 +1,107 @@ +/* + This file is part of GNUnet. + Copyright (C) 2024 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 + */ +/* + * @author Tobias Frisch + * @file gnunet_chat_tagging.h + */ + +#ifndef GNUNET_CHAT_TAGGING_H_ +#define GNUNET_CHAT_TAGGING_H_ + +#include <gnunet/gnunet_common.h> +#include <gnunet/gnunet_util_lib.h> + +struct GNUNET_CHAT_Message; + +struct GNUNET_CHAT_Tagging +{ + struct GNUNET_CONTAINER_MultiHashMap *tags; +}; + +typedef enum GNUNET_GenericReturnValue +(*GNUNET_CHAT_TaggingCallback) (void *cls, + const struct GNUNET_CHAT_Message *message); + +/** + * Creates a tagging structure to manage different tag messages + * mapped by its custom tag value. + * + * @return New chat tagging + */ +struct GNUNET_CHAT_Tagging* +tagging_create (); + +/** + * Destroys a <i>tagging</i> structure to manage different tag + * messages mapped by its custom tag value. + * + * @param[out] tagging Chat tagging + */ +void +tagging_destroy (struct GNUNET_CHAT_Tagging *tagging); + +/** + * Adds a tag <i>message</i> to a selected <i>tagging</i> + * structure for later iterations. + * + * @param[in,out] tagging Chat tagging + * @param[in,out] message Tag message + * @return #GNUNET_OK on success, otherwise #GNUNET_SYSERR + */ +enum GNUNET_GenericReturnValue +tagging_add (struct GNUNET_CHAT_Tagging *tagging, + struct GNUNET_CHAT_Message *message); + +/** + * Removes a tag <i>message</i> from a selected <i>tagging</i> + * structure. + * + * @param[in,out] tagging Chat tagging + * @param[in] message Tag message + * @return #GNUNET_YES on success, #GNUNET_SYSERR on failure and + * otherwise #GNUNET_NO + */ +enum GNUNET_GenericReturnValue +tagging_remove (struct GNUNET_CHAT_Tagging *tagging, + const struct GNUNET_CHAT_Message *message); + +/** + * Iterates through a selected <i>tagging</i> structure forwarding + * tag messages with a specific <i>tag</i> to a custom callback with + * its closure. + * + * If <i>ignore_tag</i> is set to #GNUNET_YES all tag messages of the + * <i>tagging</i> structure will be iterated, otherwise only with matching + * tag value. + * + * @param[in] tagging Chat tagging + * @param[in] ignore_tag Flag to set tag filtering of the iteration + * @param[in] tag Tag value for filtering the iteration + * @param[in] cb Callback for iteration + * @param[in,out] cls Closure for iteration + */ +int +tagging_iterate (const struct GNUNET_CHAT_Tagging *tagging, + enum GNUNET_GenericReturnValue ignore_tag, + const char *tag, + GNUNET_CHAT_TaggingCallback cb, + void *cls); + +#endif /* GNUNET_CHAT_TAGGING_H_ */ diff --git a/src/meson.build b/src/meson.build @@ -28,6 +28,7 @@ gnunetchat_sources = files([ 'gnunet_chat_invitation.c', 'gnunet_chat_invitation.h', 'gnunet_chat_lobby.c', 'gnunet_chat_lobby.h', 'gnunet_chat_message.c', 'gnunet_chat_message.h', + 'gnunet_chat_tagging.c', 'gnunet_chat_tagging.h', 'gnunet_chat_ticket.c', 'gnunet_chat_ticket.h', 'gnunet_chat_uri.c', 'gnunet_chat_uri.h', 'gnunet_chat_util.c', 'gnunet_chat_util.h',