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:
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',