diff options
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; |