summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTheJackiMonster <thejackimonster@gmail.com>2021-03-20 13:53:23 +0100
committerTheJackiMonster <thejackimonster@gmail.com>2021-04-04 17:58:11 +0200
commitac3aa3cc3a617bc54ed8beb2b5a30c0b95483525 (patch)
tree6e0444e568722f18501746665a07dfa3434c7ad6
parent2413977f917534aa24ef562a28da193a2cdaa343 (diff)
-multiple fixes and correction regarding messenger service
Signed-off-by: TheJackiMonster <thejackimonster@gmail.com> -added message states to tunnels Signed-off-by: TheJackiMonster <thejackimonster@gmail.com> -fixed requests for deleted messages returning previous ones Signed-off-by: TheJackiMonster <thejackimonster@gmail.com> -added automatic solving of member id collissions Signed-off-by: TheJackiMonster <thejackimonster@gmail.com> -added light timestamp verification Signed-off-by: TheJackiMonster <thejackimonster@gmail.com> -fixed decoding asserts and member session forwarding Signed-off-by: TheJackiMonster <thejackimonster@gmail.com> -added permission check for member sessions during local join Signed-off-by: TheJackiMonster <thejackimonster@gmail.com>
-rw-r--r--src/messenger/Makefile.am1
-rwxr-xr-xsrc/messenger/gnunet-service-messenger.c59
-rw-r--r--src/messenger/gnunet-service-messenger_member_session.c20
-rw-r--r--src/messenger/gnunet-service-messenger_member_session.h12
-rw-r--r--src/messenger/gnunet-service-messenger_message_handle.c14
-rw-r--r--src/messenger/gnunet-service-messenger_message_recv.c71
-rw-r--r--src/messenger/gnunet-service-messenger_message_send.c7
-rw-r--r--src/messenger/gnunet-service-messenger_message_send.h13
-rw-r--r--src/messenger/gnunet-service-messenger_message_state.c109
-rw-r--r--src/messenger/gnunet-service-messenger_message_state.h63
-rwxr-xr-xsrc/messenger/gnunet-service-messenger_message_store.c3
-rw-r--r--src/messenger/gnunet-service-messenger_room.c277
-rw-r--r--src/messenger/gnunet-service-messenger_room.h73
-rw-r--r--src/messenger/gnunet-service-messenger_tunnel.c30
-rw-r--r--src/messenger/gnunet-service-messenger_tunnel.h3
-rw-r--r--src/messenger/messenger_api.c2
-rwxr-xr-xsrc/messenger/messenger_api_message.c2
17 files changed, 587 insertions, 172 deletions
diff --git a/src/messenger/Makefile.am b/src/messenger/Makefile.am
index 2bb9ad922..3fc532e7e 100644
--- a/src/messenger/Makefile.am
+++ b/src/messenger/Makefile.am
@@ -68,6 +68,7 @@ gnunet_service_messenger_SOURCES = \
gnunet-service-messenger_message_kind.c gnunet-service-messenger_message_kind.h \
gnunet-service-messenger_message_recv.c gnunet-service-messenger_message_recv.h \
gnunet-service-messenger_message_send.c gnunet-service-messenger_message_send.h \
+ gnunet-service-messenger_message_state.c gnunet-service-messenger_message_state.h \
gnunet-service-messenger_message_store.c gnunet-service-messenger_message_store.h \
gnunet-service-messenger_operation_store.c gnunet-service-messenger_operation_store.h \
gnunet-service-messenger_operation.c gnunet-service-messenger_operation.h \
diff --git a/src/messenger/gnunet-service-messenger.c b/src/messenger/gnunet-service-messenger.c
index 76fb31d95..7edd76d32 100755
--- a/src/messenger/gnunet-service-messenger.c
+++ b/src/messenger/gnunet-service-messenger.c
@@ -25,6 +25,8 @@
#include "gnunet-service-messenger.h"
+#include "gnunet-service-messenger_handle.h"
+#include "gnunet-service-messenger_message_kind.h"
#include "gnunet-service-messenger_service.h"
#include "messenger_api_message.h"
@@ -209,6 +211,9 @@ check_for_message:
struct GNUNET_MESSENGER_Message message;
+ if (length < get_message_kind_size(GNUNET_MESSENGER_KIND_UNKNOWN))
+ return GNUNET_NO;
+
if (GNUNET_YES != decode_message (&message, msg_length, msg_buffer, GNUNET_NO, NULL))
return GNUNET_NO;
@@ -266,6 +271,35 @@ end_handling:
}
static void
+callback_found_message (void *cls, struct GNUNET_MESSENGER_SrvRoom *room,
+ const struct GNUNET_MESSENGER_Message *message,
+ const struct GNUNET_HashCode *hash)
+{
+ struct GNUNET_MESSENGER_Client *msg_client = cls;
+
+ if (!message)
+ {
+ send_room_message(room, msg_client->handle, create_message_request(hash));
+ return;
+ }
+
+ struct GNUNET_MESSENGER_MemberStore *store = get_room_member_store(room);
+
+ struct GNUNET_MESSENGER_Member *member = get_store_member_of(store, message);
+
+ if (!member)
+ {
+ GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Sender of message (%s) unknown!\n", GNUNET_h2s (hash));
+ return;
+ }
+
+ struct GNUNET_MESSENGER_MemberSession *session = get_member_session_of(member, message, hash);
+
+ if (session)
+ notify_handle_message (msg_client->handle, get_room_key(room), session, message, hash);
+}
+
+static void
handle_get_message (void *cls, const struct GNUNET_MESSENGER_GetMessage *msg)
{
struct GNUNET_MESSENGER_Client *msg_client = cls;
@@ -280,26 +314,27 @@ handle_get_message (void *cls, const struct GNUNET_MESSENGER_GetMessage *msg)
goto end_handling;
}
- const struct GNUNET_MESSENGER_Message *message = get_room_message (room, msg_client->handle, &(msg->hash),
- GNUNET_YES);
-
- if (!message)
- goto end_handling;
-
- struct GNUNET_MESSENGER_MemberStore *store = get_room_member_store(room);
+ struct GNUNET_MESSENGER_MemberStore *member_store = get_room_member_store(room);
- struct GNUNET_MESSENGER_Member *member = get_store_member_of(store, message);
+ struct GNUNET_MESSENGER_Member *member = get_store_member(member_store, get_handle_member_id(
+ msg_client->handle, &(msg->key)
+ ));
if (!member)
{
- GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Sender of message (%s) unknown!\n", GNUNET_h2s (&(msg->hash)));
+ GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Member not valid to request a message!\n");
goto end_handling;
}
- struct GNUNET_MESSENGER_MemberSession *session = get_member_session_of(member, message, &(msg->hash));
+ struct GNUNET_MESSENGER_MemberSession *session = get_member_session(member, &(get_handle_ego(msg_client->handle)->pub));
- if (session)
- notify_handle_message (msg_client->handle, get_room_key(room), session, message, &(msg->hash));
+ if (!session)
+ {
+ GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Session not valid to request a message!\n");
+ goto end_handling;
+ }
+
+ request_room_message (room, &(msg->hash), session, callback_found_message, msg_client);
end_handling:
GNUNET_SERVICE_client_continue (msg_client->client);
diff --git a/src/messenger/gnunet-service-messenger_member_session.c b/src/messenger/gnunet-service-messenger_member_session.c
index 2e6eae59e..690c703b2 100644
--- a/src/messenger/gnunet-service-messenger_member_session.c
+++ b/src/messenger/gnunet-service-messenger_member_session.c
@@ -71,6 +71,8 @@ create_member_session (struct GNUNET_MESSENGER_Member *member,
session->prev = NULL;
session->next = NULL;
+ session->start = GNUNET_TIME_absolute_get();
+
session->closed = GNUNET_NO;
session->completed = GNUNET_NO;
@@ -226,6 +228,8 @@ switch_member_session (struct GNUNET_MESSENGER_MemberSession *session,
next->prev = session;
next->next = NULL;
+ next->start = GNUNET_TIME_absolute_get();
+
session->closed = GNUNET_YES;
next->closed = GNUNET_NO;
next->completed = GNUNET_NO;
@@ -314,6 +318,17 @@ is_member_session_completed (const struct GNUNET_MESSENGER_MemberSession* sessio
return session->completed;
}
+struct GNUNET_TIME_Absolute
+get_member_session_start (const struct GNUNET_MESSENGER_MemberSession* session)
+{
+ GNUNET_assert(session);
+
+ if (session->prev)
+ return get_member_session_start(session->prev);
+
+ return session->start;
+}
+
const struct GNUNET_HashCode*
get_member_session_key (const struct GNUNET_MESSENGER_MemberSession* session)
{
@@ -521,6 +536,9 @@ load_member_session (struct GNUNET_MESSENGER_Member *member, const char *directo
unsigned long long numeric_value;
+ if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg, "session", "start", &numeric_value))
+ session->start.abs_value_us = numeric_value;
+
if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg, "session", "closed", &numeric_value))
session->closed = (GNUNET_YES == numeric_value? GNUNET_YES : GNUNET_NO);
@@ -701,6 +719,8 @@ save_member_session (struct GNUNET_MESSENGER_MemberSession *session, const char
}
}
+ GNUNET_CONFIGURATION_set_value_number(cfg, "session", "start", session->start.abs_value_us);
+
GNUNET_CONFIGURATION_set_value_number (cfg, "session", "closed", session->closed);
GNUNET_CONFIGURATION_set_value_number (cfg, "session", "completed", session->completed);
diff --git a/src/messenger/gnunet-service-messenger_member_session.h b/src/messenger/gnunet-service-messenger_member_session.h
index cf4a6bb07..fa9c6b829 100644
--- a/src/messenger/gnunet-service-messenger_member_session.h
+++ b/src/messenger/gnunet-service-messenger_member_session.h
@@ -30,6 +30,7 @@
#include "gnunet_crypto_lib.h"
#include "gnunet_container_lib.h"
#include "gnunet_identity_service.h"
+#include "gnunet_time_lib.h"
#include "gnunet-service-messenger_member.h"
@@ -49,6 +50,8 @@ struct GNUNET_MESSENGER_MemberSession {
struct GNUNET_MESSENGER_MemberSession* prev;
struct GNUNET_MESSENGER_MemberSession* next;
+ struct GNUNET_TIME_Absolute start;
+
int closed;
int completed;
};
@@ -140,6 +143,15 @@ int
is_member_session_completed (const struct GNUNET_MESSENGER_MemberSession* session);
/**
+ * Returns the timestamp of the member <i>session</i>'s start.
+ *
+ * @param[in] session Member session
+ * @return Absolute timestamp
+ */
+struct GNUNET_TIME_Absolute
+get_member_session_start (const struct GNUNET_MESSENGER_MemberSession* session);
+
+/**
* Returns the key of the room a given member <i>session</i> belongs to.
*
* @param[in] session Member session
diff --git a/src/messenger/gnunet-service-messenger_message_handle.c b/src/messenger/gnunet-service-messenger_message_handle.c
index c22e51fbf..1d489310c 100644
--- a/src/messenger/gnunet-service-messenger_message_handle.c
+++ b/src/messenger/gnunet-service-messenger_message_handle.c
@@ -44,6 +44,13 @@ handle_message_join (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSEN
if (GNUNET_OK != reset_member_session(session, hash))
GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Resetting member session failed!\n");
+
+ solve_room_member_collisions (
+ room,
+ &(message->body.join.key),
+ &(message->header.sender_id),
+ GNUNET_TIME_absolute_ntoh(message->header.timestamp)
+ );
}
void
@@ -91,6 +98,13 @@ handle_message_id (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGE
const struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
{
handle_session_switch (session, message, hash);
+
+ solve_room_member_collisions (
+ room,
+ get_member_session_public_key(session),
+ &(message->body.id.id),
+ GNUNET_TIME_absolute_ntoh(message->header.timestamp)
+ );
}
void
diff --git a/src/messenger/gnunet-service-messenger_message_recv.c b/src/messenger/gnunet-service-messenger_message_recv.c
index 8aab805d2..b2a5052d2 100644
--- a/src/messenger/gnunet-service-messenger_message_recv.c
+++ b/src/messenger/gnunet-service-messenger_message_recv.c
@@ -27,18 +27,46 @@
#include "gnunet-service-messenger_operation.h"
+static void
+forward_about_members (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
+ struct GNUNET_MESSENGER_MemberSession *session, struct GNUNET_CONTAINER_MultiHashMap *map)
+{
+ if (session->prev)
+ forward_about_members (room, tunnel, session->prev, map);
+
+ struct GNUNET_MESSENGER_MessageStore *message_store = get_room_message_store(room);
+ struct GNUNET_MESSENGER_ListMessage *element;
+
+ for (element = session->messages.head; element; element = element->next)
+ {
+ if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(map, &(element->hash)))
+ continue;
+
+ if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put(map, &(element->hash), NULL,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
+ GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Forwarding of session message could be duplicated!\n");
+
+ const struct GNUNET_MESSENGER_Message *message = get_store_message(message_store, &(element->hash));
+
+ if (message)
+ forward_tunnel_message(tunnel, message, &(element->hash));
+ }
+}
+
static int
iterate_forward_members (void *cls, const struct GNUNET_IDENTITY_PublicKey *public_key,
- struct GNUNET_MESSENGER_MemberSession *session)
+ struct GNUNET_MESSENGER_MemberSession *session)
{
struct GNUNET_MESSENGER_SrvTunnel *tunnel = cls;
- struct GNUNET_MESSENGER_SrvRoom *room = tunnel->room;
- struct GNUNET_MESSENGER_ListMessage *element;
+ if (GNUNET_YES == is_member_session_completed(session))
+ return GNUNET_YES;
- for (element = session->messages.head; element; element = element->next)
- forward_tunnel_message(tunnel, get_room_message(room, NULL, &(element->hash), GNUNET_NO), &(element->hash));
+ struct GNUNET_CONTAINER_MultiHashMap *map = GNUNET_CONTAINER_multihashmap_create(4, GNUNET_NO);
+ forward_about_members (tunnel->room, tunnel, session, map);
+
+ GNUNET_CONTAINER_multihashmap_destroy(map);
return GNUNET_YES;
}
@@ -97,32 +125,40 @@ recv_message_peer (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGE
return GNUNET_YES;
}
-int
-recv_message_request (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
- const struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
+static void
+callback_found_message (void *cls, struct GNUNET_MESSENGER_SrvRoom *room,
+ const struct GNUNET_MESSENGER_Message *message,
+ const struct GNUNET_HashCode *hash)
{
- const struct GNUNET_MESSENGER_Message *msg = get_room_message (
- room, NULL, &(message->body.request.hash), GNUNET_NO
- );
+ struct GNUNET_MESSENGER_SrvTunnel *tunnel = tunnel;
- if (!msg)
+ if (!message)
{
struct GNUNET_MESSENGER_OperationStore *operation_store = get_room_operation_store(room);
use_store_operation(
operation_store,
- &(message->body.request.hash),
+ hash,
GNUNET_MESSENGER_OP_REQUEST,
GNUNET_MESSENGER_REQUEST_DELAY
);
-
- return GNUNET_YES;
}
+ else
+ forward_tunnel_message (tunnel, message, hash);
+}
+/*
+ * Function returns GNUNET_NO to drop forwarding the request.
+ * It will only be forwarded if it can't be answered!
+ */
+int
+recv_message_request (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvTunnel *tunnel,
+ const struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
+{
struct GNUNET_MESSENGER_MemberStore *member_store = get_room_member_store(room);
struct GNUNET_MESSENGER_Member *member = get_store_member_of(member_store, message);
- GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Callback for message (%s)\n", GNUNET_h2s (hash));
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Request for message (%s)\n", GNUNET_h2s (hash));
if (!member)
return GNUNET_NO;
@@ -132,7 +168,8 @@ recv_message_request (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSE
if ((!session) || (GNUNET_YES != check_member_session_history(session, hash, GNUNET_NO)))
return GNUNET_NO;
- forward_tunnel_message (tunnel, msg, &(message->body.request.hash));
+ if (GNUNET_NO == request_room_message(room, &(message->body.request.hash), session, callback_found_message, tunnel))
+ return GNUNET_YES;
return GNUNET_NO;
}
diff --git a/src/messenger/gnunet-service-messenger_message_send.c b/src/messenger/gnunet-service-messenger_message_send.c
index 59bbaea8d..a59a178cc 100644
--- a/src/messenger/gnunet-service-messenger_message_send.c
+++ b/src/messenger/gnunet-service-messenger_message_send.c
@@ -47,6 +47,13 @@ send_message_peer (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGE
}
void
+send_message_id (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
+ const struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
+{
+ change_handle_member_id (handle, get_room_key(room), &(message->body.id.id));
+}
+
+void
send_message_request (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
const struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
{
diff --git a/src/messenger/gnunet-service-messenger_message_send.h b/src/messenger/gnunet-service-messenger_message_send.h
index 8e3ff4495..63320ab17 100644
--- a/src/messenger/gnunet-service-messenger_message_send.h
+++ b/src/messenger/gnunet-service-messenger_message_send.h
@@ -61,6 +61,19 @@ send_message_peer (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGE
const struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
/**
+ * Handles a sent id message to update the handles member id in the room.
+ * (changing member id is useful to prevent collisions)
+ *
+ * @param[in/out] room Room of the message
+ * @param[in/out] handle Sending handle
+ * @param[in] message ID-Message
+ * @param[in] hash Hash of the message
+ */
+void
+send_message_id (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
+ const struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
+
+/**
* Handles a sent request message to trigger the request operation for this service.
* (the request operation will deactivate the possibility of spamming requests)
*
diff --git a/src/messenger/gnunet-service-messenger_message_state.c b/src/messenger/gnunet-service-messenger_message_state.c
new file mode 100644
index 000000000..cdd2d9712
--- /dev/null
+++ b/src/messenger/gnunet-service-messenger_message_state.c
@@ -0,0 +1,109 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020--2021 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 src/messenger/gnunet-service-messenger_message_state.c
+ * @brief GNUnet MESSENGER service
+ */
+
+#include "gnunet-service-messenger_message_state.h"
+
+void
+init_message_state (struct GNUNET_MESSENGER_MessageState *state)
+{
+ GNUNET_assert(state);
+
+ init_list_messages (&(state->last_messages));
+}
+
+void
+clear_message_state (struct GNUNET_MESSENGER_MessageState *state)
+{
+ GNUNET_assert(state);
+
+ clear_list_messages (&(state->last_messages));
+}
+
+void
+get_message_state_chain_hash (const struct GNUNET_MESSENGER_MessageState *state,
+ struct GNUNET_HashCode *hash)
+{
+ GNUNET_assert((state) && (hash));
+
+ if (state->last_messages.head)
+ GNUNET_memcpy(hash, &(state->last_messages.head->hash), sizeof(*hash));
+ else
+ memset (hash, 0, sizeof(*hash));
+}
+
+const struct GNUNET_HashCode*
+get_message_state_merge_hash (const struct GNUNET_MESSENGER_MessageState *state)
+{
+ GNUNET_assert(state);
+
+ if (state->last_messages.head == state->last_messages.tail)
+ return NULL;
+
+ return &(state->last_messages.tail->hash);
+}
+
+void
+update_message_state (struct GNUNET_MESSENGER_MessageState *state, int requested,
+ const struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
+{
+ GNUNET_assert((state) && (message) && (hash));
+
+ if ((GNUNET_YES == requested) ||
+ (GNUNET_MESSENGER_KIND_INFO == message->header.kind) ||
+ (GNUNET_MESSENGER_KIND_REQUEST == message->header.kind))
+ return;
+
+ if (GNUNET_MESSENGER_KIND_MERGE == message->header.kind)
+ remove_from_list_messages(&(state->last_messages), &(message->body.merge.previous));
+ remove_from_list_messages(&(state->last_messages), &(message->header.previous));
+
+ add_to_list_messages (&(state->last_messages), hash);
+}
+
+void
+load_message_state (struct GNUNET_MESSENGER_MessageState *state, const char *path)
+{
+ GNUNET_assert((state) && (path));
+
+ char *last_messages_file;
+ GNUNET_asprintf (&last_messages_file, "%s%s", path, "last_messages.list");
+
+ load_list_messages(&(state->last_messages), last_messages_file);
+ GNUNET_free(last_messages_file);
+}
+
+void
+save_message_state (const struct GNUNET_MESSENGER_MessageState *state, const char *path)
+{
+ GNUNET_assert((state) && (path));
+
+ char *last_messages_file;
+ GNUNET_asprintf (&last_messages_file, "%s%s", path, "last_messages.list");
+
+ save_list_messages(&(state->last_messages), last_messages_file);
+ GNUNET_free(last_messages_file);
+}
+
+
diff --git a/src/messenger/gnunet-service-messenger_message_state.h b/src/messenger/gnunet-service-messenger_message_state.h
new file mode 100644
index 000000000..dc8671df4
--- /dev/null
+++ b/src/messenger/gnunet-service-messenger_message_state.h
@@ -0,0 +1,63 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2020--2021 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 src/messenger/gnunet-service-messenger_message_state.h
+ * @brief GNUnet MESSENGER service
+ */
+
+#ifndef GNUNET_SERVICE_MESSENGER_MESSAGE_STATE_H
+#define GNUNET_SERVICE_MESSENGER_MESSAGE_STATE_H
+
+#include "platform.h"
+#include "gnunet_crypto_lib.h"
+
+#include "messenger_api_message.h"
+#include "gnunet-service-messenger_list_messages.h"
+
+struct GNUNET_MESSENGER_MessageState
+{
+ struct GNUNET_MESSENGER_ListMessages last_messages;
+};
+
+void
+init_message_state (struct GNUNET_MESSENGER_MessageState *state);
+
+void
+clear_message_state (struct GNUNET_MESSENGER_MessageState *state);
+
+void
+get_message_state_chain_hash (const struct GNUNET_MESSENGER_MessageState *state,
+ struct GNUNET_HashCode *hash);
+
+const struct GNUNET_HashCode*
+get_message_state_merge_hash (const struct GNUNET_MESSENGER_MessageState *state);
+
+void
+update_message_state (struct GNUNET_MESSENGER_MessageState *state, int requested,
+ const struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash);
+
+void
+load_message_state (struct GNUNET_MESSENGER_MessageState *state, const char *path);
+
+void
+save_message_state (const struct GNUNET_MESSENGER_MessageState *state, const char *path);
+
+#endif //GNUNET_SERVICE_MESSENGER_MESSAGE_STATE_H
diff --git a/src/messenger/gnunet-service-messenger_message_store.c b/src/messenger/gnunet-service-messenger_message_store.c
index b143c6c98..1984eba21 100755
--- a/src/messenger/gnunet-service-messenger_message_store.c
+++ b/src/messenger/gnunet-service-messenger_message_store.c
@@ -408,7 +408,8 @@ get_store_message (struct GNUNET_MESSENGER_MessageStore *store, const struct GNU
if (!buffer)
return NULL;
- if (GNUNET_DISK_file_read (store->storage_messages, buffer, entry->length) != entry->length)
+ if ((GNUNET_DISK_file_read (store->storage_messages, buffer, entry->length) != entry->length) ||
+ (entry->length < get_message_kind_size(GNUNET_MESSENGER_KIND_UNKNOWN)))
goto free_buffer;
message = create_message (GNUNET_MESSENGER_KIND_UNKNOWN);
diff --git a/src/messenger/gnunet-service-messenger_room.c b/src/messenger/gnunet-service-messenger_room.c
index 027df682c..e8fe5b1f3 100644
--- a/src/messenger/gnunet-service-messenger_room.c
+++ b/src/messenger/gnunet-service-messenger_room.c
@@ -62,7 +62,7 @@ create_room (struct GNUNET_MESSENGER_SrvHandle *handle, const struct GNUNET_Hash
init_operation_store(get_room_operation_store(room), room);
init_list_tunnels (&(room->basement));
- init_list_messages (&(room->last_messages));
+ init_message_state(&(room->state));
room->peer_message = NULL;
@@ -117,7 +117,7 @@ destroy_room (struct GNUNET_MESSENGER_SrvRoom *room)
GNUNET_CONTAINER_multipeermap_destroy (room->tunnels);
clear_list_tunnels (&(room->basement));
- clear_list_messages (&(room->last_messages));
+ clear_message_state(&(room->state));
if (room->peer_message)
GNUNET_free(room->peer_message);
@@ -149,22 +149,6 @@ get_room_operation_store (struct GNUNET_MESSENGER_SrvRoom *room)
return &(room->operation_store);
}
-const struct GNUNET_ShortHashCode*
-get_room_host_id (const struct GNUNET_MESSENGER_SrvRoom *room)
-{
- GNUNET_assert(room);
-
- return get_handle_member_id (room->host, get_room_key(room));
-}
-
-void
-change_room_host_id (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_ShortHashCode *unique_id)
-{
- GNUNET_assert(room);
-
- change_handle_member_id (room->host, get_room_key(room), unique_id);
-}
-
static int
send_room_info (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
struct GNUNET_MESSENGER_SrvTunnel *tunnel)
@@ -243,27 +227,50 @@ struct GNUNET_MESSENGER_MemberNotify
struct GNUNET_MESSENGER_MemberSession *session;
};
-static int
-iterate_notify_about_members (void *cls, const struct GNUNET_IDENTITY_PublicKey *public_key,
- struct GNUNET_MESSENGER_MemberSession *session)
+static void
+notify_about_members (struct GNUNET_MESSENGER_MemberNotify *notify, struct GNUNET_MESSENGER_MemberSession *session,
+ struct GNUNET_CONTAINER_MultiHashMap *map, int check_permission)
{
- struct GNUNET_MESSENGER_MemberNotify *notify = cls;
-
- if (notify->session == session)
- return GNUNET_YES;
+ if (session->prev)
+ notify_about_members (notify, session->prev, map, GNUNET_YES);
+ struct GNUNET_MESSENGER_MessageStore *message_store = get_room_message_store(notify->room);
struct GNUNET_MESSENGER_ListMessage *element;
for (element = session->messages.head; element; element = element->next)
{
- const struct GNUNET_MESSENGER_Message *message = get_room_message (
- notify->room, notify->handle, &(element->hash), GNUNET_NO
- );
+ if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(map, &(element->hash)))
+ continue;
+
+ if ((GNUNET_YES == check_permission) &&
+ (GNUNET_YES != check_member_session_history(notify->session, &(element->hash), GNUNET_NO)))
+ continue;
+
+ if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put(map, &(element->hash), NULL,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
+ GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Notification of session message could be duplicated!\n");
+
+ const struct GNUNET_MESSENGER_Message *message = get_store_message(message_store, &(element->hash));
if (message)
notify_handle_message (notify->handle, get_room_key(notify->room), session, message, &(element->hash));
}
+}
+
+static int
+iterate_notify_about_members (void *cls, const struct GNUNET_IDENTITY_PublicKey *public_key,
+ struct GNUNET_MESSENGER_MemberSession *session)
+{
+ struct GNUNET_MESSENGER_MemberNotify *notify = cls;
+ if ((notify->session == session) || (GNUNET_YES == is_member_session_completed(session)))
+ return GNUNET_YES;
+
+ struct GNUNET_CONTAINER_MultiHashMap *map = GNUNET_CONTAINER_multihashmap_create(4, GNUNET_NO);
+
+ notify_about_members (notify, session, map, GNUNET_NO);
+
+ GNUNET_CONTAINER_multihashmap_destroy(map);
return GNUNET_YES;
}
@@ -407,11 +414,7 @@ pack_room_message (const struct GNUNET_MESSENGER_SrvRoom *room, const struct GNU
GNUNET_assert(id);
GNUNET_memcpy(&(message->header.sender_id), id, sizeof(struct GNUNET_ShortHashCode));
-
- if (room->last_messages.head)
- GNUNET_memcpy(&(message->header.previous), &(room->last_messages.head->hash), sizeof(struct GNUNET_HashCode));
- else
- memset (&(message->header.previous), 0, sizeof(struct GNUNET_HashCode));
+ get_message_state_chain_hash (&(room->state), &(message->header.previous));
return pack_message (message, hash, get_handle_ego (handle), mode);
}
@@ -510,6 +513,9 @@ send_room_message (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGE
case GNUNET_MESSENGER_KIND_PEER:
send_message_peer (room, handle, message, &hash);
break;
+ case GNUNET_MESSENGER_KIND_ID:
+ send_message_id (room, handle, message, &hash);
+ break;
case GNUNET_MESSENGER_KIND_REQUEST:
send_message_request (room, handle, message, &hash);
break;
@@ -551,7 +557,9 @@ check_room_peer_status (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MES
if (!room->peer_message)
return;
- const struct GNUNET_MESSENGER_Message *message = get_room_message(room, NULL, room->peer_message, GNUNET_NO);
+ struct GNUNET_MESSENGER_MessageStore *message_store = get_room_message_store(room);
+
+ const struct GNUNET_MESSENGER_Message *message = get_store_message(message_store, room->peer_message);
if (!message)
{
@@ -581,15 +589,6 @@ resend_peer_message:
send_room_message (room, room->host, create_message_peer (room->service));
}
-static void
-merge_room_message (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
- const struct GNUNET_HashCode *hash)
-{
- GNUNET_assert((room) && (handle) && (hash));
-
- send_room_message (room, handle, create_message_merge (hash));
-}
-
void
merge_room_last_messages (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle)
{
@@ -598,21 +597,21 @@ merge_room_last_messages (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_M
if (!handle)
return;
- if (!room->last_messages.head)
+ const struct GNUNET_HashCode *hash;
+
+merge_next:
+ hash = get_message_state_merge_hash (&(room->state));
+
+ if (!hash)
return;
- while (room->last_messages.head != room->last_messages.tail)
- merge_room_message (room, handle, &(room->last_messages.tail->hash));
+ send_room_message (room, handle, create_message_merge (hash));
+ goto merge_next;
}
void
callback_room_deletion (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_HashCode *hash)
{
- const struct GNUNET_MESSENGER_Message *message = get_room_message(room, NULL, hash, GNUNET_NO);
-
- if (message)
- add_to_list_messages(&(room->last_messages), &(message->header.previous));
-
if (GNUNET_OK != delete_store_message (get_room_message_store(room), hash))
{
GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Deletion of message failed! (%s)\n", GNUNET_h2s(hash));
@@ -626,7 +625,7 @@ callback_room_merge (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_
if (!room->host)
return;
- merge_room_message (room, room->host, hash);
+ send_room_message (room, room->host, create_message_merge (hash));
}
int
@@ -643,7 +642,9 @@ delete_room_message (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSEN
return GNUNET_SYSERR;
}
- const struct GNUNET_MESSENGER_Message *message = get_room_message(room, NULL, hash, GNUNET_NO);
+ struct GNUNET_MESSENGER_MessageStore *message_store = get_room_message_store(room);
+
+ const struct GNUNET_MESSENGER_Message *message = get_store_message(message_store, hash);
if (!message)
return GNUNET_YES;
@@ -691,23 +692,56 @@ get_room_tunnel (const struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNE
return GNUNET_CONTAINER_multipeermap_get (room->tunnels, peer);
}
-const struct GNUNET_MESSENGER_Message*
-get_room_message (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
- const struct GNUNET_HashCode *hash, int request)
+static int
+request_room_message_step (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_HashCode *hash,
+ const struct GNUNET_MESSENGER_MemberSession *session,
+ GNUNET_MESSENGER_MessageRequestCallback callback, void* cls)
{
- GNUNET_assert((room) && (hash));
+ struct GNUNET_MESSENGER_MessageStore *message_store = get_room_message_store(room);
- const struct GNUNET_MESSENGER_Message *message = get_store_message (get_room_message_store(room), hash);
+ const struct GNUNET_MESSENGER_MessageLink *link = get_store_message_link(
+ message_store, hash, GNUNET_YES
+ );
- if ((message) || (!handle) || (GNUNET_YES != request))
- return message;
+ if (!link)
+ goto forward;
- struct GNUNET_MESSENGER_OperationStore* operation_store = get_room_operation_store(room);
+ int result = request_room_message_step(room, &(link->first), session, callback, cls);
- if (GNUNET_OK == use_store_operation(operation_store, hash, GNUNET_MESSENGER_OP_REQUEST, GNUNET_MESSENGER_REQUEST_DELAY))
- send_room_message (room, handle, create_message_request (hash));
+ if ((GNUNET_YES == link->multiple) &&
+ (GNUNET_YES == request_room_message_step(room, &(link->second), session, callback, cls)))
+ return GNUNET_YES;
+ else
+ return result;
- return NULL;
+forward:
+ if (GNUNET_YES != check_member_session_history(session, hash, GNUNET_NO))
+ return GNUNET_YES;
+
+ const struct GNUNET_MESSENGER_Message *message = get_store_message(message_store, hash);
+
+ if (!message)
+ return GNUNET_NO;
+
+ if (callback)
+ callback (cls, room, message, hash);
+
+ return GNUNET_YES;
+}
+
+int
+request_room_message (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_HashCode *hash,
+ const struct GNUNET_MESSENGER_MemberSession *session,
+ GNUNET_MESSENGER_MessageRequestCallback callback, void* cls)
+{
+ GNUNET_assert((room) && (hash));
+
+ int result = request_room_message_step (room, hash, session, callback, cls);
+
+ if ((GNUNET_NO == result) && (callback))
+ callback (cls, room, NULL, hash);
+
+ return result;
}
void
@@ -739,6 +773,23 @@ callback_verify_room_message (struct GNUNET_MESSENGER_SrvRoom *room, void *cls,
return GNUNET_SYSERR;
}
+ struct GNUNET_MESSENGER_MessageStore *message_store = get_room_message_store(room);
+
+ const struct GNUNET_MESSENGER_Message *previous = get_store_message(message_store, &(message->header.previous));
+
+ if (!previous)
+ goto skip_time_comparison;
+
+ struct GNUNET_TIME_Absolute timestamp = GNUNET_TIME_absolute_ntoh(message->header.timestamp);
+ struct GNUNET_TIME_Absolute last = GNUNET_TIME_absolute_ntoh(previous->header.timestamp);
+
+ if (GNUNET_TIME_relative_get_zero_().rel_value_us != GNUNET_TIME_absolute_get_difference(timestamp, last).rel_value_us)
+ {
+ GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Message error: Timestamp does not check out!\n");
+ return GNUNET_SYSERR;
+ }
+
+skip_time_comparison:
GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Receiving message of kind: %s!\n",
GNUNET_MESSENGER_name_of_kind(message->header.kind));
@@ -753,12 +804,13 @@ idle_request_room_messages (void *cls)
room->idle = NULL;
struct GNUNET_MESSENGER_OperationStore *operation_store = get_room_operation_store(room);
+ const struct GNUNET_HashCode *hash = get_message_state_merge_hash(&(room->state));
- if ((room->last_messages.head != room->last_messages.tail) &&
- (GNUNET_MESSENGER_OP_UNKNOWN == get_store_operation_type(operation_store, &(room->last_messages.tail->hash))))
+ if ((hash) &&
+ (GNUNET_MESSENGER_OP_UNKNOWN == get_store_operation_type(operation_store, hash)))
use_store_operation(
operation_store,
- &(room->last_messages.tail->hash),
+ hash,
GNUNET_MESSENGER_OP_MERGE,
GNUNET_MESSENGER_MERGE_DELAY
);
@@ -772,6 +824,46 @@ idle_request_room_messages (void *cls)
}
void
+solve_room_member_collisions (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_IDENTITY_PublicKey *public_key,
+ const struct GNUNET_ShortHashCode *member_id, struct GNUNET_TIME_Absolute timestamp)
+{
+ GNUNET_assert ((room) && (public_key) && (member_id));
+
+ struct GNUNET_MESSENGER_MemberStore *member_store = get_room_member_store(room);
+ struct GNUNET_MESSENGER_Member *member = get_store_member(member_store, member_id);
+
+ if ((!member) || (1 >= GNUNET_CONTAINER_multihashmap_size(member->sessions)))
+ return;
+
+ struct GNUNET_MESSENGER_ListHandles *handles = &(room->service->handles);
+ struct GNUNET_MESSENGER_ListHandle* element;
+
+ for (element = handles->head; element; element = element->next)
+ {
+ if (0 != GNUNET_memcmp(member_id, get_handle_member_id(element->handle, get_room_key(room))))
+ continue;
+
+ if (0 == GNUNET_memcmp(public_key, &(get_handle_ego(element->handle)->pub)))
+ continue;
+
+ struct GNUNET_MESSENGER_MemberSession *session = get_member_session(member, &(get_handle_ego(element->handle)->pub));
+
+ if (!session)
+ continue;
+
+ struct GNUNET_TIME_Absolute start = get_member_session_start(session);
+
+ if (GNUNET_TIME_relative_get_zero_().rel_value_us != GNUNET_TIME_absolute_get_difference(start, timestamp).rel_value_us)
+ continue;
+
+ struct GNUNET_ShortHashCode random_id;
+ generate_free_member_id (&random_id, member_store->members);
+
+ send_room_message(room, element->handle, create_message_id(&random_id));
+ }
+}
+
+void
rebuild_room_basement_structure (struct GNUNET_MESSENGER_SrvRoom *room)
{
GNUNET_assert(room);
@@ -821,25 +913,27 @@ rebuild_room_basement_structure (struct GNUNET_MESSENGER_SrvRoom *room)
static void
handle_room_messages (struct GNUNET_MESSENGER_SrvRoom *room)
{
+ struct GNUNET_MESSENGER_MessageStore *message_store = get_room_message_store(room);
+ struct GNUNET_MESSENGER_MemberStore *member_store = get_room_member_store(room);
+
while (room->handling.head)
{
struct GNUNET_MESSENGER_ListMessage *element = room->handling.head;
- const struct GNUNET_MESSENGER_Message *msg = get_room_message (room, room->host, &(element->hash), GNUNET_NO);
+ const struct GNUNET_MESSENGER_Message *message = get_store_message (message_store, &(element->hash));
- if (!msg)
+ if (!message)
goto finish_handling;
- struct GNUNET_MESSENGER_MemberStore *member_store = get_room_member_store(room);
- struct GNUNET_MESSENGER_Member *member = get_store_member_of(member_store, msg);
+ struct GNUNET_MESSENGER_Member *member = get_store_member_of(member_store, message);
if (!member)
goto finish_handling;
- struct GNUNET_MESSENGER_MemberSession *session = get_member_session_of(member, msg, &(element->hash));
+ struct GNUNET_MESSENGER_MemberSession *session = get_member_session_of(member, message, &(element->hash));
if (session)
- handle_service_message (room->service, room, session, msg, &(element->hash));
+ handle_service_message (room->service, room, session, message, &(element->hash));
finish_handling:
GNUNET_CONTAINER_DLL_remove(room->handling.head, room->handling.tail, element);
@@ -847,17 +941,6 @@ finish_handling:
}
}
-static void
-remove_room_last_message (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_HashCode *hash)
-{
- remove_from_list_messages(&(room->last_messages), hash);
-
- struct GNUNET_MESSENGER_OperationStore *operation_store = get_room_operation_store(room);
-
- if (GNUNET_MESSENGER_OP_MERGE == get_store_operation_type(operation_store, hash))
- cancel_store_operation(operation_store, hash);
-}
-
int
update_room_message (struct GNUNET_MESSENGER_SrvRoom *room,
struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
@@ -873,11 +956,13 @@ update_room_message (struct GNUNET_MESSENGER_SrvRoom *room,
if (GNUNET_YES == requested)
cancel_store_operation(operation_store, hash);
- const struct GNUNET_MESSENGER_Message *old_message = get_room_message (room, NULL, hash, GNUNET_NO);
+ struct GNUNET_MESSENGER_MessageStore *message_store = get_room_message_store(room);
+
+ const struct GNUNET_MESSENGER_Message *old_message = get_store_message (message_store, hash);
GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Handle a message in room (%s).\n", GNUNET_h2s (get_room_key(room)));
- if ((old_message) || (GNUNET_OK != put_store_message (get_room_message_store(room), hash, message)))
+ if ((old_message) || (GNUNET_OK != put_store_message (message_store, hash, message)))
{
if (old_message != message)
destroy_message(message);
@@ -886,16 +971,19 @@ update_room_message (struct GNUNET_MESSENGER_SrvRoom *room,
return GNUNET_NO;
}
+ update_message_state(&(room->state), requested, message, hash);
+
if ((GNUNET_YES == requested) ||
(GNUNET_MESSENGER_KIND_INFO == message->header.kind) ||
(GNUNET_MESSENGER_KIND_REQUEST == message->header.kind))
return GNUNET_YES;
- if (GNUNET_MESSENGER_KIND_MERGE == message->header.kind)
- remove_room_last_message(room, &(message->body.merge.previous));
- remove_room_last_message(room, &(message->header.previous));
+ if ((GNUNET_MESSENGER_KIND_MERGE == message->header.kind) &&
+ (GNUNET_MESSENGER_OP_MERGE == get_store_operation_type(operation_store, &(message->body.merge.previous))))
+ cancel_store_operation(operation_store, &(message->body.merge.previous));
- add_to_list_messages (&(room->last_messages), hash);
+ if (GNUNET_MESSENGER_OP_MERGE == get_store_operation_type(operation_store, &(message->header.previous)))
+ cancel_store_operation(operation_store, &(message->header.previous));
return GNUNET_YES;
}
@@ -1053,8 +1141,7 @@ load_room (struct GNUNET_MESSENGER_SrvRoom *room)
char *last_messages_file;
GNUNET_asprintf (&last_messages_file, "%s%s", room_dir, "last_messages.list");
- load_list_messages(&(room->last_messages), last_messages_file);
- GNUNET_free(last_messages_file);
+ load_message_state(&(room->state), room_dir);
}
GNUNET_free(room_dir);
@@ -1081,11 +1168,7 @@ save_room (struct GNUNET_MESSENGER_SrvRoom *room)
save_list_tunnels(&(room->basement), basement_file);
GNUNET_free(basement_file);
- char *last_messages_file;
- GNUNET_asprintf (&last_messages_file, "%s%s", room_dir, "last_messages.list");
-
- save_list_messages(&(room->last_messages), last_messages_file);
- GNUNET_free(last_messages_file);
+ save_message_state(&(room->state), room_dir);
}
GNUNET_free(room_dir);
diff --git a/src/messenger/gnunet-service-messenger_room.h b/src/messenger/gnunet-service-messenger_room.h
index a40961177..b6a0f1064 100644
--- a/src/messenger/gnunet-service-messenger_room.h
+++ b/src/messenger/gnunet-service-messenger_room.h
@@ -36,6 +36,7 @@
#include "gnunet_messenger_service.h"
#include "gnunet-service-messenger_basement.h"
#include "gnunet-service-messenger_handle.h"
+#include "gnunet-service-messenger_message_state.h"
#include "gnunet-service-messenger_list_messages.h"
#include "messenger_api_list_tunnels.h"
@@ -72,7 +73,7 @@ struct GNUNET_MESSENGER_SrvRoom
struct GNUNET_MESSENGER_OperationStore operation_store;
struct GNUNET_MESSENGER_ListTunnels basement;
- struct GNUNET_MESSENGER_ListMessages last_messages;
+ struct GNUNET_MESSENGER_MessageState state;
struct GNUNET_HashCode *peer_message;
@@ -126,24 +127,6 @@ struct GNUNET_MESSENGER_OperationStore*
get_room_operation_store (struct GNUNET_MESSENGER_SrvRoom *room);
/**
- * Returns the member id of the member representing the handle currently hosting this <i>room</i>.
- *
- * @param[in] room Room
- * @return Host member id or NULL
- */
-const struct GNUNET_ShortHashCode*
-get_room_host_id (const struct GNUNET_MESSENGER_SrvRoom *room);
-
-/**
- * Changes the member id of the member representing the handle currently hosting this <i>room</i>.
- *
- * @param[in/out] room Room
- * @param[in] unique_id Unique member id
- */
-void
-change_room_host_id (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_ShortHashCode *unique_id);
-
-/**
* Tries to open a <i>room</i> for a given <i>handle</i>. If the room has already been opened, the handle
* will locally join the room.
*
@@ -289,25 +272,51 @@ const struct GNUNET_MESSENGER_SrvTunnel*
get_room_tunnel (const struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_PeerIdentity *peer);
/**
- * Returns a message from a <i>room</i> identified by a given <i>hash</i>. If no matching message is
- * found and <i>request</i> is set to #GNUNET_YES, the <i>handle</i> will request the missing message
- * automatically.
+ * Method called whenever a <i>message</i> is found during a request in a <i>room</i>.
*
- * The function uses the optimized check for a message via its hash from the message store.
- * @see contains_store_message()
+ * @param[in/out] cls Closure from #request_room_message
+ * @param[in/out] room Room
+ * @param[in] message Message or NULL
+ * @param[in] hash Hash of message
+ */
+typedef void (GNUNET_MESSENGER_MessageRequestCallback) (
+ void *cls, struct GNUNET_MESSENGER_SrvRoom *room,
+ const struct GNUNET_MESSENGER_Message *message,
+ const struct GNUNET_HashCode *hash
+);
+
+/**
+ * Requests a message from a <i>room</i> identified by a given <i>hash</i>. If the message is found,
+ * the selected <i>callback</i> will be called with it and the provided closure. If no matching message
+ * is found but it wasn't deleted the selected callback will be called with #NULL as message instead.
+ * In case of deletion the next available previous message will be used to call the callback.
*
- * If a message is missing independent of the following request, NULL gets returned instead of the
- * matching message.
+ * It is also possible that the given callback will not be called if the requesting session is not
+ * permitted!
*
* @param[in/out] room Room
- * @param[in/out] handle Handle
* @param[in] hash Hash of message
- * @param[in] request Flag to request a message
- * @return Message or NULL
+ * @param[in] callback Callback to process result
+ * @param[in] cls Closure for the <i>callback</i>
+ * @return #GNUNET_YES if the request could be processed, otherwise #GNUNET_NO
+ */
+int
+request_room_message (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_HashCode *hash,
+ const struct GNUNET_MESSENGER_MemberSession *session,
+ GNUNET_MESSENGER_MessageRequestCallback callback, void* cls);
+
+/**
+ * Checks for potential collisions with member ids and solves them changing active handles ids if they
+ * use an already used member id (comparing public key and timestamp).
+ *
+ * @param[in/out] room Room
+ * @param[in] public_key Public key of EGO
+ * @param[in] member_id Member ID
+ * @param[in] timestamp Timestamp
*/
-const struct GNUNET_MESSENGER_Message*
-get_room_message (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUNET_MESSENGER_SrvHandle *handle,
- const struct GNUNET_HashCode *hash, int request);
+void
+solve_room_member_collisions (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_IDENTITY_PublicKey *public_key,
+ const struct GNUNET_ShortHashCode *member_id, struct GNUNET_TIME_Absolute timestamp);
/**
* Rebuilds the decentralized structure for a <i>room</i> by ensuring all required connections are made
diff --git a/src/messenger/gnunet-service-messenger_tunnel.c b/src/messenger/gnunet-service-messenger_tunnel.c
index f7e8713c6..80d8dfa5e 100644
--- a/src/messenger/gnunet-service-messenger_tunnel.c
+++ b/src/messenger/gnunet-service-messenger_tunnel.c
@@ -27,6 +27,9 @@
#include "gnunet-service-messenger_handle.h"
#include "gnunet-service-messenger_message_recv.h"
+#include "gnunet-service-messenger_message_store.h"
+#include "gnunet-service-messenger_operation_store.h"
+#include "gnunet-service-messenger_operation.h"
#include "messenger_api_util.h"
struct GNUNET_MESSENGER_SrvTunnel*
@@ -44,7 +47,8 @@ create_tunnel (struct GNUNET_MESSENGER_SrvRoom *room, const struct GNUNET_PeerId
tunnel->messenger_version = 0;
tunnel->peer_message = NULL;
- tunnel->last_message = NULL;
+
+ init_message_state(&(tunnel->state));
return tunnel;
}
@@ -62,8 +66,7 @@ destroy_tunnel (struct GNUNET_MESSENGER_SrvTunnel *tunnel)
if (tunnel->peer_message)
GNUNET_free(tunnel->peer_message);
- if (tunnel->last_message)
- GNUNET_free(tunnel->last_message);
+ clear_message_state(&(tunnel->state));
GNUNET_free(tunnel);
}
@@ -143,10 +146,18 @@ callback_room_handle_message (struct GNUNET_MESSENGER_SrvRoom *room, struct GNUN
static void
update_tunnel_last_message (struct GNUNET_MESSENGER_SrvTunnel *tunnel, const struct GNUNET_HashCode *hash)
{
- if (!tunnel->last_message)
- tunnel->last_message = GNUNET_new(struct GNUNET_HashCode);
+ struct GNUNET_MESSENGER_OperationStore *operation_store = get_room_operation_store(tunnel->room);
+
+ const int requested = (GNUNET_MESSENGER_OP_REQUEST == get_store_operation_type(operation_store, hash)?
+ GNUNET_YES : GNUNET_NO
+ );
+
+ struct GNUNET_MESSENGER_MessageStore *message_store = get_room_message_store(tunnel->room);
+
+ const struct GNUNET_MESSENGER_Message *message = get_store_message(message_store, hash);
- GNUNET_memcpy(tunnel->last_message, hash, sizeof(*hash));
+ if (message)
+ update_message_state(&(tunnel->state), requested, message, hash);
}
void
@@ -171,7 +182,9 @@ handle_tunnel_message (void *cls, const struct GNUNET_MessageHeader *header)
if (!tunnel)
return;
- const int new_message = update_room_message (tunnel->room, copy_message (&message), &hash);
+ const int new_message = update_room_message (
+ tunnel->room, copy_message (&message), &hash
+ );
if (GNUNET_YES != new_message)
goto receive_done;
@@ -313,9 +326,6 @@ void
forward_tunnel_message (struct GNUNET_MESSENGER_SrvTunnel *tunnel, const struct GNUNET_MESSENGER_Message *message,
const struct GNUNET_HashCode *hash)
{
- if (!message)
- return;
-
GNUNET_assert((tunnel) && (message) && (hash));
struct GNUNET_MESSENGER_Message *copy = copy_message(message);
diff --git a/src/messenger/gnunet-service-messenger_tunnel.h b/src/messenger/gnunet-service-messenger_tunnel.h
index 51c5d32c1..96d98546d 100644
--- a/src/messenger/gnunet-service-messenger_tunnel.h
+++ b/src/messenger/gnunet-service-messenger_tunnel.h
@@ -32,6 +32,7 @@
#include "gnunet_crypto_lib.h"
#include "gnunet-service-messenger_room.h"
+#include "gnunet-service-messenger_message_state.h"
struct GNUNET_MESSENGER_SrvTunnel
{
@@ -43,7 +44,7 @@ struct GNUNET_MESSENGER_SrvTunnel
uint32_t messenger_version;
struct GNUNET_HashCode *peer_message;
- struct GNUNET_HashCode *last_message;
+ struct GNUNET_MESSENGER_MessageState state;
};
/**
diff --git a/src/messenger/messenger_api.c b/src/messenger/messenger_api.c
index dc6d11aaf..b42bb40cc 100644
--- a/src/messenger/messenger_api.c
+++ b/src/messenger/messenger_api.c
@@ -199,7 +199,7 @@ check_recv_message (void *cls, const struct GNUNET_MESSENGER_RecvMessage *msg)
struct GNUNET_MESSENGER_Message message;
- if (length < sizeof(message.header))
+ if (length < get_message_kind_size(GNUNET_MESSENGER_KIND_UNKNOWN))
return GNUNET_NO;
if (GNUNET_YES != decode_message (&message, length, buffer, GNUNET_YES, NULL))
diff --git a/src/messenger/messenger_api_message.c b/src/messenger/messenger_api_message.c
index 0d885f9ee..d65b80576 100755
--- a/src/messenger/messenger_api_message.c
+++ b/src/messenger/messenger_api_message.c
@@ -590,7 +590,7 @@ int
decode_message (struct GNUNET_MESSENGER_Message *message, uint16_t length, const char *buffer,
int include_signature, uint16_t *padding)
{
- GNUNET_assert((message) && (buffer) && (length >= sizeof(message->header)));
+ GNUNET_assert((message) && (buffer) && (length >= get_message_kind_size(GNUNET_MESSENGER_KIND_UNKNOWN)));
uint16_t offset = 0;