gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[gnunet] branch master updated: -multiple fixes and correction regarding


From: gnunet
Subject: [gnunet] branch master updated: -multiple fixes and correction regarding messenger service
Date: Sun, 04 Apr 2021 18:01:27 +0200

This is an automated email from the git hooks/post-receive script.

thejackimonster pushed a commit to branch master
in repository gnunet.

The following commit(s) were added to refs/heads/master by this push:
     new ac3aa3cc3 -multiple fixes and correction regarding messenger service
ac3aa3cc3 is described below

commit ac3aa3cc3a617bc54ed8beb2b5a30c0b95483525
Author: TheJackiMonster <thejackimonster@gmail.com>
AuthorDate: Sat Mar 20 13:53:23 2021 +0100

    -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>
---
 src/messenger/Makefile.am                          |   1 +
 src/messenger/gnunet-service-messenger.c           |  59 ++++-
 .../gnunet-service-messenger_member_session.c      |  20 ++
 .../gnunet-service-messenger_member_session.h      |  12 +
 .../gnunet-service-messenger_message_handle.c      |  14 ++
 .../gnunet-service-messenger_message_recv.c        |  71 ++++--
 .../gnunet-service-messenger_message_send.c        |   7 +
 .../gnunet-service-messenger_message_send.h        |  13 +
 .../gnunet-service-messenger_message_state.c       | 109 ++++++++
 .../gnunet-service-messenger_message_state.h       |  63 +++++
 .../gnunet-service-messenger_message_store.c       |   3 +-
 src/messenger/gnunet-service-messenger_room.c      | 277 +++++++++++++--------
 src/messenger/gnunet-service-messenger_room.h      |  73 +++---
 src/messenger/gnunet-service-messenger_tunnel.c    |  30 ++-
 src/messenger/gnunet-service-messenger_tunnel.h    |   3 +-
 src/messenger/messenger_api.c                      |   2 +-
 src/messenger/messenger_api_message.c              |   2 +-
 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;
 
@@ -265,6 +270,35 @@ end_handling:
   GNUNET_SERVICE_client_continue (msg_client->client);
 }
 
+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)
 {
@@ -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;
 };
@@ -139,6 +142,15 @@ is_member_session_closed (const struct 
GNUNET_MESSENGER_MemberSession* session);
 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.
  *
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
@@ -46,6 +46,13 @@ send_message_peer (struct GNUNET_MESSENGER_SrvRoom *room, 
struct GNUNET_MESSENGE
   GNUNET_memcpy(room->peer_message, hash, sizeof(struct GNUNET_HashCode));
 }
 
+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
@@ -60,6 +60,19 @@ void
 send_message_peer (struct GNUNET_MESSENGER_SrvRoom *room, struct 
GNUNET_MESSENGER_SrvHandle *handle,
                    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
     );
@@ -771,6 +823,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)
 {
@@ -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;
 
@@ -125,24 +126,6 @@ get_room_message_store (struct GNUNET_MESSENGER_SrvRoom 
*room);
 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;
 

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]