aboutsummaryrefslogtreecommitdiff
path: root/src/service/messenger
diff options
context:
space:
mode:
Diffstat (limited to 'src/service/messenger')
-rw-r--r--src/service/messenger/.gitignore14
-rw-r--r--src/service/messenger/Makefile.am162
-rw-r--r--src/service/messenger/gnunet-service-messenger.c569
-rw-r--r--src/service/messenger/gnunet-service-messenger.h106
-rw-r--r--src/service/messenger/gnunet-service-messenger_basement.c66
-rw-r--r--src/service/messenger/gnunet-service-messenger_basement.h70
-rw-r--r--src/service/messenger/gnunet-service-messenger_handle.c570
-rw-r--r--src/service/messenger/gnunet-service-messenger_handle.h241
-rw-r--r--src/service/messenger/gnunet-service-messenger_list_handles.c117
-rw-r--r--src/service/messenger/gnunet-service-messenger_list_handles.h100
-rw-r--r--src/service/messenger/gnunet-service-messenger_list_messages.c168
-rw-r--r--src/service/messenger/gnunet-service-messenger_list_messages.h111
-rw-r--r--src/service/messenger/gnunet-service-messenger_member.c462
-rw-r--r--src/service/messenger/gnunet-service-messenger_member.h175
-rw-r--r--src/service/messenger/gnunet-service-messenger_member_session.c866
-rw-r--r--src/service/messenger/gnunet-service-messenger_member_session.h296
-rw-r--r--src/service/messenger/gnunet-service-messenger_member_store.c315
-rw-r--r--src/service/messenger/gnunet-service-messenger_member_store.h158
-rw-r--r--src/service/messenger/gnunet-service-messenger_message_handle.c185
-rw-r--r--src/service/messenger/gnunet-service-messenger_message_handle.h151
-rw-r--r--src/service/messenger/gnunet-service-messenger_message_kind.c129
-rw-r--r--src/service/messenger/gnunet-service-messenger_message_kind.h86
-rw-r--r--src/service/messenger/gnunet-service-messenger_message_recv.c246
-rw-r--r--src/service/messenger/gnunet-service-messenger_message_recv.h96
-rw-r--r--src/service/messenger/gnunet-service-messenger_message_send.c220
-rw-r--r--src/service/messenger/gnunet-service-messenger_message_send.h105
-rw-r--r--src/service/messenger/gnunet-service-messenger_message_state.c119
-rw-r--r--src/service/messenger/gnunet-service-messenger_message_state.h66
-rw-r--r--src/service/messenger/gnunet-service-messenger_message_store.c677
-rw-r--r--src/service/messenger/gnunet-service-messenger_message_store.h167
-rw-r--r--src/service/messenger/gnunet-service-messenger_operation.c238
-rw-r--r--src/service/messenger/gnunet-service-messenger_operation.h128
-rw-r--r--src/service/messenger/gnunet-service-messenger_operation_store.c268
-rw-r--r--src/service/messenger/gnunet-service-messenger_operation_store.h129
-rw-r--r--src/service/messenger/gnunet-service-messenger_peer_store.c384
-rw-r--r--src/service/messenger/gnunet-service-messenger_peer_store.h108
-rw-r--r--src/service/messenger/gnunet-service-messenger_room.c1524
-rw-r--r--src/service/messenger/gnunet-service-messenger_room.h404
-rw-r--r--src/service/messenger/gnunet-service-messenger_sender_session.h42
-rw-r--r--src/service/messenger/gnunet-service-messenger_service.c461
-rw-r--r--src/service/messenger/gnunet-service-messenger_service.h205
-rw-r--r--src/service/messenger/gnunet-service-messenger_tunnel.c441
-rw-r--r--src/service/messenger/gnunet-service-messenger_tunnel.h193
-rw-r--r--src/service/messenger/meson.build70
-rw-r--r--src/service/messenger/messenger-testing-cmds.h103
-rw-r--r--src/service/messenger/messenger-testing.c114
-rw-r--r--src/service/messenger/messenger-testing.h102
-rw-r--r--src/service/messenger/messenger.conf.in17
-rw-r--r--src/service/messenger/messenger_api.c1263
-rw-r--r--src/service/messenger/messenger_api_cmd_join_room.c181
-rw-r--r--src/service/messenger/messenger_api_cmd_start_service.c172
-rw-r--r--src/service/messenger/messenger_api_cmd_stop_service.c95
-rw-r--r--src/service/messenger/messenger_api_contact.c129
-rw-r--r--src/service/messenger/messenger_api_contact.h126
-rw-r--r--src/service/messenger/messenger_api_contact_store.c218
-rw-r--r--src/service/messenger/messenger_api_contact_store.h126
-rw-r--r--src/service/messenger/messenger_api_handle.c270
-rw-r--r--src/service/messenger/messenger_api_handle.h190
-rw-r--r--src/service/messenger/messenger_api_list_tunnels.c298
-rw-r--r--src/service/messenger/messenger_api_list_tunnels.h187
-rw-r--r--src/service/messenger/messenger_api_message.c1380
-rw-r--r--src/service/messenger/messenger_api_message.h351
-rw-r--r--src/service/messenger/messenger_api_message_control.c251
-rw-r--r--src/service/messenger/messenger_api_message_control.h105
-rw-r--r--src/service/messenger/messenger_api_message_kind.c209
-rw-r--r--src/service/messenger/messenger_api_message_kind.h138
-rw-r--r--src/service/messenger/messenger_api_queue_messages.c133
-rw-r--r--src/service/messenger/messenger_api_queue_messages.h94
-rw-r--r--src/service/messenger/messenger_api_room.c913
-rw-r--r--src/service/messenger/messenger_api_room.h270
-rw-r--r--src/service/messenger/messenger_api_traits.c29
-rw-r--r--src/service/messenger/messenger_api_util.c129
-rw-r--r--src/service/messenger/messenger_api_util.h95
-rw-r--r--src/service/messenger/test_messenger.c218
-rw-r--r--src/service/messenger/test_messenger_anonymous.c190
-rw-r--r--src/service/messenger/test_messenger_api.conf49
-rw-r--r--src/service/messenger/test_messenger_plugin_cmd_simple_join.c400
-rwxr-xr-xsrc/service/messenger/test_messenger_start_testcase.sh16
78 files changed, 19969 insertions, 0 deletions
diff --git a/src/service/messenger/.gitignore b/src/service/messenger/.gitignore
new file mode 100644
index 000000000..ed78c5562
--- /dev/null
+++ b/src/service/messenger/.gitignore
@@ -0,0 +1,14 @@
1gnunet-service-messenger
2gnunet-messenger
3test_messenger_api
4test_messenger_anonymous
5test_messenger_sync_client
6test_messenger_async_client
7test_messenger_worst_client
8test_messenger_sync_p2p
9test_messenger_async_p2p
10test_messenger_worst_p2p
11test_messenger_server
12test_messenger_growth
13test_messenger_ring
14test_messenger_adapt
diff --git a/src/service/messenger/Makefile.am b/src/service/messenger/Makefile.am
new file mode 100644
index 000000000..876b19985
--- /dev/null
+++ b/src/service/messenger/Makefile.am
@@ -0,0 +1,162 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4if USE_COVERAGE
5 AM_CFLAGS = --coverage -O0
6 XLIB = -lgcov
7endif
8
9pkgcfgdir= $(pkgdatadir)/config.d/
10
11libexecdir= $(pkglibdir)/libexec/
12
13pkgcfg_DATA = \
14 messenger.conf
15
16plugindir = $(libdir)/gnunet
17
18AM_CLFAGS = -g
19
20libexec_PROGRAMS = \
21 gnunet-service-messenger \
22 $(EXP_LIBEXEC)
23
24plugin_LTLIBRARIES = \
25 libgnunet_test_messenger_plugin_cmd_simple_join.la
26
27TESTING_LIBS = \
28 libgnunetmessengertesting.la
29
30lib_LTLIBRARIES = \
31 libgnunetmessenger.la \
32 $(EXP_LIB) \
33 $(TESTING_LIBS)
34
35libgnunetmessenger_la_SOURCES = \
36 messenger_api.c \
37 messenger_api_contact.c messenger_api_contact.h \
38 messenger_api_contact_store.c messenger_api_contact_store.h \
39 messenger_api_message.c messenger_api_message.h \
40 messenger_api_message_control.c messenger_api_message_control.h \
41 messenger_api_message_kind.c messenger_api_message_kind.h \
42 messenger_api_list_tunnels.c messenger_api_list_tunnels.h \
43 messenger_api_queue_messages.c messenger_api_queue_messages.h \
44 messenger_api_util.c messenger_api_util.h \
45 messenger_api_handle.c messenger_api_handle.h \
46 messenger_api_room.c messenger_api_room.h
47libgnunetmessenger_la_LIBADD = \
48 $(top_builddir)/src/lib/util/libgnunetutil.la \
49 $(top_builddir)/src/service/cadet/libgnunetcadet.la \
50 $(top_builddir)/src/service/identity/libgnunetidentity.la \
51 $(XLIB) \
52 $(LTLIBINTL)
53libgnunetmessenger_la_LDFLAGS = \
54 $(GN_LIB_LDFLAGS) \
55 -version-info 0:0:0
56
57libgnunetmessengertesting_la_SOURCES = \
58 messenger_api_cmd_join_room.c \
59 messenger_api_cmd_start_service.c \
60 messenger_api_cmd_stop_service.c \
61 messenger_api_traits.c \
62 messenger-testing.c messenger-testing.h
63libgnunetmessengertesting_la_LIBADD = \
64 libgnunetmessenger.la \
65 $(top_builddir)/src/lib/testing/libgnunettesting.la \
66 $(top_builddir)/src/service/cadet/libgnunetcadet.la \
67 $(top_builddir)/src/service/transport/libgnunettransporttesting2.la \
68 $(top_builddir)/src/service/transport/libgnunettransportapplication.la \
69 $(top_builddir)/src/service/transport/libgnunettransportcore.la \
70 $(top_builddir)/src/service/core/libgnunetcore.la \
71 $(top_builddir)/src/service/peerstore/libgnunetpeerstore.la \
72 $(top_builddir)/src/service/identity/libgnunetidentity.la \
73 $(top_builddir)/src/service/arm/libgnunetarm.la \
74 $(top_builddir)/src/lib/hello/libgnunethello.la \
75 $(top_builddir)/src/lib/util/libgnunetutil.la
76libgnunetmessengertesting_la_LDFLAGS = \
77 $(GN_LIBINTL) \
78 $(GN_LIB_LDFLAGS) \
79 -version-info 0:0:0
80
81libgnunet_test_messenger_plugin_cmd_simple_join_la_SOURCES = \
82 messenger-testing-cmds.h \
83 test_messenger_plugin_cmd_simple_join.c
84libgnunet_test_messenger_plugin_cmd_simple_join_la_LIBADD = \
85 libgnunetmessenger.la \
86 libgnunetmessengertesting.la \
87 $(top_builddir)/src/service/cadet/libgnunetcadet.la \
88 $(top_builddir)/src/service/core/libgnunetcore.la \
89 $(top_builddir)/src/service/core/libgnunetcoretesting.la \
90 $(top_builddir)/src/service/transport/libgnunettransporttesting2.la \
91 $(top_builddir)/src/service/transport/libgnunettransportapplication.la \
92 $(top_builddir)/src/service/transport/libgnunettransportcore.la \
93 $(top_builddir)/src/lib/testing/libgnunettesting.la \
94 $(top_builddir)/src/service/peerstore/libgnunetpeerstore.la \
95 $(top_builddir)/src/service/identity/libgnunetidentity.la \
96 $(top_builddir)/src/service/statistics/libgnunetstatistics.la \
97 $(top_builddir)/src/lib/hello/libgnunethello.la \
98 $(top_builddir)/src/service/arm/libgnunetarm.la \
99 $(top_builddir)/src/lib/util/libgnunetutil.la \
100 $(LTLIBINTL)
101libgnunet_test_messenger_plugin_cmd_simple_join_la_LDFLAGS = \
102 $(GN_PLUGIN_LDFLAGS)
103
104gnunet_service_messenger_SOURCES = \
105 gnunet-service-messenger.c gnunet-service-messenger.h \
106 gnunet-service-messenger_service.c gnunet-service-messenger_service.h \
107 gnunet-service-messenger_list_handles.c gnunet-service-messenger_list_handles.h \
108 gnunet-service-messenger_list_messages.c gnunet-service-messenger_list_messages.h \
109 gnunet-service-messenger_member_session.c gnunet-service-messenger_member_session.h \
110 gnunet-service-messenger_sender_session.h \
111 gnunet-service-messenger_member.c gnunet-service-messenger_member.h \
112 gnunet-service-messenger_member_store.c gnunet-service-messenger_member_store.h \
113 gnunet-service-messenger_message_handle.c gnunet-service-messenger_message_handle.h \
114 gnunet-service-messenger_message_kind.c gnunet-service-messenger_message_kind.h \
115 gnunet-service-messenger_message_recv.c gnunet-service-messenger_message_recv.h \
116 gnunet-service-messenger_message_send.c gnunet-service-messenger_message_send.h \
117 gnunet-service-messenger_message_state.c gnunet-service-messenger_message_state.h \
118 gnunet-service-messenger_message_store.c gnunet-service-messenger_message_store.h \
119 gnunet-service-messenger_operation_store.c gnunet-service-messenger_operation_store.h \
120 gnunet-service-messenger_operation.c gnunet-service-messenger_operation.h \
121 gnunet-service-messenger_peer_store.c gnunet-service-messenger_peer_store.h \
122 gnunet-service-messenger_basement.c gnunet-service-messenger_basement.h \
123 gnunet-service-messenger_handle.c gnunet-service-messenger_handle.h \
124 gnunet-service-messenger_room.c gnunet-service-messenger_room.h \
125 gnunet-service-messenger_tunnel.c gnunet-service-messenger_tunnel.h
126gnunet_service_messenger_LDADD = \
127 libgnunetmessenger.la \
128 $(top_builddir)/src/lib/util/libgnunetutil.la \
129 $(top_builddir)/src/service/cadet/libgnunetcadet.la \
130 $(top_builddir)/src/service/identity/libgnunetidentity.la \
131 $(GN_LIBINTL)
132
133check_PROGRAMS = \
134 test_messenger_api \
135 test_messenger_anonymous
136
137#check_SCRIPTS= \
138# test_messenger_start_testcase.sh
139
140if ENABLE_TEST_RUN
141AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
142TESTS = $(check_PROGRAMS) \
143 $(check_SCRIPTS)
144endif
145
146test_messenger_api_SOURCES = \
147 test_messenger.c
148test_messenger_api_LDADD = \
149 libgnunetmessenger.la \
150 $(top_builddir)/src/lib/testing/libgnunettesting.la \
151 $(top_builddir)/src/lib/util/libgnunetutil.la
152
153test_messenger_anonymous_SOURCES = \
154 test_messenger_anonymous.c
155test_messenger_anonymous_LDADD = \
156 libgnunetmessenger.la \
157 $(top_builddir)/src/lib/testing/libgnunettesting.la \
158 $(top_builddir)/src/lib/util/libgnunetutil.la
159
160EXTRA_DIST = \
161 test_messenger_start_testcase.sh \
162 test_messenger_api.conf
diff --git a/src/service/messenger/gnunet-service-messenger.c b/src/service/messenger/gnunet-service-messenger.c
new file mode 100644
index 000000000..06f9384aa
--- /dev/null
+++ b/src/service/messenger/gnunet-service-messenger.c
@@ -0,0 +1,569 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger.c
23 * @brief GNUnet MESSENGER service
24 */
25
26#include "gnunet-service-messenger.h"
27
28#include "gnunet-service-messenger_handle.h"
29#include "gnunet-service-messenger_room.h"
30#include "gnunet-service-messenger_service.h"
31#include "gnunet_common.h"
32#include "messenger_api_message.h"
33
34struct GNUNET_MESSENGER_Client
35{
36 struct GNUNET_SERVICE_Client *client;
37 struct GNUNET_MESSENGER_SrvHandle *handle;
38};
39
40struct GNUNET_MESSENGER_Service *messenger;
41
42static void
43handle_create (void *cls,
44 const struct GNUNET_MESSENGER_CreateMessage *msg)
45{
46 struct GNUNET_MESSENGER_Client *msg_client = cls;
47
48 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Handle created\n");
49
50 GNUNET_SERVICE_client_continue (msg_client->client);
51}
52
53
54static void
55handle_destroy (void *cls,
56 const struct GNUNET_MESSENGER_DestroyMessage *msg)
57{
58 struct GNUNET_MESSENGER_Client *msg_client = cls;
59
60 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Handle destroyed\n");
61
62 GNUNET_SERVICE_client_drop (msg_client->client);
63}
64
65
66static enum GNUNET_GenericReturnValue
67check_room_initial_key (const struct GNUNET_MESSENGER_RoomMessage *msg)
68{
69 const uint16_t full_length = ntohs (msg->header.size);
70
71 if (full_length < sizeof(*msg))
72 return GNUNET_NO;
73
74 const uint16_t msg_length = full_length - sizeof(*msg);
75 const char *msg_buffer = ((const char*) msg) + sizeof(*msg);
76
77 if (0 == msg_length)
78 return GNUNET_OK;
79
80 struct GNUNET_CRYPTO_PublicKey key;
81 size_t key_len;
82
83 if (GNUNET_OK != GNUNET_CRYPTO_read_public_key_from_buffer (msg_buffer,
84 msg_length,
85 &key, &key_len))
86 return GNUNET_NO;
87
88 return key_len == msg_length ? GNUNET_OK : GNUNET_NO;
89}
90
91
92static void
93initialize_handle_via_key (struct GNUNET_MESSENGER_SrvHandle *handle,
94 const struct GNUNET_MESSENGER_RoomMessage *msg)
95{
96 GNUNET_assert (handle);
97
98 const uint16_t full_length = ntohs (msg->header.size);
99 const uint16_t msg_length = full_length - sizeof(*msg);
100 const char *msg_buffer = ((const char*) msg) + sizeof(*msg);
101
102 if (msg_length > 0)
103 {
104 struct GNUNET_CRYPTO_PublicKey key;
105 size_t key_len;
106
107 if (GNUNET_OK == GNUNET_CRYPTO_read_public_key_from_buffer (msg_buffer,
108 msg_length,
109 &key,
110 &key_len))
111 set_srv_handle_key (handle, &key);
112 else
113 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
114 "Initialization failed while reading invalid key!\n");
115 }
116 else
117 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Initialization is missing key!\n");
118}
119
120
121static enum GNUNET_GenericReturnValue
122check_room_open (void *cls,
123 const struct GNUNET_MESSENGER_RoomMessage *msg)
124{
125 return check_room_initial_key (msg);
126}
127
128
129static void
130handle_room_open (void *cls,
131 const struct GNUNET_MESSENGER_RoomMessage *msg)
132{
133 struct GNUNET_MESSENGER_Client *msg_client = cls;
134
135 initialize_handle_via_key (msg_client->handle, msg);
136
137 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Opening room: %s\n", GNUNET_h2s (
138 &(msg->key)));
139
140 if (GNUNET_YES == open_srv_handle_room (msg_client->handle, &(msg->key)))
141 {
142 struct GNUNET_HashCode prev;
143 sync_srv_handle_messages (msg_client->handle, &(msg->key), &(msg->previous),
144 &prev);
145
146 const struct GNUNET_ShortHashCode *member_id = get_srv_handle_member_id (
147 msg_client->handle, &(msg->key));
148
149 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Opening room with member id: %s\n",
150 GNUNET_sh2s (member_id));
151
152 struct GNUNET_MESSENGER_RoomMessage *response;
153 struct GNUNET_MQ_Envelope *env;
154
155 env = GNUNET_MQ_msg (response, GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_OPEN);
156 GNUNET_memcpy (&(response->key), &(msg->key), sizeof(response->key));
157 GNUNET_memcpy (&(response->previous), &prev, sizeof(response->previous));
158 GNUNET_MQ_send (msg_client->handle->mq, env);
159 }
160 else
161 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Opening room failed: %s\n",
162 GNUNET_h2s (&(msg->key)));
163
164 GNUNET_SERVICE_client_continue (msg_client->client);
165}
166
167
168static enum GNUNET_GenericReturnValue
169check_room_entry (void *cls,
170 const struct GNUNET_MESSENGER_RoomMessage *msg)
171{
172 return check_room_initial_key (msg);
173}
174
175
176static void
177handle_room_entry (void *cls,
178 const struct GNUNET_MESSENGER_RoomMessage *msg)
179{
180 struct GNUNET_MESSENGER_Client *msg_client = cls;
181
182 initialize_handle_via_key (msg_client->handle, msg);
183
184 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Entering room: %s, %s\n", GNUNET_h2s (
185 &(msg->key)), GNUNET_i2s (&(msg->door)));
186
187 if (GNUNET_YES == entry_srv_handle_room (msg_client->handle, &(msg->door),
188 &(msg->key)))
189 {
190 struct GNUNET_HashCode prev;
191 sync_srv_handle_messages (msg_client->handle, &(msg->key), &(msg->previous),
192 &prev);
193
194 const struct GNUNET_ShortHashCode *member_id = get_srv_handle_member_id (
195 msg_client->handle, &(msg->key));
196
197 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Entering room with member id: %s\n",
198 GNUNET_sh2s (member_id));
199
200 struct GNUNET_MESSENGER_RoomMessage *response;
201 struct GNUNET_MQ_Envelope *env;
202
203 env = GNUNET_MQ_msg (response, GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_ENTRY);
204 GNUNET_memcpy (&(response->door), &(msg->door), sizeof(response->door));
205 GNUNET_memcpy (&(response->key), &(msg->key), sizeof(response->key));
206 GNUNET_memcpy (&(response->previous), &prev, sizeof(response->previous));
207 GNUNET_MQ_send (msg_client->handle->mq, env);
208 }
209 else
210 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Entrance into room failed: %s, %s\n",
211 GNUNET_h2s (&(msg->key)),
212 GNUNET_i2s (&(msg->door)));
213
214 GNUNET_SERVICE_client_continue (msg_client->client);
215}
216
217
218static void
219handle_room_close (void *cls,
220 const struct GNUNET_MESSENGER_RoomMessage *msg)
221{
222 struct GNUNET_MESSENGER_Client *msg_client = cls;
223
224 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Closing room: %s\n", GNUNET_h2s (
225 &(msg->key)));
226
227 if (GNUNET_YES == close_srv_handle_room (msg_client->handle, &(msg->key)))
228 {
229 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Closing room succeeded: %s\n",
230 GNUNET_h2s (&(msg->key)));
231
232 struct GNUNET_MESSENGER_RoomMessage *response;
233 struct GNUNET_MQ_Envelope *env;
234
235 env = GNUNET_MQ_msg (response, GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_CLOSE);
236 GNUNET_memcpy (&(response->key), &(msg->key), sizeof(response->key));
237 GNUNET_memcpy (&(response->previous), &(msg->previous),
238 sizeof(response->previous));
239 GNUNET_MQ_send (msg_client->handle->mq, env);
240 }
241 else
242 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Closing room failed: %s\n",
243 GNUNET_h2s (&(msg->key)));
244
245 GNUNET_SERVICE_client_continue (msg_client->client);
246}
247
248
249static void
250handle_room_sync (void *cls,
251 const struct GNUNET_MESSENGER_RoomMessage *msg)
252{
253 struct GNUNET_MESSENGER_Client *msg_client = cls;
254
255 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Syncing room: %s\n", GNUNET_h2s (
256 &(msg->key)));
257
258 struct GNUNET_HashCode prev;
259 sync_srv_handle_messages (msg_client->handle, &(msg->key), &(msg->previous),
260 &prev);
261
262 struct GNUNET_MESSENGER_RoomMessage *response;
263 struct GNUNET_MQ_Envelope *env;
264
265 env = GNUNET_MQ_msg (response, GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_SYNC);
266 GNUNET_memcpy (&(response->key), &(msg->key), sizeof(response->key));
267 GNUNET_memcpy (&(response->previous), &prev, sizeof(response->previous));
268 GNUNET_MQ_send (msg_client->handle->mq, env);
269
270 GNUNET_SERVICE_client_continue (msg_client->client);
271}
272
273
274static enum GNUNET_GenericReturnValue
275check_send_message (void *cls,
276 const struct GNUNET_MESSENGER_SendMessage *msg)
277{
278 const uint16_t full_length = ntohs (msg->header.size);
279
280 if (full_length < sizeof(*msg))
281 return GNUNET_NO;
282
283 const uint16_t msg_length = full_length - sizeof(*msg);
284 const char *msg_buffer = ((const char*) msg) + sizeof(*msg);
285
286 struct GNUNET_MESSENGER_Message message;
287
288 if (msg_length < get_message_kind_size (GNUNET_MESSENGER_KIND_UNKNOWN,
289 GNUNET_YES))
290 {
291 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Too short message: %s\n", GNUNET_h2s (
292 &(msg->key)));
293 return GNUNET_NO;
294 }
295
296 if (GNUNET_YES != decode_message (&message, msg_length, msg_buffer,
297 GNUNET_YES,
298 NULL))
299 {
300 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Decoding message failed: %s\n",
301 GNUNET_h2s (
302 &(msg->key)));
303 return GNUNET_NO;
304 }
305
306 enum GNUNET_GenericReturnValue allowed;
307 allowed = filter_message_sending (&message);
308
309 if (GNUNET_SYSERR == allowed)
310 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
311 "Sending message not allowed: %s to %s\n",
312 GNUNET_MESSENGER_name_of_kind (message.header.kind),
313 GNUNET_h2s (&(msg->key)));
314
315 cleanup_message (&message);
316 return GNUNET_SYSERR != allowed? GNUNET_OK : GNUNET_NO;
317}
318
319
320static void
321handle_send_message (void *cls,
322 const struct GNUNET_MESSENGER_SendMessage *msg)
323{
324 struct GNUNET_MESSENGER_Client *msg_client = cls;
325
326 const struct GNUNET_HashCode *key = &(msg->key);
327 const char *msg_buffer = ((const char*) msg) + sizeof(*msg);
328 const uint16_t msg_length = ntohs (msg->header.size) - sizeof(*msg);
329
330 struct GNUNET_MESSENGER_Message message;
331 decode_message (&message, msg_length, msg_buffer, GNUNET_YES, NULL);
332
333 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending message: %s to %s (by %s)\n",
334 GNUNET_MESSENGER_name_of_kind (message.header.kind),
335 GNUNET_h2s (key),
336 GNUNET_sh2s (&(message.header.sender_id)));
337
338 if (GNUNET_YES != send_srv_handle_message (msg_client->handle, key, &message))
339 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Sending message failed: %s to %s\n",
340 GNUNET_MESSENGER_name_of_kind (message.header.kind),
341 GNUNET_h2s (key));
342
343 cleanup_message (&message);
344
345 GNUNET_SERVICE_client_continue (msg_client->client);
346}
347
348
349static void
350callback_found_message (void *cls,
351 struct GNUNET_MESSENGER_SrvRoom *room,
352 const struct GNUNET_MESSENGER_Message *message,
353 const struct GNUNET_HashCode *hash)
354{
355 struct GNUNET_MESSENGER_Client *msg_client = cls;
356
357 if (! message)
358 {
359 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
360 "Notifying client about missing message: %s\n",
361 GNUNET_h2s (hash));
362
363 struct GNUNET_MESSENGER_GetMessage *response;
364 struct GNUNET_MQ_Envelope *env;
365
366 env = GNUNET_MQ_msg (response,
367 GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_GET_MESSAGE);
368 GNUNET_memcpy (&(response->key), &(room->key), sizeof(room->key));
369 GNUNET_memcpy (&(response->hash), hash, sizeof(*hash));
370 GNUNET_MQ_send (msg_client->handle->mq, env);
371 return;
372 }
373
374 struct GNUNET_MESSENGER_SenderSession session;
375
376 if (GNUNET_YES == is_peer_message (message))
377 {
378 struct GNUNET_MESSENGER_PeerStore *store = get_srv_room_peer_store (room);
379
380 session.peer = get_store_peer_of (store, message, hash);
381
382 if (! session.peer)
383 {
384 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
385 "Peer session from sender of message (%s) unknown!\n",
386 GNUNET_h2s (hash));
387 return;
388 }
389 }
390 else
391 {
392 struct GNUNET_MESSENGER_MemberStore *store = get_srv_room_member_store (
393 room);
394 struct GNUNET_MESSENGER_Member *member = get_store_member_of (store,
395 message);
396
397 if (! member)
398 {
399 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Sender of message (%s) unknown!\n",
400 GNUNET_h2s (hash));
401 return;
402 }
403
404 session.member = get_member_session_of (member, message, hash);
405
406 if (! session.member)
407 {
408 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
409 "Member session from sender of message (%s) unknown!\n",
410 GNUNET_h2s (hash));
411 return;
412 }
413 }
414
415 notify_srv_handle_message (msg_client->handle, room, &session, message,
416 hash, GNUNET_NO);
417}
418
419
420static void
421handle_get_message (void *cls,
422 const struct GNUNET_MESSENGER_GetMessage *msg)
423{
424 struct GNUNET_MESSENGER_Client *msg_client = cls;
425
426 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Requesting message from room: %s\n",
427 GNUNET_h2s (&(msg->key)));
428 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Requested message: %s\n",
429 GNUNET_h2s (&(msg->hash)));
430
431 struct GNUNET_MESSENGER_SrvRoom *room = get_service_room (messenger,
432 &(msg->key));
433
434 if (! room)
435 {
436 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Room not found: %s\n", GNUNET_h2s (
437 &(msg->key)));
438 goto end_handling;
439 }
440
441 struct GNUNET_MESSENGER_MemberStore *member_store =
442 get_srv_room_member_store (room);
443
444 const struct GNUNET_ShortHashCode *member_id;
445 member_id = get_srv_handle_member_id (msg_client->handle,
446 &(msg->key));
447
448 struct GNUNET_MESSENGER_Member *member = get_store_member (member_store,
449 member_id);
450
451 if (! member)
452 {
453 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
454 "Member not valid to request a message! (%s)\n",
455 GNUNET_sh2s (member_id));
456 goto end_handling;
457 }
458
459 const struct GNUNET_CRYPTO_PublicKey *pubkey = get_srv_handle_key (
460 msg_client->handle);
461
462 if (! pubkey)
463 {
464 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
465 "Handle needs to have a public key to request a message! (%s)\n",
466 GNUNET_sh2s (member_id));
467 goto end_handling;
468 }
469
470 struct GNUNET_MESSENGER_MemberSession *session = get_member_session (member,
471 pubkey);
472
473 if (! session)
474 {
475 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
476 "Session not valid to request a message! (%s)\n",
477 GNUNET_sh2s (member_id));
478 goto end_handling;
479 }
480
481 request_srv_room_message (room, &(msg->hash), session, callback_found_message,
482 msg_client);
483
484end_handling:
485 GNUNET_SERVICE_client_continue (msg_client->client);
486}
487
488
489static void*
490callback_client_connect (void *cls,
491 struct GNUNET_SERVICE_Client *client,
492 struct GNUNET_MQ_Handle *mq)
493{
494 struct GNUNET_MESSENGER_Client *msg_client = GNUNET_new (struct
495 GNUNET_MESSENGER_Client);
496
497 msg_client->client = client;
498 msg_client->handle = add_service_handle (messenger, mq);
499
500 return msg_client;
501}
502
503
504static void
505callback_client_disconnect (void *cls,
506 struct GNUNET_SERVICE_Client *client,
507 void *internal_cls)
508{
509 struct GNUNET_MESSENGER_Client *msg_client = internal_cls;
510
511 remove_service_handle (messenger, msg_client->handle);
512
513 GNUNET_free (msg_client);
514}
515
516
517/**
518 * Setup MESSENGER internals.
519 *
520 * @param[in/out] cls closure
521 * @param[in] config configuration to use
522 * @param[in/out] service the initialized service
523 */
524static void
525run (void *cls,
526 const struct GNUNET_CONFIGURATION_Handle *config,
527 struct GNUNET_SERVICE_Handle *service)
528{
529 messenger = create_service (config, service);
530
531 if (! messenger)
532 GNUNET_SCHEDULER_shutdown ();
533}
534
535
536/**
537 * Define "main" method using service macro.
538 */
539GNUNET_SERVICE_MAIN (
540 GNUNET_MESSENGER_SERVICE_NAME,
541 GNUNET_SERVICE_OPTION_NONE,
542 &run,
543 &callback_client_connect,
544 &callback_client_disconnect,
545 NULL,
546 GNUNET_MQ_hd_fixed_size (create,
547 GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_CREATE,
548 struct
549 GNUNET_MESSENGER_CreateMessage, NULL),
550 GNUNET_MQ_hd_fixed_size (destroy,
551 GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_DESTROY,
552 struct
553 GNUNET_MESSENGER_DestroyMessage, NULL),
554 GNUNET_MQ_hd_var_size (room_open, GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_OPEN,
555 struct GNUNET_MESSENGER_RoomMessage, NULL),
556 GNUNET_MQ_hd_var_size (room_entry, GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_ENTRY,
557 struct GNUNET_MESSENGER_RoomMessage, NULL),
558 GNUNET_MQ_hd_fixed_size (room_close, GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_CLOSE,
559 struct GNUNET_MESSENGER_RoomMessage, NULL),
560 GNUNET_MQ_hd_var_size (send_message,
561 GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_SEND_MESSAGE, struct
562 GNUNET_MESSENGER_SendMessage, NULL),
563 GNUNET_MQ_hd_fixed_size (get_message,
564 GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_GET_MESSAGE,
565 struct
566 GNUNET_MESSENGER_GetMessage, NULL),
567 GNUNET_MQ_hd_fixed_size (room_sync, GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_SYNC,
568 struct GNUNET_MESSENGER_RoomMessage, NULL),
569 GNUNET_MQ_handler_end ());
diff --git a/src/service/messenger/gnunet-service-messenger.h b/src/service/messenger/gnunet-service-messenger.h
new file mode 100644
index 000000000..5d96cc345
--- /dev/null
+++ b/src/service/messenger/gnunet-service-messenger.h
@@ -0,0 +1,106 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger.h
23 * @brief GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_SERVICE_MESSENGER_H
27#define GNUNET_SERVICE_MESSENGER_H
28
29#include "gnunet_util_lib.h"
30
31/**
32 * Message to create a handle for a client
33 */
34struct GNUNET_MESSENGER_CreateMessage
35{
36 struct GNUNET_MessageHeader header;
37};
38
39/**
40 * Message to destroy the handle for a client
41 */
42struct GNUNET_MESSENGER_DestroyMessage
43{
44 struct GNUNET_MessageHeader header;
45};
46
47/**
48 * General message to confirm interaction with a room
49 */
50struct GNUNET_MESSENGER_RoomMessage
51{
52 struct GNUNET_MessageHeader header;
53
54 struct GNUNET_PeerIdentity door;
55 struct GNUNET_HashCode key;
56 struct GNUNET_HashCode previous;
57};
58
59/**
60 * Message to receive the current member id of a handle in room
61 */
62struct GNUNET_MESSENGER_MemberMessage
63{
64 struct GNUNET_MessageHeader header;
65
66 struct GNUNET_HashCode key;
67 struct GNUNET_ShortHashCode id;
68 uint32_t reset;
69};
70
71/**
72 * Message to send something into a room
73 */
74struct GNUNET_MESSENGER_SendMessage
75{
76 struct GNUNET_MessageHeader header;
77
78 struct GNUNET_HashCode key;
79};
80
81/**
82 * Message to request something from a room
83 */
84struct GNUNET_MESSENGER_GetMessage
85{
86 struct GNUNET_MessageHeader header;
87
88 struct GNUNET_HashCode key;
89 struct GNUNET_HashCode hash;
90};
91
92/**
93 * Message to receive something from a room
94 */
95struct GNUNET_MESSENGER_RecvMessage
96{
97 struct GNUNET_MessageHeader header;
98
99 struct GNUNET_HashCode key;
100 struct GNUNET_HashCode sender;
101 struct GNUNET_HashCode context;
102 struct GNUNET_HashCode hash;
103 uint32_t flags;
104};
105
106#endif //GNUNET_SERVICE_MESSENGER_H
diff --git a/src/service/messenger/gnunet-service-messenger_basement.c b/src/service/messenger/gnunet-service-messenger_basement.c
new file mode 100644
index 000000000..5d1d475e9
--- /dev/null
+++ b/src/service/messenger/gnunet-service-messenger_basement.c
@@ -0,0 +1,66 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2023 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_basement.c
23 * @brief GNUnet MESSENGER service
24 */
25
26#include "gnunet-service-messenger_basement.h"
27
28size_t
29count_of_tunnels (const struct GNUNET_MESSENGER_ListTunnels *tunnels)
30{
31 GNUNET_assert (tunnels);
32
33 const struct GNUNET_MESSENGER_ListTunnel *element;
34 size_t count = 0;
35
36 for (element = tunnels->head; element; element = element->next)
37 count++;
38
39 return count;
40}
41
42
43enum GNUNET_GenericReturnValue
44should_connect_tunnel_to (size_t count,
45 size_t src,
46 size_t dst)
47{
48 if ((src + 1) % count == dst % count)
49 return GNUNET_YES;
50
51 return GNUNET_NO;
52}
53
54
55enum GNUNET_GenericReturnValue
56required_connection_between (size_t count,
57 size_t src,
58 size_t dst)
59{
60 if (GNUNET_YES == should_connect_tunnel_to (count, src, dst))
61 return GNUNET_YES;
62 if (GNUNET_YES == should_connect_tunnel_to (count, dst, src))
63 return GNUNET_YES;
64
65 return GNUNET_NO;
66}
diff --git a/src/service/messenger/gnunet-service-messenger_basement.h b/src/service/messenger/gnunet-service-messenger_basement.h
new file mode 100644
index 000000000..988ff9d1a
--- /dev/null
+++ b/src/service/messenger/gnunet-service-messenger_basement.h
@@ -0,0 +1,70 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2023 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_basement.h
23 * @brief GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_SERVICE_MESSENGER_BASEMENT_H
27#define GNUNET_SERVICE_MESSENGER_BASEMENT_H
28
29#include "messenger_api_list_tunnels.h"
30
31/**
32 * Returns the count of peers in a list (typically from the basement of a room).
33 *
34 * @param[in] tunnels List of peer identities
35 * @return Count of the entries in the list
36 */
37size_t
38count_of_tunnels (const struct GNUNET_MESSENGER_ListTunnels *tunnels);
39
40/**
41 * Returns #GNUNET_YES or #GNUNET_NO to determine if the peer at index <i>src</i> should
42 * or should not connect outgoing to the peer at index <i>dst</i> to construct a complete
43 * basement with a given <i>count</i> of peers.
44 *
45 * @param[in] count Count of peers
46 * @param[in] src Source index
47 * @param[in] dst Destination index
48 * @return #GNUNET_YES or #GNUNET_NO based on topologic requirement
49 */
50enum GNUNET_GenericReturnValue
51should_connect_tunnel_to (size_t count,
52 size_t src,
53 size_t dst);
54
55/**
56 * Returns #GNUNET_YES or #GNUNET_NO to determine if the peers of index <i>src</i> and
57 * index <i>dst</i> should be connected in any direction to construct a complete
58 * basement with a given <i>count</i> of peers.
59 *
60 * @param[in] count Count of peers
61 * @param[in] src Source index
62 * @param[in] dst Destination index
63 * @return #GNUNET_YES or #GNUNET_NO based on topologic requirement
64 */
65enum GNUNET_GenericReturnValue
66required_connection_between (size_t count,
67 size_t src,
68 size_t dst);
69
70#endif //GNUNET_SERVICE_MESSENGER_BASEMENT_H
diff --git a/src/service/messenger/gnunet-service-messenger_handle.c b/src/service/messenger/gnunet-service-messenger_handle.c
new file mode 100644
index 000000000..ca9dcfb15
--- /dev/null
+++ b/src/service/messenger/gnunet-service-messenger_handle.c
@@ -0,0 +1,570 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_handle.c
23 * @brief GNUnet MESSENGER service
24 */
25
26#include "platform.h"
27#include "gnunet_messenger_service.h"
28
29#include "gnunet-service-messenger.h"
30#include "gnunet-service-messenger_handle.h"
31#include "gnunet-service-messenger_room.h"
32
33#include "messenger_api_util.h"
34
35struct GNUNET_MESSENGER_NextMemberId
36{
37 struct GNUNET_ShortHashCode id;
38 enum GNUNET_GenericReturnValue reset;
39};
40
41struct GNUNET_MESSENGER_SrvHandle*
42create_srv_handle (struct GNUNET_MESSENGER_Service *service,
43 struct GNUNET_MQ_Handle *mq)
44{
45 GNUNET_assert ((service) && (mq));
46
47 struct GNUNET_MESSENGER_SrvHandle *handle = GNUNET_new (struct
48 GNUNET_MESSENGER_SrvHandle);
49
50 handle->service = service;
51 handle->mq = mq;
52
53 handle->member_ids = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
54 handle->next_ids = GNUNET_CONTAINER_multihashmap_create (4, GNUNET_NO);
55 handle->routing = GNUNET_CONTAINER_multihashmap_create (4, GNUNET_NO);
56
57 handle->notify = NULL;
58
59 return handle;
60}
61
62
63static enum GNUNET_GenericReturnValue
64iterate_close_rooms (void *cls,
65 const struct GNUNET_HashCode *key,
66 void *value)
67{
68 struct GNUNET_MESSENGER_SrvHandle *handle = cls;
69 close_service_room (handle->service, handle, key, GNUNET_NO);
70 return GNUNET_YES;
71}
72
73
74static enum GNUNET_GenericReturnValue
75iterate_free_values (void *cls,
76 const struct GNUNET_HashCode *key,
77 void *value)
78{
79 GNUNET_free (value);
80 return GNUNET_YES;
81}
82
83
84void
85destroy_srv_handle (struct GNUNET_MESSENGER_SrvHandle *handle)
86{
87 GNUNET_assert (handle);
88
89 GNUNET_CONTAINER_multihashmap_iterate (handle->routing,
90 iterate_close_rooms, handle);
91
92 if (handle->notify)
93 GNUNET_SCHEDULER_cancel (handle->notify);
94
95 GNUNET_CONTAINER_multihashmap_iterate (handle->next_ids,
96 iterate_free_values, NULL);
97 GNUNET_CONTAINER_multihashmap_iterate (handle->member_ids,
98 iterate_free_values, NULL);
99
100 GNUNET_CONTAINER_multihashmap_destroy (handle->next_ids);
101 GNUNET_CONTAINER_multihashmap_destroy (handle->member_ids);
102 GNUNET_CONTAINER_multihashmap_destroy (handle->routing);
103
104 GNUNET_free (handle);
105}
106
107
108void
109set_srv_handle_key (struct GNUNET_MESSENGER_SrvHandle *handle,
110 const struct GNUNET_CRYPTO_PublicKey *key)
111{
112 GNUNET_assert (handle);
113
114 if ((handle->key) && (! key))
115 {
116 GNUNET_free (handle->key);
117 handle->key = NULL;
118 }
119 else if (! handle->key)
120 handle->key = GNUNET_new (struct GNUNET_CRYPTO_PublicKey);
121
122 if (key)
123 memcpy (handle->key, key, sizeof(struct GNUNET_CRYPTO_PublicKey));
124}
125
126
127const struct GNUNET_CRYPTO_PublicKey*
128get_srv_handle_key (const struct GNUNET_MESSENGER_SrvHandle *handle)
129{
130 GNUNET_assert (handle);
131
132 return handle->key;
133}
134
135
136void
137get_srv_handle_data_subdir (const struct GNUNET_MESSENGER_SrvHandle *handle,
138 const char *name,
139 char **dir)
140{
141 GNUNET_assert ((handle) && (dir));
142
143 if (name)
144 GNUNET_asprintf (dir, "%s%s%c%s%c", handle->service->dir, "identities",
145 DIR_SEPARATOR, name, DIR_SEPARATOR);
146 else
147 GNUNET_asprintf (dir, "%s%s%c", handle->service->dir, "anonymous",
148 DIR_SEPARATOR);
149}
150
151
152static enum GNUNET_GenericReturnValue
153create_handle_member_id (const struct GNUNET_MESSENGER_SrvHandle *handle,
154 const struct GNUNET_HashCode *key)
155{
156 GNUNET_assert ((handle) && (key));
157
158 struct GNUNET_ShortHashCode *random_id = GNUNET_new (struct
159 GNUNET_ShortHashCode);
160
161 if (! random_id)
162 return GNUNET_NO;
163
164 generate_free_member_id (random_id, NULL);
165
166 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (handle->member_ids, key,
167 random_id,
168 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
169 {
170 GNUNET_free (random_id);
171 return GNUNET_NO;
172 }
173
174 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
175 "Created a new member id (%s) for room: %s\n", GNUNET_sh2s (
176 random_id),
177 GNUNET_h2s (key));
178
179 return GNUNET_YES;
180}
181
182
183const struct GNUNET_ShortHashCode*
184get_srv_handle_member_id (const struct GNUNET_MESSENGER_SrvHandle *handle,
185 const struct GNUNET_HashCode *key)
186{
187 GNUNET_assert ((handle) && (key));
188
189 return GNUNET_CONTAINER_multihashmap_get (handle->member_ids, key);
190}
191
192
193enum GNUNET_GenericReturnValue
194change_srv_handle_member_id (struct GNUNET_MESSENGER_SrvHandle *handle,
195 const struct GNUNET_HashCode *key,
196 const struct GNUNET_ShortHashCode *unique_id)
197{
198 GNUNET_assert ((handle) && (key) && (unique_id));
199
200 struct GNUNET_ShortHashCode *member_id = GNUNET_CONTAINER_multihashmap_get (
201 handle->member_ids, key);
202
203 if (! member_id)
204 {
205 member_id = GNUNET_new (struct GNUNET_ShortHashCode);
206 GNUNET_memcpy (member_id, unique_id, sizeof(*member_id));
207
208 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (handle->member_ids, key,
209 member_id,
210 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
211 {
212 GNUNET_free (member_id);
213 return GNUNET_SYSERR;
214 }
215 }
216
217 if (0 == GNUNET_memcmp (unique_id, member_id))
218 return GNUNET_OK;
219
220 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
221 "Change a member id (%s) for room (%s).\n", GNUNET_sh2s (
222 member_id),
223 GNUNET_h2s (key));
224
225 GNUNET_memcpy (member_id, unique_id, sizeof(*unique_id));
226
227 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Member id changed to (%s).\n",
228 GNUNET_sh2s (unique_id));
229 return GNUNET_OK;
230}
231
232
233enum GNUNET_GenericReturnValue
234open_srv_handle_room (struct GNUNET_MESSENGER_SrvHandle *handle,
235 const struct GNUNET_HashCode *key)
236{
237 GNUNET_assert ((handle) && (key));
238
239 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (handle->routing,
240 key,
241 NULL,
242 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE))
243
244 return GNUNET_NO;
245
246 if ((! get_srv_handle_member_id (handle, key)) &&
247 (GNUNET_YES != create_handle_member_id (handle,
248 key)))
249 return GNUNET_NO;
250
251 return open_service_room (handle->service, handle, key);
252}
253
254
255enum GNUNET_GenericReturnValue
256entry_srv_handle_room (struct GNUNET_MESSENGER_SrvHandle *handle,
257 const struct GNUNET_PeerIdentity *door,
258 const struct GNUNET_HashCode *key)
259{
260 GNUNET_assert ((handle) && (door) && (key));
261
262 if ((! get_srv_handle_member_id (handle, key)) && (GNUNET_YES !=
263 create_handle_member_id (
264 handle, key)))
265 return GNUNET_NO;
266
267 return entry_service_room (handle->service, handle, door, key);
268}
269
270
271enum GNUNET_GenericReturnValue
272close_srv_handle_room (struct GNUNET_MESSENGER_SrvHandle *handle,
273 const struct GNUNET_HashCode *key)
274{
275 GNUNET_assert ((handle) && (key));
276
277 GNUNET_CONTAINER_multihashmap_get_multiple (handle->next_ids, key,
278 iterate_free_values, NULL);
279 GNUNET_CONTAINER_multihashmap_remove_all (handle->next_ids, key);
280
281 if ((handle->notify) && (0 == GNUNET_CONTAINER_multihashmap_size (
282 handle->next_ids)))
283 {
284 GNUNET_SCHEDULER_cancel (handle->notify);
285 handle->notify = NULL;
286 }
287
288 if (! get_srv_handle_member_id (handle, key))
289 return GNUNET_NO;
290
291 enum GNUNET_GenericReturnValue result;
292 result = close_service_room (handle->service, handle, key, GNUNET_YES);
293
294 if (GNUNET_YES != result)
295 return result;
296
297 GNUNET_CONTAINER_multihashmap_remove_all (handle->routing, key);
298 return result;
299}
300
301
302enum GNUNET_GenericReturnValue
303is_srv_handle_routing (const struct GNUNET_MESSENGER_SrvHandle *handle,
304 const struct GNUNET_HashCode *key)
305{
306 GNUNET_assert ((handle) && (key));
307
308 return GNUNET_CONTAINER_multihashmap_contains (handle->routing, key);
309}
310
311
312void
313sync_srv_handle_messages (struct GNUNET_MESSENGER_SrvHandle *handle,
314 const struct GNUNET_HashCode *key,
315 const struct GNUNET_HashCode *prev,
316 struct GNUNET_HashCode *hash)
317{
318 GNUNET_assert ((handle) && (key) && (prev) && (hash));
319
320 struct GNUNET_MESSENGER_SrvRoom *room = get_service_room (handle->service,
321 key);
322
323 if ((! room) || (! get_srv_handle_member_id (handle, key)))
324 {
325 GNUNET_memcpy (hash, prev, sizeof(*hash));
326 return;
327 }
328
329 merge_srv_room_last_messages (room, handle);
330 get_message_state_chain_hash (&(room->state), hash);
331}
332
333
334enum GNUNET_GenericReturnValue
335send_srv_handle_message (struct GNUNET_MESSENGER_SrvHandle *handle,
336 const struct GNUNET_HashCode *key,
337 const struct GNUNET_MESSENGER_Message *message)
338{
339 GNUNET_assert ((handle) && (key) && (message));
340
341 const struct GNUNET_ShortHashCode *id = get_srv_handle_member_id (handle,
342 key);
343
344 if (! id)
345 {
346 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
347 "It is required to be a member of a room to send messages!\n");
348 return GNUNET_NO;
349 }
350
351 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending message with member id: %s\n",
352 GNUNET_sh2s (id));
353
354 if (0 != GNUNET_memcmp (id, &(message->header.sender_id)))
355 {
356 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
357 "Member id does not match with handle!\n");
358 return GNUNET_NO;
359 }
360
361 struct GNUNET_MESSENGER_SrvRoom *room = get_service_room (handle->service,
362 key);
363
364 if (! room)
365 {
366 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "The room (%s) is unknown!\n",
367 GNUNET_h2s (key));
368 return GNUNET_NO;
369 }
370
371 struct GNUNET_MESSENGER_Message *msg = copy_message (message);
372 return send_srv_room_message (room, handle, msg);
373}
374
375
376static const struct GNUNET_HashCode*
377get_next_member_session_context (const struct
378 GNUNET_MESSENGER_MemberSession *session)
379{
380 if (session->next)
381 return get_next_member_session_context (session->next);
382 else
383 return get_member_session_context (session);
384}
385
386
387static const struct GNUNET_MESSENGER_MemberSession*
388get_handle_member_session (struct GNUNET_MESSENGER_SrvHandle *handle,
389 struct GNUNET_MESSENGER_SrvRoom *room,
390 const struct GNUNET_HashCode *key)
391{
392 GNUNET_assert ((handle) && (room) && (key) && (handle->service));
393
394 const struct GNUNET_ShortHashCode *id = get_srv_handle_member_id (handle,
395 key);
396
397 if (! id)
398 {
399 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
400 "Handle is missing a member id for its member session! (%s)\n",
401 GNUNET_h2s (key));
402 return NULL;
403 }
404
405 struct GNUNET_MESSENGER_MemberStore *store = get_srv_room_member_store (room);
406 struct GNUNET_MESSENGER_Member *member = get_store_member (store, id);
407
408 const struct GNUNET_CRYPTO_PublicKey *pubkey = get_srv_handle_key (handle);
409
410 if (! pubkey)
411 {
412 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
413 "Handle is missing a public key for its member session! (%s)\n",
414 GNUNET_h2s (key));
415 return NULL;
416 }
417
418 return get_member_session (member, pubkey);
419}
420
421
422void
423notify_srv_handle_message (struct GNUNET_MESSENGER_SrvHandle *handle,
424 struct GNUNET_MESSENGER_SrvRoom *room,
425 const struct GNUNET_MESSENGER_SenderSession *session,
426 const struct GNUNET_MESSENGER_Message *message,
427 const struct GNUNET_HashCode *hash,
428 enum GNUNET_GenericReturnValue recent)
429{
430 GNUNET_assert ((handle) && (room) && (session) && (message) && (hash));
431
432 const struct GNUNET_HashCode *key = get_srv_room_key (room);
433
434 if ((! handle->mq) || (! get_srv_handle_member_id (handle, key)))
435 {
436 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
437 "Notifying client about message requires membership!\n");
438 return;
439 }
440
441 struct GNUNET_HashCode sender;
442 const struct GNUNET_HashCode *context = NULL;
443
444 if (GNUNET_YES == is_peer_message (message))
445 {
446 const struct GNUNET_PeerIdentity *identity = session->peer;
447 GNUNET_CRYPTO_hash (identity, sizeof(*identity), &sender);
448
449 context = &sender;
450 }
451 else
452 {
453 const struct GNUNET_CRYPTO_PublicKey *pubkey;
454 pubkey = get_member_session_public_key (session->member);
455 GNUNET_CRYPTO_hash (pubkey, sizeof(*pubkey), &sender);
456
457 context = get_next_member_session_context (session->member);
458 }
459
460 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
461 "Notifying client about message: %s (%s)\n",
462 GNUNET_h2s (hash), GNUNET_MESSENGER_name_of_kind (
463 message->header.kind));
464
465 struct GNUNET_MESSENGER_RecvMessage *msg;
466 struct GNUNET_MQ_Envelope *env;
467
468 uint16_t length = get_message_size (message, GNUNET_YES);
469
470 env = GNUNET_MQ_msg_extra (msg, length,
471 GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_RECV_MESSAGE);
472
473 GNUNET_memcpy (&(msg->key), key, sizeof(msg->key));
474 GNUNET_memcpy (&(msg->sender), &sender, sizeof(msg->sender));
475 GNUNET_memcpy (&(msg->context), context, sizeof(msg->context));
476 GNUNET_memcpy (&(msg->hash), hash, sizeof(msg->hash));
477
478 msg->flags = (uint32_t) GNUNET_MESSENGER_FLAG_NONE;
479
480 if (GNUNET_YES == is_peer_message (message))
481 msg->flags |= (uint32_t) GNUNET_MESSENGER_FLAG_PEER;
482 else if (get_handle_member_session (handle, room, key) == session->member)
483 msg->flags |= (uint32_t) GNUNET_MESSENGER_FLAG_SENT;
484
485 if (GNUNET_YES == recent)
486 msg->flags |= (uint32_t) GNUNET_MESSENGER_FLAG_RECENT;
487
488 char *buffer = ((char*) msg) + sizeof(*msg);
489 encode_message (message, length, buffer, GNUNET_YES);
490
491 GNUNET_MQ_send (handle->mq, env);
492}
493
494
495static enum GNUNET_GenericReturnValue
496iterate_next_member_ids (void *cls,
497 const struct GNUNET_HashCode *key,
498 void *value)
499{
500 struct GNUNET_MESSENGER_SrvHandle *handle = cls;
501 struct GNUNET_MESSENGER_NextMemberId *next = value;
502
503 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
504 "Notifying client about next member id: %s (%s)\n",
505 GNUNET_sh2s (&(next->id)), GNUNET_h2s (key));
506
507 struct GNUNET_MESSENGER_MemberMessage *msg;
508 struct GNUNET_MQ_Envelope *env;
509
510 env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_MEMBER_ID);
511
512 GNUNET_memcpy (&(msg->key), key, sizeof(*key));
513 GNUNET_memcpy (&(msg->id), &(next->id), sizeof(next->id));
514 msg->reset = (uint32_t) next->reset;
515
516 GNUNET_MQ_send (handle->mq, env);
517
518 GNUNET_free (next);
519 return GNUNET_YES;
520}
521
522
523static void
524task_notify_srv_handle_member_id (void *cls)
525{
526 struct GNUNET_MESSENGER_SrvHandle *handle = cls;
527 handle->notify = NULL;
528
529 GNUNET_CONTAINER_multihashmap_iterate (handle->next_ids,
530 iterate_next_member_ids, handle);
531 GNUNET_CONTAINER_multihashmap_clear (handle->next_ids);
532}
533
534
535void
536notify_srv_handle_member_id (struct GNUNET_MESSENGER_SrvHandle *handle,
537 struct GNUNET_MESSENGER_SrvRoom *room,
538 const struct GNUNET_ShortHashCode *member_id,
539 enum GNUNET_GenericReturnValue reset)
540{
541 GNUNET_assert ((handle) && (room) && (member_id));
542
543 struct GNUNET_MESSENGER_NextMemberId *next = GNUNET_new (struct
544 GNUNET_MESSENGER_NextMemberId);
545 if (! next)
546 {
547 return;
548 }
549
550 GNUNET_memcpy (&(next->id), member_id, sizeof(next->id));
551 next->reset = reset;
552
553 const struct GNUNET_HashCode *key = get_srv_room_key (room);
554
555 struct GNUNET_MESSENGER_NextMemberId *prev =
556 GNUNET_CONTAINER_multihashmap_get (handle->next_ids, key);
557 if (GNUNET_YES != GNUNET_CONTAINER_multihashmap_put (handle->next_ids, key,
558 next,
559 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE))
560 {
561 return;
562 }
563
564 if (prev)
565 GNUNET_free (prev);
566
567 if (! handle->notify)
568 handle->notify = GNUNET_SCHEDULER_add_now (task_notify_srv_handle_member_id,
569 handle);
570}
diff --git a/src/service/messenger/gnunet-service-messenger_handle.h b/src/service/messenger/gnunet-service-messenger_handle.h
new file mode 100644
index 000000000..9b41c738d
--- /dev/null
+++ b/src/service/messenger/gnunet-service-messenger_handle.h
@@ -0,0 +1,241 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_handle.h
23 * @brief GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_SERVICE_MESSENGER_HANDLE_H
27#define GNUNET_SERVICE_MESSENGER_HANDLE_H
28
29#include "gnunet_util_lib.h"
30
31#include "gnunet-service-messenger_service.h"
32#include "gnunet-service-messenger_sender_session.h"
33
34struct GNUNET_MESSENGER_SrvHandle
35{
36 struct GNUNET_MESSENGER_Service *service;
37 struct GNUNET_MQ_Handle *mq;
38
39 struct GNUNET_CRYPTO_PublicKey *key;
40
41 struct GNUNET_CONTAINER_MultiHashMap *member_ids;
42 struct GNUNET_CONTAINER_MultiHashMap *next_ids;
43 struct GNUNET_CONTAINER_MultiHashMap *routing;
44
45 struct GNUNET_SCHEDULER_Task *notify;
46};
47
48/**
49 * Creates and allocates a new handle related to a <i>service</i> and using a given <i>mq</i> (message queue).
50 *
51 * @param[in,out] service MESSENGER Service
52 * @param[in,out] mq Message queue
53 * @return New handle
54 */
55struct GNUNET_MESSENGER_SrvHandle*
56create_srv_handle (struct GNUNET_MESSENGER_Service *service,
57 struct GNUNET_MQ_Handle *mq);
58
59/**
60 * Destroys a handle and frees its memory fully.
61 *
62 * @param[in,out] handle Handle
63 */
64void
65destroy_srv_handle (struct GNUNET_MESSENGER_SrvHandle *handle);
66
67/**
68 * Sets the public key of a given <i>handle</i>.
69 *
70 * @param[out] handle Handle
71 * @param[in] key Public key
72 */
73void
74set_srv_handle_key (struct GNUNET_MESSENGER_SrvHandle *handle,
75 const struct GNUNET_CRYPTO_PublicKey *key);
76
77/**
78 * Returns the public key of a given <i>handle</i>.
79 *
80 * @param[in] handle Handle
81 * @return Public key of handle
82 */
83const struct GNUNET_CRYPTO_PublicKey*
84get_srv_handle_key (const struct GNUNET_MESSENGER_SrvHandle *handle);
85
86/**
87 * Writes the path of the directory for a given <i>handle</i> using a specific <i>name</i> to the parameter
88 * <i>dir</i>. This directory will be used to store data regarding the handle and its messages.
89 *
90 * @param[in] handle Handle
91 * @param[in] name Potential name of the handle
92 * @param[out] dir Path to store data
93 */
94void
95get_srv_handle_data_subdir (const struct GNUNET_MESSENGER_SrvHandle *handle,
96 const char *name,
97 char **dir);
98
99/**
100 * Returns the member id of a given <i>handle</i> in a specific <i>room</i>.
101 *
102 * If the handle is not a member of the specific <i>room</i>, NULL gets returned.
103 *
104 * @param[in] handle Handle
105 * @param[in] key Key of a room
106 * @return Member id or NULL
107 */
108const struct GNUNET_ShortHashCode*
109get_srv_handle_member_id (const struct GNUNET_MESSENGER_SrvHandle *handle,
110 const struct GNUNET_HashCode *key);
111
112/**
113 * Changes the member id of a given <i>handle</i> in a specific <i>room</i> to match a <i>unique_id</i>
114 * and returns GNUNET_OK on success.
115 *
116 * The client connected to the <i>handle</i> will be informed afterwards automatically.
117 *
118 * @param[in,out] handle Handle
119 * @param[in] key Key of a room
120 * @param[in] unique_id Unique member id
121 * @return GNUNET_OK on success, otherwise GNUNET_SYSERR
122 */
123enum GNUNET_GenericReturnValue
124change_srv_handle_member_id (struct GNUNET_MESSENGER_SrvHandle *handle,
125 const struct GNUNET_HashCode *key,
126 const struct GNUNET_ShortHashCode *unique_id);
127
128/**
129 * Makes a given <i>handle</i> a member of the room using a specific <i>key</i> and opens the
130 * room from the handles service.
131 *
132 * @param[in,out] handle Handle
133 * @param[in] key Key of a room
134 * @return #GNUNET_YES on success, otherwise #GNUNET_NO
135 */
136enum GNUNET_GenericReturnValue
137open_srv_handle_room (struct GNUNET_MESSENGER_SrvHandle *handle,
138 const struct GNUNET_HashCode *key);
139
140/**
141 * Makes a given <i>handle</i> a member of the room using a specific <i>key</i> and enters the room
142 * through a tunnel to a peer identified by a given <i>door</i> (peer identity).
143 *
144 * @param[in,out] handle Handle
145 * @param[in] door Peer identity
146 * @param[in] key Key of a room
147 * @return #GNUNET_YES on success, otherwise #GNUNET_NO
148 */
149enum GNUNET_GenericReturnValue
150entry_srv_handle_room (struct GNUNET_MESSENGER_SrvHandle *handle,
151 const struct GNUNET_PeerIdentity *door,
152 const struct GNUNET_HashCode *key);
153
154/**
155 * Removes the membership of the room using a specific <i>key</i> and closes it if no other handle
156 * from this service is still a member of it.
157 *
158 * @param[in,out] handle Handle
159 * @param[in] key Key of a room
160 * @return #GNUNET_YES on success, otherwise #GNUNET_NO
161 */
162enum GNUNET_GenericReturnValue
163close_srv_handle_room (struct GNUNET_MESSENGER_SrvHandle *handle,
164 const struct GNUNET_HashCode *key);
165
166/**
167 * Returns whether a given <i>handle</i> has enabled routing for a room using a specific <i>key</i>
168 * by opening that room.
169 *
170 * @param[in] handle Handle
171 * @param[in] key Key of a room
172 * @return #GNUNET_YES is routing is enabled, otherwise #GNUNET_NO
173 */
174enum GNUNET_GenericReturnValue
175is_srv_handle_routing (const struct GNUNET_MESSENGER_SrvHandle *handle,
176 const struct GNUNET_HashCode *key);
177
178
179/**
180 * Returns the latest merged hash from a room of a given <i>handle</i> using a specific <i>key</i>
181 * and the handles own latest known <i>hash</i> of a message. If the room does not contain other
182 * messages being accessible to the handle and older than the provided hash, the function returns
183 * the originally provided hash as fallback.
184 *
185 * @param[in,out] handle Handle
186 * @param[in] key Key of a room
187 * @param[in] prev Known hash of a message
188 * @param[out] hash Hash of the latest merged message in a room available to the handle
189 */
190void
191sync_srv_handle_messages (struct GNUNET_MESSENGER_SrvHandle *handle,
192 const struct GNUNET_HashCode *key,
193 const struct GNUNET_HashCode *prev,
194 struct GNUNET_HashCode *hash);
195
196/**
197 * Sends a <i>message</i> from a given <i>handle</i> to the room using a specific <i>key</i>.
198 *
199 * @param[in,out] handle Handle
200 * @param[in] key Key of a room
201 * @param[in] message Message
202 * @return #GNUNET_YES on success, #GNUNET_NO or #GNUNET_SYSERR otherwise.
203 */
204enum GNUNET_GenericReturnValue
205send_srv_handle_message (struct GNUNET_MESSENGER_SrvHandle *handle,
206 const struct GNUNET_HashCode *key,
207 const struct GNUNET_MESSENGER_Message *message);
208
209/**
210 * Notifies the handle that a new message was received or sent.
211 *
212 * @param[in,out] handle Handle
213 * @param[in] room Room of the message
214 * @param[in] session Sender session
215 * @param[in] message Message
216 * @param[in] hash Hash of message
217 * @param[in] recent Whether the message was recently handled
218 */
219void
220notify_srv_handle_message (struct GNUNET_MESSENGER_SrvHandle *handle,
221 struct GNUNET_MESSENGER_SrvRoom *room,
222 const struct GNUNET_MESSENGER_SenderSession *session,
223 const struct GNUNET_MESSENGER_Message *message,
224 const struct GNUNET_HashCode *hash,
225 enum GNUNET_GenericReturnValue recent);
226
227/**
228 * Notifies the handle that a new member id needs to be used.
229 *
230 * @param[in,out] handle Handle
231 * @param[in] room Room of the member
232 * @param[in] member_id Member id
233 * @param[in] reset Reset member session with join message
234 */
235void
236notify_srv_handle_member_id (struct GNUNET_MESSENGER_SrvHandle *handle,
237 struct GNUNET_MESSENGER_SrvRoom *room,
238 const struct GNUNET_ShortHashCode *member_id,
239 enum GNUNET_GenericReturnValue reset);
240
241#endif //GNUNET_SERVICE_MESSENGER_HANDLE_H
diff --git a/src/service/messenger/gnunet-service-messenger_list_handles.c b/src/service/messenger/gnunet-service-messenger_list_handles.c
new file mode 100644
index 000000000..6002dfe7b
--- /dev/null
+++ b/src/service/messenger/gnunet-service-messenger_list_handles.c
@@ -0,0 +1,117 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2023 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_list_handles.c
23 * @brief GNUnet MESSENGER service
24 */
25
26#include "gnunet-service-messenger_list_handles.h"
27
28#include "gnunet-service-messenger_handle.h"
29
30void
31init_list_handles (struct GNUNET_MESSENGER_ListHandles *handles)
32{
33 GNUNET_assert (handles);
34
35 handles->head = NULL;
36 handles->tail = NULL;
37}
38
39
40void
41clear_list_handles (struct GNUNET_MESSENGER_ListHandles *handles)
42{
43 GNUNET_assert (handles);
44
45 while (handles->head)
46 {
47 struct GNUNET_MESSENGER_ListHandle *element = handles->head;
48
49 GNUNET_CONTAINER_DLL_remove (handles->head, handles->tail, element);
50 destroy_srv_handle (element->handle);
51 GNUNET_free (element);
52 }
53
54 handles->head = NULL;
55 handles->tail = NULL;
56}
57
58
59void
60add_list_handle (struct GNUNET_MESSENGER_ListHandles *handles,
61 struct GNUNET_MESSENGER_SrvHandle *handle)
62{
63 GNUNET_assert ((handles) && (handle));
64
65 struct GNUNET_MESSENGER_ListHandle *element = GNUNET_new (struct
66 GNUNET_MESSENGER_ListHandle);
67
68 element->handle = handle;
69
70 GNUNET_CONTAINER_DLL_insert_tail (handles->head, handles->tail, element);
71}
72
73
74enum GNUNET_GenericReturnValue
75remove_list_handle (struct GNUNET_MESSENGER_ListHandles *handles,
76 struct GNUNET_MESSENGER_SrvHandle *handle)
77{
78 GNUNET_assert ((handles) && (handle));
79
80 struct GNUNET_MESSENGER_ListHandle *element;
81
82 for (element = handles->head; element; element = element->next)
83 if (element->handle == handle)
84 break;
85
86 if (! element)
87 return GNUNET_NO;
88
89 GNUNET_CONTAINER_DLL_remove (handles->head, handles->tail, element);
90 GNUNET_free (element);
91
92 return GNUNET_YES;
93}
94
95
96struct GNUNET_MESSENGER_SrvHandle*
97find_list_handle_by_member (const struct GNUNET_MESSENGER_ListHandles *handles,
98 const struct GNUNET_HashCode *key)
99{
100 GNUNET_assert ((handles) && (key));
101
102 struct GNUNET_MESSENGER_ListHandle *element;
103 struct GNUNET_MESSENGER_SrvHandle *handle = NULL;
104
105 for (element = handles->head; element; element = element->next)
106 {
107 if (get_srv_handle_member_id ((struct
108 GNUNET_MESSENGER_SrvHandle *) element->handle,
109 key))
110 handle = (struct GNUNET_MESSENGER_SrvHandle *) element->handle;
111
112 if ((handle) && (GNUNET_YES == is_srv_handle_routing (handle, key)))
113 break;
114 }
115
116 return handle;
117}
diff --git a/src/service/messenger/gnunet-service-messenger_list_handles.h b/src/service/messenger/gnunet-service-messenger_list_handles.h
new file mode 100644
index 000000000..64dee6544
--- /dev/null
+++ b/src/service/messenger/gnunet-service-messenger_list_handles.h
@@ -0,0 +1,100 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_list_handles.h
23 * @brief GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_SERVICE_MESSENGER_LIST_HANDLES_H
27#define GNUNET_SERVICE_MESSENGER_LIST_HANDLES_H
28
29#include "gnunet_common.h"
30
31struct GNUNET_MESSENGER_SrvHandle;
32
33struct GNUNET_MESSENGER_ListHandle
34{
35 struct GNUNET_MESSENGER_ListHandle *prev;
36 struct GNUNET_MESSENGER_ListHandle *next;
37
38 struct GNUNET_MESSENGER_SrvHandle *handle;
39};
40
41struct GNUNET_MESSENGER_ListHandles
42{
43 struct GNUNET_MESSENGER_ListHandle *head;
44 struct GNUNET_MESSENGER_ListHandle *tail;
45};
46
47/**
48 * Initializes list of <i>handles</i> as empty list.
49 *
50 * @param[out] handles List of handles
51 */
52void
53init_list_handles (struct GNUNET_MESSENGER_ListHandles *handles);
54
55/**
56 * Destroys remaining <i>handles</i> and clears the list.
57 *
58 * @param[in,out] handles List of handles
59 */
60void
61clear_list_handles (struct GNUNET_MESSENGER_ListHandles *handles);
62
63/**
64 * Adds a specific <i>handle</i> to the end of the list.
65 *
66 * @param[in,out] handles List of handles
67 * @param[in,out] handle Handle
68 */
69void
70add_list_handle (struct GNUNET_MESSENGER_ListHandles *handles,
71 struct GNUNET_MESSENGER_SrvHandle *handle);
72
73/**
74 * Removes the first entry matching with a specific <i>handle</i> from the list of
75 * <i>handles</i> and returns #GNUNET_YES on success or #GNUNET_NO on failure.
76 *
77 * @param[in,out] handles List of handles
78 * @param[in,out] handle Handle
79 * @return #GNUNET_YES on success, otherwise #GNUNET_NO
80 */
81enum GNUNET_GenericReturnValue
82remove_list_handle (struct GNUNET_MESSENGER_ListHandles *handles,
83 struct GNUNET_MESSENGER_SrvHandle *handle);
84
85/**
86 * Searches linearly through the list of <i>handles</i> for members of a specific room
87 * which is identified by a given <i>key</i>. The handle returned will be one that has
88 * enabled routing for the room if possible.
89 *
90 * If no handle is found which is a current member, NULL gets returned.
91 *
92 * @param[in] handles List of handles
93 * @param[in] key Common key of a room
94 * @return A handle which is a current member
95 */
96struct GNUNET_MESSENGER_SrvHandle*
97find_list_handle_by_member (const struct GNUNET_MESSENGER_ListHandles *handles,
98 const struct GNUNET_HashCode *key);
99
100#endif //GNUNET_SERVICE_MESSENGER_LIST_HANDLES_H
diff --git a/src/service/messenger/gnunet-service-messenger_list_messages.c b/src/service/messenger/gnunet-service-messenger_list_messages.c
new file mode 100644
index 000000000..cd59c8aec
--- /dev/null
+++ b/src/service/messenger/gnunet-service-messenger_list_messages.c
@@ -0,0 +1,168 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_list_messages.c
23 * @brief GNUnet MESSENGER service
24 */
25
26#include "gnunet-service-messenger_list_messages.h"
27
28#include "gnunet_util_lib.h"
29
30void
31init_list_messages (struct GNUNET_MESSENGER_ListMessages *messages)
32{
33 GNUNET_assert (messages);
34
35 messages->head = NULL;
36 messages->tail = NULL;
37}
38
39
40void
41clear_list_messages (struct GNUNET_MESSENGER_ListMessages *messages)
42{
43 GNUNET_assert (messages);
44
45 while (messages->head)
46 {
47 struct GNUNET_MESSENGER_ListMessage *element = messages->head;
48
49 GNUNET_CONTAINER_DLL_remove (messages->head, messages->tail, element);
50 GNUNET_free (element);
51 }
52
53 messages->head = NULL;
54 messages->tail = NULL;
55}
56
57
58void
59add_to_list_messages (struct GNUNET_MESSENGER_ListMessages *messages,
60 const struct GNUNET_HashCode *hash)
61{
62 GNUNET_assert ((messages) && (hash));
63
64 struct GNUNET_MESSENGER_ListMessage *element = GNUNET_new (struct
65 GNUNET_MESSENGER_ListMessage);
66
67 GNUNET_memcpy (&(element->hash), hash, sizeof(struct GNUNET_HashCode));
68
69 GNUNET_CONTAINER_DLL_insert_tail (messages->head, messages->tail, element);
70}
71
72
73void
74copy_list_messages (struct GNUNET_MESSENGER_ListMessages *messages,
75 const struct GNUNET_MESSENGER_ListMessages *origin)
76{
77 GNUNET_assert ((messages) && (origin));
78
79 struct GNUNET_MESSENGER_ListMessage *element;
80
81 for (element = origin->head; element; element = element->next)
82 add_to_list_messages (messages, &(element->hash));
83}
84
85
86void
87remove_from_list_messages (struct GNUNET_MESSENGER_ListMessages *messages,
88 const struct GNUNET_HashCode *hash)
89{
90 GNUNET_assert ((messages) && (hash));
91
92 struct GNUNET_MESSENGER_ListMessage *element;
93
94 for (element = messages->head; element; element = element->next)
95 if (0 == GNUNET_CRYPTO_hash_cmp (&(element->hash), hash))
96 {
97 GNUNET_CONTAINER_DLL_remove (messages->head, messages->tail, element);
98 GNUNET_free (element);
99 break;
100 }
101}
102
103
104void
105load_list_messages (struct GNUNET_MESSENGER_ListMessages *messages,
106 const char *path)
107{
108 GNUNET_assert ((messages) && (path));
109
110 if (GNUNET_YES != GNUNET_DISK_file_test (path))
111 return;
112
113 enum GNUNET_DISK_AccessPermissions permission = (GNUNET_DISK_PERM_USER_READ
114 | GNUNET_DISK_PERM_USER_WRITE
115 );
116
117 struct GNUNET_DISK_FileHandle *handle = GNUNET_DISK_file_open (
118 path, GNUNET_DISK_OPEN_READ, permission
119 );
120
121 if (! handle)
122 return;
123
124 GNUNET_DISK_file_seek (handle, 0, GNUNET_DISK_SEEK_SET);
125
126 struct GNUNET_HashCode hash;
127 ssize_t len;
128
129 do {
130 len = GNUNET_DISK_file_read (handle, &hash, sizeof(hash));
131
132 if (len != sizeof(hash))
133 break;
134
135 add_to_list_messages (messages, &hash);
136 } while (len == sizeof(hash));
137
138 GNUNET_DISK_file_close (handle);
139}
140
141
142void
143save_list_messages (const struct GNUNET_MESSENGER_ListMessages *messages,
144 const char *path)
145{
146 GNUNET_assert ((messages) && (path));
147
148 enum GNUNET_DISK_AccessPermissions permission = (GNUNET_DISK_PERM_USER_READ
149 | GNUNET_DISK_PERM_USER_WRITE
150 );
151
152 struct GNUNET_DISK_FileHandle *handle = GNUNET_DISK_file_open (
153 path, GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_WRITE, permission
154 );
155
156 if (! handle)
157 return;
158
159 GNUNET_DISK_file_seek (handle, 0, GNUNET_DISK_SEEK_SET);
160
161 struct GNUNET_MESSENGER_ListMessage *element;
162
163 for (element = messages->head; element; element = element->next)
164 GNUNET_DISK_file_write (handle, &(element->hash), sizeof(element->hash));
165
166 GNUNET_DISK_file_sync (handle);
167 GNUNET_DISK_file_close (handle);
168}
diff --git a/src/service/messenger/gnunet-service-messenger_list_messages.h b/src/service/messenger/gnunet-service-messenger_list_messages.h
new file mode 100644
index 000000000..133091506
--- /dev/null
+++ b/src/service/messenger/gnunet-service-messenger_list_messages.h
@@ -0,0 +1,111 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_list_messages.h
23 * @brief GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_SERVICE_MESSENGER_LIST_MESSAGES_H
27#define GNUNET_SERVICE_MESSENGER_LIST_MESSAGES_H
28
29#include "gnunet_common.h"
30
31struct GNUNET_MESSENGER_ListMessage
32{
33 struct GNUNET_MESSENGER_ListMessage *prev;
34 struct GNUNET_MESSENGER_ListMessage *next;
35
36 struct GNUNET_HashCode hash;
37};
38
39struct GNUNET_MESSENGER_ListMessages
40{
41 struct GNUNET_MESSENGER_ListMessage *head;
42 struct GNUNET_MESSENGER_ListMessage *tail;
43};
44
45/**
46 * Initializes list of message hashes as empty list.
47 *
48 * @param[out] messages List of hashes
49 */
50void
51init_list_messages (struct GNUNET_MESSENGER_ListMessages *messages);
52
53/**
54 * Clears the list of message hashes.
55 *
56 * @param[in,out] messages List of hashes
57 */
58void
59clear_list_messages (struct GNUNET_MESSENGER_ListMessages *messages);
60
61/**
62 * Adds a specific <i>hash</i> from a message to the end of the list.
63 *
64 * @param[in,out] messages List of hashes
65 * @param[in] hash Hash of message
66 */
67void
68add_to_list_messages (struct GNUNET_MESSENGER_ListMessages *messages,
69 const struct GNUNET_HashCode *hash);
70
71/**
72 * Copies all message hashes from an <i>origin</i> to another list.
73 *
74 * @param[in,out] messages Destination list of hashes
75 * @param[in] origin Source list of hashes
76 */
77void
78copy_list_messages (struct GNUNET_MESSENGER_ListMessages *messages,
79 const struct GNUNET_MESSENGER_ListMessages *origin);
80
81/**
82 * Removes the first entry with a matching <i>hash</i> from the list.
83 *
84 * @param[in,out] messages List of hashes
85 * @param[in] hash Hash of message
86 */
87void
88remove_from_list_messages (struct GNUNET_MESSENGER_ListMessages *messages,
89 const struct GNUNET_HashCode *hash);
90
91/**
92 * Loads the list of message hashes from a file under a given <i>path</i>.
93 *
94 * @param[out] messages List of hashes
95 * @param[in] path Path of file
96 */
97void
98load_list_messages (struct GNUNET_MESSENGER_ListMessages *messages,
99 const char *path);
100
101/**
102 * Saves the list of message hashes to a file under a given <i>path</i>.
103 *
104 * @param[in] messages List of hashes
105 * @param[in] path Path of file
106 */
107void
108save_list_messages (const struct GNUNET_MESSENGER_ListMessages *messages,
109 const char *path);
110
111#endif //GNUNET_SERVICE_MESSENGER_LIST_MESSAGES_H
diff --git a/src/service/messenger/gnunet-service-messenger_member.c b/src/service/messenger/gnunet-service-messenger_member.c
new file mode 100644
index 000000000..0940c42ce
--- /dev/null
+++ b/src/service/messenger/gnunet-service-messenger_member.c
@@ -0,0 +1,462 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_member.c
23 * @brief GNUnet MESSENGER service
24 */
25
26#include "platform.h"
27#include "gnunet-service-messenger_member.h"
28
29#include "gnunet-service-messenger_member_session.h"
30
31#include "messenger_api_util.h"
32
33struct GNUNET_MESSENGER_Member*
34create_member (struct GNUNET_MESSENGER_MemberStore *store,
35 const struct GNUNET_ShortHashCode *id)
36{
37 GNUNET_assert (store);
38
39 struct GNUNET_MESSENGER_Member *member = GNUNET_new (struct
40 GNUNET_MESSENGER_Member);
41
42 member->store = store;
43
44 if (id)
45 GNUNET_memcpy (&(member->id), id, sizeof(member->id));
46 else if (GNUNET_YES != generate_free_member_id (&(member->id),
47 store->members))
48 {
49 GNUNET_free (member);
50 return NULL;
51 }
52
53 member->sessions = GNUNET_CONTAINER_multihashmap_create (2, GNUNET_NO);
54
55 return member;
56}
57
58
59static enum GNUNET_GenericReturnValue
60iterate_destroy_session (void *cls,
61 const struct GNUNET_HashCode *key,
62 void *value)
63{
64 struct GNUNET_MESSENGER_MemberSession *session = value;
65 destroy_member_session (session);
66 return GNUNET_YES;
67}
68
69
70void
71destroy_member (struct GNUNET_MESSENGER_Member *member)
72{
73 GNUNET_assert ((member) && (member->sessions));
74
75 GNUNET_CONTAINER_multihashmap_iterate (member->sessions,
76 iterate_destroy_session, NULL);
77 GNUNET_CONTAINER_multihashmap_destroy (member->sessions);
78
79 GNUNET_free (member);
80}
81
82
83const struct GNUNET_ShortHashCode*
84get_member_id (const struct GNUNET_MESSENGER_Member *member)
85{
86 GNUNET_assert (member);
87
88 return &(member->id);
89}
90
91
92static enum GNUNET_GenericReturnValue
93callback_scan_for_sessions (void *cls,
94 const char *filename)
95{
96 struct GNUNET_MESSENGER_Member *member = cls;
97
98 if (GNUNET_YES == GNUNET_DISK_directory_test (filename, GNUNET_YES))
99 {
100 char *directory;
101
102 GNUNET_asprintf (&directory, "%s%c", filename, DIR_SEPARATOR);
103
104 load_member_session (member, directory);
105 GNUNET_free (directory);
106 }
107
108 return GNUNET_OK;
109}
110
111
112void
113load_member (struct GNUNET_MESSENGER_MemberStore *store,
114 const char *directory)
115{
116 GNUNET_assert ((store) && (directory));
117
118 char *config_file;
119 GNUNET_asprintf (&config_file, "%s%s", directory, "member.cfg");
120
121 struct GNUNET_MESSENGER_Member *member = NULL;
122
123 if (GNUNET_YES != GNUNET_DISK_file_test (config_file))
124 goto free_config;
125
126 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Load member configuration: %s\n",
127 config_file);
128
129 struct GNUNET_CONFIGURATION_Handle *cfg = GNUNET_CONFIGURATION_create ();
130
131 if (GNUNET_OK == GNUNET_CONFIGURATION_parse (cfg, config_file))
132 {
133 struct GNUNET_ShortHashCode id;
134
135 if (GNUNET_OK != GNUNET_CONFIGURATION_get_data (cfg, "member", "id", &id,
136 sizeof(id)))
137 goto destroy_config;
138
139 member = add_store_member (store, &id);
140 }
141
142destroy_config:
143
144 GNUNET_CONFIGURATION_destroy (cfg);
145
146free_config:
147 GNUNET_free (config_file);
148
149 if (! member)
150 return;
151
152 char *scan_dir;
153 GNUNET_asprintf (&scan_dir, "%s%s%c", directory, "sessions", DIR_SEPARATOR);
154
155 if (GNUNET_OK == GNUNET_DISK_directory_test (scan_dir, GNUNET_YES))
156 GNUNET_DISK_directory_scan (scan_dir, callback_scan_for_sessions, member);
157
158 GNUNET_free (scan_dir);
159}
160
161
162static enum GNUNET_GenericReturnValue
163iterate_load_next_session (void *cls,
164 const struct GNUNET_HashCode *key,
165 void *value)
166{
167 const char *sessions_directory = cls;
168
169 char *load_dir;
170 GNUNET_asprintf (&load_dir, "%s%s%c", sessions_directory, GNUNET_h2s (key),
171 DIR_SEPARATOR);
172
173 struct GNUNET_MESSENGER_MemberSession *session = value;
174
175 if (GNUNET_YES == GNUNET_DISK_directory_test (load_dir, GNUNET_YES))
176 load_member_session_next (session, load_dir);
177
178 GNUNET_free (load_dir);
179 return GNUNET_YES;
180}
181
182
183void
184load_member_next_sessions (const struct GNUNET_MESSENGER_Member *member,
185 const char *directory)
186{
187 GNUNET_assert ((member) && (directory));
188
189 char *load_dir;
190 GNUNET_asprintf (&load_dir, "%s%s%c", directory, "sessions", DIR_SEPARATOR);
191
192 GNUNET_CONTAINER_multihashmap_iterate (member->sessions,
193 iterate_load_next_session, load_dir);
194
195 GNUNET_free (load_dir);
196}
197
198
199static enum GNUNET_GenericReturnValue
200iterate_save_session (void *cls,
201 const struct GNUNET_HashCode *key,
202 void *value)
203{
204 const char *sessions_directory = cls;
205
206 char *save_dir;
207 GNUNET_asprintf (&save_dir, "%s%s%c", sessions_directory, GNUNET_h2s (key),
208 DIR_SEPARATOR);
209
210 struct GNUNET_MESSENGER_MemberSession *session = value;
211
212 if ((GNUNET_YES == GNUNET_DISK_directory_test (save_dir, GNUNET_NO)) ||
213 (GNUNET_OK == GNUNET_DISK_directory_create (save_dir)))
214 save_member_session (session, save_dir);
215
216 GNUNET_free (save_dir);
217 return GNUNET_YES;
218}
219
220
221void
222save_member (struct GNUNET_MESSENGER_Member *member,
223 const char *directory)
224{
225 GNUNET_assert ((member) && (directory));
226
227 char *config_file;
228 GNUNET_asprintf (&config_file, "%s%s", directory, "member.cfg");
229
230 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Save member configuration: %s\n",
231 config_file);
232
233 struct GNUNET_CONFIGURATION_Handle *cfg = GNUNET_CONFIGURATION_create ();
234
235 char *id_data = GNUNET_STRINGS_data_to_string_alloc (&(member->id),
236 sizeof(member->id));
237
238 if (id_data)
239 {
240 GNUNET_CONFIGURATION_set_value_string (cfg, "member", "id", id_data);
241
242 GNUNET_free (id_data);
243 }
244
245 GNUNET_CONFIGURATION_write (cfg, config_file);
246 GNUNET_CONFIGURATION_destroy (cfg);
247
248 GNUNET_free (config_file);
249
250 char *save_dir;
251 GNUNET_asprintf (&save_dir, "%s%s%c", directory, "sessions", DIR_SEPARATOR);
252
253 if ((GNUNET_YES == GNUNET_DISK_directory_test (save_dir, GNUNET_NO)) ||
254 (GNUNET_OK == GNUNET_DISK_directory_create (save_dir)))
255 GNUNET_CONTAINER_multihashmap_iterate (member->sessions,
256 iterate_save_session, save_dir);
257
258 GNUNET_free (save_dir);
259}
260
261
262static void
263sync_session_contact_from_next (struct GNUNET_MESSENGER_MemberSession *session,
264 struct GNUNET_MESSENGER_MemberSession *next)
265{
266 GNUNET_assert ((session) && (next));
267
268 if (session == next)
269 return;
270
271 if (next->next)
272 sync_session_contact_from_next (session, next->next);
273 else
274 session->contact = next->contact;
275}
276
277
278static enum GNUNET_GenericReturnValue
279iterate_sync_session_contact (void *cls,
280 const struct GNUNET_HashCode *key,
281 void *value)
282{
283 struct GNUNET_MESSENGER_MemberSession *session = value;
284
285 if (session->next)
286 sync_session_contact_from_next (session, session->next);
287
288 return GNUNET_YES;
289}
290
291
292void
293sync_member_contacts (struct GNUNET_MESSENGER_Member *member)
294{
295 GNUNET_assert ((member) && (member->sessions));
296
297 GNUNET_CONTAINER_multihashmap_iterate (member->sessions,
298 iterate_sync_session_contact, NULL);
299}
300
301
302struct GNUNET_MESSENGER_MemberSession*
303get_member_session (const struct GNUNET_MESSENGER_Member *member,
304 const struct GNUNET_CRYPTO_PublicKey *public_key)
305{
306 GNUNET_assert ((member) && (public_key));
307
308 struct GNUNET_HashCode hash;
309 GNUNET_CRYPTO_hash (public_key, sizeof(*public_key), &hash);
310
311 return GNUNET_CONTAINER_multihashmap_get (member->sessions, &hash);
312}
313
314
315struct GNUNET_MESSENGER_ClosureSearchSession
316{
317 const struct GNUNET_MESSENGER_Message *message;
318 const struct GNUNET_HashCode *hash;
319
320 struct GNUNET_MESSENGER_MemberSession *match;
321};
322
323static enum GNUNET_GenericReturnValue
324iterate_search_session (void *cls,
325 const struct GNUNET_HashCode *key,
326 void *value)
327{
328 struct GNUNET_MESSENGER_ClosureSearchSession *search = cls;
329 struct GNUNET_MESSENGER_MemberSession *session = value;
330
331 if (GNUNET_OK != verify_member_session_as_sender (session, search->message,
332 search->hash))
333 return GNUNET_YES;
334
335 search->match = session;
336 return GNUNET_NO;
337}
338
339
340static struct GNUNET_MESSENGER_MemberSession*
341try_member_session (struct GNUNET_MESSENGER_Member *member,
342 const struct GNUNET_CRYPTO_PublicKey *public_key)
343{
344 struct GNUNET_MESSENGER_MemberSession *session = get_member_session (member,
345 public_key);
346
347 if (session)
348 return session;
349
350 session = create_member_session (member, public_key);
351
352 if (session)
353 add_member_session (member, session);
354
355 return session;
356}
357
358
359struct GNUNET_MESSENGER_MemberSession*
360get_member_session_of (struct GNUNET_MESSENGER_Member *member,
361 const struct GNUNET_MESSENGER_Message *message,
362 const struct GNUNET_HashCode *hash)
363{
364 GNUNET_assert ((member) && (message) && (hash) &&
365 (0 == GNUNET_memcmp (&(member->id),
366 &(message->header.sender_id))));
367
368 if (GNUNET_MESSENGER_KIND_JOIN == message->header.kind)
369 return try_member_session (member, &(message->body.join.key));
370
371 struct GNUNET_MESSENGER_ClosureSearchSession search;
372
373 search.message = message;
374 search.hash = hash;
375
376 search.match = NULL;
377 GNUNET_CONTAINER_multihashmap_iterate (member->sessions,
378 iterate_search_session, &search);
379
380 return search.match;
381}
382
383
384void
385add_member_session (struct GNUNET_MESSENGER_Member *member,
386 struct GNUNET_MESSENGER_MemberSession *session)
387{
388 if (! session)
389 return;
390
391 GNUNET_assert ((member) && (session->member == member));
392
393 const struct GNUNET_CRYPTO_PublicKey *public_key =
394 get_member_session_public_key (session);
395
396 struct GNUNET_HashCode hash;
397 GNUNET_CRYPTO_hash (public_key, sizeof(*public_key), &hash);
398
399 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (
400 member->sessions, &hash, session,
401 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
402 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
403 "Adding a member session failed: %s\n",
404 GNUNET_h2s (&hash));
405}
406
407
408void
409remove_member_session (struct GNUNET_MESSENGER_Member *member,
410 struct GNUNET_MESSENGER_MemberSession *session)
411{
412 GNUNET_assert ((member) && (session) && (session->member == member));
413
414 const struct GNUNET_CRYPTO_PublicKey *public_key =
415 get_member_session_public_key (session);
416
417 struct GNUNET_HashCode hash;
418 GNUNET_CRYPTO_hash (public_key, sizeof(*public_key), &hash);
419
420 if (GNUNET_YES != GNUNET_CONTAINER_multihashmap_remove (member->sessions,
421 &hash, session))
422 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
423 "Removing a member session failed: %s\n",
424 GNUNET_h2s (&hash));
425}
426
427
428struct GNUNET_MESSENGER_ClosureIterateSessions
429{
430 GNUNET_MESSENGER_MemberIteratorCallback it;
431 void *cls;
432};
433
434static enum GNUNET_GenericReturnValue
435iterate_member_sessions_it (void *cls,
436 const struct GNUNET_HashCode *key,
437 void *value)
438{
439 struct GNUNET_MESSENGER_ClosureIterateSessions *iterate = cls;
440 struct GNUNET_MESSENGER_MemberSession *session = value;
441
442 return iterate->it (iterate->cls, get_member_session_public_key (session),
443 session);
444}
445
446
447int
448iterate_member_sessions (struct GNUNET_MESSENGER_Member *member,
449 GNUNET_MESSENGER_MemberIteratorCallback it,
450 void *cls)
451{
452 GNUNET_assert ((member) && (member->sessions) && (it));
453
454 struct GNUNET_MESSENGER_ClosureIterateSessions iterate;
455
456 iterate.it = it;
457 iterate.cls = cls;
458
459 return GNUNET_CONTAINER_multihashmap_iterate (member->sessions,
460 iterate_member_sessions_it,
461 &iterate);
462}
diff --git a/src/service/messenger/gnunet-service-messenger_member.h b/src/service/messenger/gnunet-service-messenger_member.h
new file mode 100644
index 000000000..0e5afaa6a
--- /dev/null
+++ b/src/service/messenger/gnunet-service-messenger_member.h
@@ -0,0 +1,175 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_member.h
23 * @brief GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_SERVICE_MESSENGER_MEMBER_H
27#define GNUNET_SERVICE_MESSENGER_MEMBER_H
28
29#include "gnunet-service-messenger_member_store.h"
30
31struct GNUNET_MESSENGER_Member
32{
33 struct GNUNET_MESSENGER_MemberStore *store;
34 struct GNUNET_ShortHashCode id;
35
36 struct GNUNET_CONTAINER_MultiHashMap *sessions;
37};
38
39/**
40 * Creates and allocates a new member of a <i>room</i> with an optionally defined or
41 * random <i>id</i>.
42 *
43 * If the creation fails, NULL gets returned.
44 *
45 * @param[in,out] store Member store
46 * @param[in] id Member id or NULL
47 * @return New member or NULL
48 */
49struct GNUNET_MESSENGER_Member*
50create_member (struct GNUNET_MESSENGER_MemberStore *store,
51 const struct GNUNET_ShortHashCode *id);
52
53/**
54 * Destroys a member and frees its memory fully.
55 *
56 * @param[in,out] member Member
57 */
58void
59destroy_member (struct GNUNET_MESSENGER_Member *member);
60
61/**
62 * Returns the current id of a given <i>member</i>.
63 *
64 * @param[in] member Member
65 * @return Member id
66 */
67const struct GNUNET_ShortHashCode*
68get_member_id (const struct GNUNET_MESSENGER_Member *member);
69
70/**
71 * Loads data from a <i>directory</i> into a new allocated and created member
72 * of a <i>store</i> if the required information can be read from the content
73 * of the given directory.
74 *
75 * @param[out] store Member store
76 * @param[in] directory Path to a directory
77 */
78void
79load_member (struct GNUNET_MESSENGER_MemberStore *store,
80 const char *directory);
81
82/**
83 * Loads data about next sessions from a <i>directory</i> into an empty loaded
84 * <i>member</i> which does not contain a fully built session graph yet.
85 *
86 * @param[in,out] member Member
87 * @param[in] directory Path to a directory
88 */
89void
90load_member_next_sessions (const struct GNUNET_MESSENGER_Member *member,
91 const char *directory);
92
93/**
94 * Saves data from a <i>member</i> into a directory which
95 * can be load to restore the member completely.
96 *
97 * @param[in] member Member
98 * @param[in] directory Path to a directory
99 */
100void
101save_member (struct GNUNET_MESSENGER_Member *member,
102 const char *directory);
103
104/**
105 * Synchronizes contacts between all sessions from a given <i>member</i>
106 * and other sessions which are linked to them.
107 *
108 * @param[in,out] member Member
109 */
110void
111sync_member_contacts (struct GNUNET_MESSENGER_Member *member);
112
113/**
114 * Returns the member session of a <i>member</i> identified by a given public key.
115 * If the member does not provide a session with the given key, NULL gets returned.
116 *
117 * @param[in] member Member
118 * @param[in] public_key Public key
119 * @return Member session
120 */
121struct GNUNET_MESSENGER_MemberSession*
122get_member_session (const struct GNUNET_MESSENGER_Member *member,
123 const struct GNUNET_CRYPTO_PublicKey *public_key);
124
125/**
126 * Returns the member session of a <i>member</i> using a public key which can verify
127 * the signature of a given <i>message</i> and its <i>hash</i>. If the member does
128 * not provide a matching session, NULL gets returned.
129 *
130 * @param[in] member Member
131 * @param[in] message Message
132 * @param[in] hash Hash of message
133 * @return Member session
134 */
135struct GNUNET_MESSENGER_MemberSession*
136get_member_session_of (struct GNUNET_MESSENGER_Member *member,
137 const struct GNUNET_MESSENGER_Message *message,
138 const struct GNUNET_HashCode *hash);
139
140/**
141 * Adds a given member <i>session</i> to its <i>member</i>.
142 *
143 * @param[in,out] member Member
144 * @param[in,out] session Member session
145 */
146void
147add_member_session (struct GNUNET_MESSENGER_Member *member,
148 struct GNUNET_MESSENGER_MemberSession *session);
149
150/**
151 * Removes a given member <i>session</i> from its <i>member</i>.
152 *
153 * @param[in,out] member Member
154 * @param[in,out] session Member session
155 */
156void
157remove_member_session (struct GNUNET_MESSENGER_Member *member,
158 struct GNUNET_MESSENGER_MemberSession *session);
159
160/**
161 * Iterate through all member sessions currently connected to a given <i>member</i>
162 * and call the provided iterator callback with a selected closure. The function
163 * will return the amount of member sessions it iterated through.
164 *
165 * @param[in,out] member Member
166 * @param[in] it Iterator callback
167 * @param[in,out] cls Closure
168 * @return Amount of sessions iterated through
169 */
170int
171iterate_member_sessions (struct GNUNET_MESSENGER_Member *member,
172 GNUNET_MESSENGER_MemberIteratorCallback it,
173 void *cls);
174
175#endif //GNUNET_SERVICE_MESSENGER_MEMBER_H
diff --git a/src/service/messenger/gnunet-service-messenger_member_session.c b/src/service/messenger/gnunet-service-messenger_member_session.c
new file mode 100644
index 000000000..ed1fd75b7
--- /dev/null
+++ b/src/service/messenger/gnunet-service-messenger_member_session.c
@@ -0,0 +1,866 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2021--2023 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_member_session.c
23 * @brief GNUnet MESSENGER service
24 */
25
26#include "gnunet-service-messenger_member_session.h"
27
28#include "gnunet-service-messenger_room.h"
29#include "gnunet-service-messenger_message_store.h"
30
31#include "messenger_api_contact_store.h"
32
33struct GNUNET_MESSENGER_MemberSession*
34create_member_session (struct GNUNET_MESSENGER_Member *member,
35 const struct GNUNET_CRYPTO_PublicKey *pubkey)
36{
37 if ((! member) || (! pubkey) || (! (member->store)))
38 return NULL;
39
40 struct GNUNET_MESSENGER_MemberSession *session = GNUNET_new (struct
41 GNUNET_MESSENGER_MemberSession);
42 session->member = member;
43
44 GNUNET_memcpy (&(session->public_key), pubkey, sizeof(session->public_key));
45
46 get_context_from_member (
47 get_member_session_key (session),
48 get_member_session_id (session),
49 &(session->context)
50 );
51
52 struct GNUNET_MESSENGER_ContactStore *store = get_member_contact_store (
53 session->member->store);
54
55 session->contact = get_store_contact (
56 store,
57 get_member_session_context (session),
58 get_member_session_public_key (session)
59 );
60
61 if (! (session->contact))
62 {
63 GNUNET_free (session);
64 return NULL;
65 }
66
67 increase_contact_rc (session->contact);
68
69 session->history = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
70
71 init_list_messages (&(session->messages));
72
73 session->prev = NULL;
74 session->next = NULL;
75
76 session->start = GNUNET_TIME_absolute_get ();
77
78 session->closed = GNUNET_NO;
79 session->completed = GNUNET_NO;
80
81 return session;
82}
83
84
85static void
86check_member_session_completion (struct GNUNET_MESSENGER_MemberSession *session)
87{
88 GNUNET_assert (session);
89
90 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
91 "Check session history (%s) for completion.\n",
92 GNUNET_sh2s (get_member_session_id (session)));
93
94 if (! session->messages.tail)
95 {
96 session->completed = GNUNET_YES;
97 goto completion;
98 }
99
100 const struct GNUNET_HashCode *start = &(session->messages.head->hash);
101 const struct GNUNET_HashCode *end = &(session->messages.tail->hash);
102
103 struct GNUNET_MESSENGER_ListMessages level;
104 init_list_messages (&level);
105
106 add_to_list_messages (&level, end);
107
108 struct GNUNET_MESSENGER_MessageStore *store = get_srv_room_message_store (
109 session->member->store->room);
110
111 struct GNUNET_MESSENGER_ListMessages list;
112 init_list_messages (&list);
113
114 while (level.head)
115 {
116 struct GNUNET_MESSENGER_ListMessage *element;
117
118 for (element = level.head; element; element = element->next)
119 {
120 const struct GNUNET_MESSENGER_MessageLink *link = get_store_message_link (
121 store, &(element->hash), GNUNET_NO
122 );
123
124 if (! link)
125 continue;
126
127 add_to_list_messages (&list, &(link->first));
128
129 if (GNUNET_YES == link->multiple)
130 add_to_list_messages (&list, &(link->second));
131 }
132
133 clear_list_messages (&level);
134
135 for (element = list.head; element; element = element->next)
136 if (GNUNET_YES == check_member_session_history (session, &(element->hash),
137 GNUNET_YES))
138 break;
139
140 if (element)
141 if (0 != GNUNET_CRYPTO_hash_cmp (&(element->hash), start))
142 add_to_list_messages (&level, &(element->hash));
143 else
144 session->completed = GNUNET_YES;
145 else
146 copy_list_messages (&level, &list);
147
148 clear_list_messages (&list);
149 }
150
151completion:
152 if (GNUNET_YES == is_member_session_completed (session))
153 {
154 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Completed session history (%s)\n",
155 GNUNET_sh2s (get_member_session_id (session)));
156
157 struct GNUNET_MESSENGER_ContactStore *store = get_member_contact_store (
158 session->member->store);
159
160 if ((session->contact) && (GNUNET_YES == decrease_contact_rc (
161 session->contact)))
162 remove_store_contact (
163 store,
164 session->contact,
165 get_member_session_context (session)
166 );
167
168 session->contact = NULL;
169 }
170}
171
172
173static enum GNUNET_GenericReturnValue
174iterate_copy_history (void *cls,
175 const struct GNUNET_HashCode *key,
176 void *value)
177{
178 struct GNUNET_MESSENGER_MemberSession *next = cls;
179
180 GNUNET_CONTAINER_multihashmap_put (next->history, key, (value? next : NULL),
181 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
182
183 return GNUNET_YES;
184}
185
186
187struct GNUNET_MESSENGER_MemberSession*
188switch_member_session (struct GNUNET_MESSENGER_MemberSession *session,
189 const struct GNUNET_MESSENGER_Message *message,
190 const struct GNUNET_HashCode *hash)
191{
192 if ((! session) || (! message) || (! hash))
193 return NULL;
194
195 GNUNET_assert ((GNUNET_MESSENGER_KIND_ID == message->header.kind) ||
196 (GNUNET_MESSENGER_KIND_KEY == message->header.kind));
197
198 struct GNUNET_MESSENGER_MemberSession *next = GNUNET_new (struct
199 GNUNET_MESSENGER_MemberSession);
200
201 if (GNUNET_MESSENGER_KIND_ID == message->header.kind)
202 next->member = add_store_member (session->member->store,
203 &(message->body.id.id));
204 else
205 next->member = session->member;
206
207 if (GNUNET_MESSENGER_KIND_KEY == message->header.kind)
208 GNUNET_memcpy (&(next->public_key), &(message->body.key.key),
209 sizeof(next->public_key));
210 else
211 GNUNET_memcpy (&(next->public_key), get_member_session_public_key (session),
212 sizeof(next->public_key));
213
214 get_context_from_member (
215 get_member_session_key (next),
216 get_member_session_id (next),
217 &(next->context)
218 );
219
220 update_store_contact (
221 get_member_contact_store (next->member->store),
222 get_member_session_contact (session),
223 get_member_session_context (session),
224 get_member_session_context (next),
225 get_member_session_public_key (next)
226 );
227
228 next->contact = get_member_session_contact (session);
229
230 if (! (next->contact))
231 {
232 GNUNET_free (next);
233 return NULL;
234 }
235
236 increase_contact_rc (next->contact);
237
238 next->history = GNUNET_CONTAINER_multihashmap_create (
239 GNUNET_CONTAINER_multihashmap_size (session->history), GNUNET_NO
240 );
241
242 GNUNET_CONTAINER_multihashmap_iterate (session->history, iterate_copy_history,
243 next);
244
245 init_list_messages (&(next->messages));
246 copy_list_messages (&(next->messages), &(session->messages));
247
248 session->next = next;
249 next->prev = session;
250 next->next = NULL;
251
252 next->start = GNUNET_TIME_absolute_get ();
253
254 session->closed = GNUNET_YES;
255 next->closed = GNUNET_NO;
256 next->completed = GNUNET_NO;
257
258 check_member_session_completion (session);
259
260 return next;
261}
262
263
264void
265destroy_member_session (struct GNUNET_MESSENGER_MemberSession *session)
266{
267 GNUNET_assert (session);
268
269 GNUNET_CONTAINER_multihashmap_destroy (session->history);
270
271 clear_list_messages (&(session->messages));
272
273 struct GNUNET_MESSENGER_Contact *contact = get_member_session_contact (
274 session);
275
276 if ((contact) && (GNUNET_YES == decrease_contact_rc (contact)))
277 remove_store_contact (
278 get_member_contact_store (session->member->store),
279 contact,
280 get_member_session_context (session)
281 );
282
283 GNUNET_free (session);
284}
285
286
287enum GNUNET_GenericReturnValue
288reset_member_session (struct GNUNET_MESSENGER_MemberSession *session,
289 const struct GNUNET_HashCode *hash)
290{
291 GNUNET_assert ((session) && (hash));
292
293 struct GNUNET_MESSENGER_ContactStore *store = get_member_contact_store (
294 session->member->store);
295 struct GNUNET_MESSENGER_Contact *contact = get_store_contact (
296 store,
297 get_member_session_context (session),
298 get_member_session_public_key (session)
299 );
300
301 if (! contact)
302 return GNUNET_SYSERR;
303
304 if (contact == session->contact)
305 goto clear_messages;
306
307 session->contact = contact;
308 increase_contact_rc (session->contact);
309
310clear_messages:
311 clear_list_messages (&(session->messages));
312 add_to_list_messages (&(session->messages), hash);
313
314 session->next = NULL;
315 session->closed = GNUNET_NO;
316 session->completed = GNUNET_NO;
317
318 return GNUNET_OK;
319}
320
321
322void
323close_member_session (struct GNUNET_MESSENGER_MemberSession *session)
324{
325 GNUNET_assert (session);
326
327 session->closed = GNUNET_YES;
328 check_member_session_completion (session);
329}
330
331
332enum GNUNET_GenericReturnValue
333is_member_session_closed (const struct GNUNET_MESSENGER_MemberSession *session)
334{
335 GNUNET_assert (session);
336
337 return session->closed;
338}
339
340
341enum GNUNET_GenericReturnValue
342is_member_session_completed (const struct
343 GNUNET_MESSENGER_MemberSession *session)
344{
345 GNUNET_assert (session);
346
347 return session->completed;
348}
349
350
351struct GNUNET_TIME_Absolute
352get_member_session_start (const struct GNUNET_MESSENGER_MemberSession *session)
353{
354 GNUNET_assert (session);
355
356 if (session->prev)
357 return get_member_session_start (session->prev);
358
359 return session->start;
360}
361
362
363const struct GNUNET_HashCode*
364get_member_session_key (const struct GNUNET_MESSENGER_MemberSession *session)
365{
366 GNUNET_assert ((session) && (session->member));
367
368 return get_member_store_key (session->member->store);
369}
370
371
372const struct GNUNET_ShortHashCode*
373get_member_session_id (const struct GNUNET_MESSENGER_MemberSession *session)
374{
375 GNUNET_assert (session);
376
377 return get_member_id (session->member);
378}
379
380
381const struct GNUNET_CRYPTO_PublicKey*
382get_member_session_public_key (const struct
383 GNUNET_MESSENGER_MemberSession *session)
384{
385 GNUNET_assert (session);
386
387 return &(session->public_key);
388}
389
390
391const struct GNUNET_HashCode*
392get_member_session_context (const struct
393 GNUNET_MESSENGER_MemberSession *session)
394{
395 GNUNET_assert (session);
396
397 return &(session->context);
398}
399
400
401struct GNUNET_MESSENGER_Contact*
402get_member_session_contact (struct GNUNET_MESSENGER_MemberSession *session)
403{
404 GNUNET_assert (session);
405
406 return session->contact;
407}
408
409
410enum GNUNET_GenericReturnValue
411verify_member_session_as_sender (const struct
412 GNUNET_MESSENGER_MemberSession *session,
413 const struct GNUNET_MESSENGER_Message *message,
414 const struct GNUNET_HashCode *hash)
415{
416 GNUNET_assert ((session) && (message) && (hash));
417
418 if (GNUNET_YES == is_member_session_completed (session))
419 {
420 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Check message (%s) using history!\n",
421 GNUNET_h2s (hash));
422
423 if (GNUNET_YES == check_member_session_history (session, hash, GNUNET_YES))
424 return GNUNET_OK;
425 else
426 return GNUNET_SYSERR;
427 }
428
429 if (0 != GNUNET_memcmp (get_member_session_id (session),
430 &(message->header.sender_id)))
431 return GNUNET_SYSERR;
432
433 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Check message (%s) using key: %s\n",
434 GNUNET_h2s (hash),
435 GNUNET_CRYPTO_public_key_to_string (
436 get_member_session_public_key (session)));
437
438 return verify_message (message, hash, get_member_session_public_key (
439 session));
440}
441
442
443enum GNUNET_GenericReturnValue
444check_member_session_history (const struct
445 GNUNET_MESSENGER_MemberSession *session,
446 const struct GNUNET_HashCode *hash,
447 enum GNUNET_GenericReturnValue ownership)
448{
449 GNUNET_assert ((session) && (hash));
450
451 if (GNUNET_YES == ownership)
452 return (NULL != GNUNET_CONTAINER_multihashmap_get (session->history, hash)?
453 GNUNET_YES : GNUNET_NO);
454 else
455 return GNUNET_CONTAINER_multihashmap_contains (session->history, hash);
456}
457
458
459static void
460update_member_chain_history (struct GNUNET_MESSENGER_MemberSession *session,
461 const struct GNUNET_HashCode *hash,
462 enum GNUNET_GenericReturnValue ownership)
463{
464 GNUNET_assert ((session) && (hash));
465
466 if ((GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (session->history, hash,
467 (GNUNET_YES == ownership?
468 session : NULL),
469 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
470 && (session->next))
471 update_member_chain_history (session->next, hash, ownership);
472}
473
474
475void
476update_member_session_history (struct GNUNET_MESSENGER_MemberSession *session,
477 const struct GNUNET_MESSENGER_Message *message,
478 const struct GNUNET_HashCode *hash)
479{
480 GNUNET_assert ((session) && (message) && (hash));
481
482 if (GNUNET_YES == is_member_session_completed (session))
483 return;
484
485 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
486 "Updating sessions history (%s) += (%s)\n",
487 GNUNET_sh2s (get_member_session_id (session)), GNUNET_h2s (hash));
488
489 if (GNUNET_OK == verify_member_session_as_sender (session, message, hash))
490 {
491 if (GNUNET_YES == is_message_session_bound (message))
492 add_to_list_messages (&(session->messages), hash);
493
494 update_member_chain_history (session, hash, GNUNET_YES);
495 }
496 else
497 update_member_chain_history (session, hash, GNUNET_NO);
498
499 if (GNUNET_YES == session->closed)
500 check_member_session_completion (session);
501}
502
503
504static void
505clear_member_chain_history (struct GNUNET_MESSENGER_MemberSession *session,
506 const struct GNUNET_HashCode *hash)
507{
508 GNUNET_assert ((session) && (hash));
509
510 if ((0 < GNUNET_CONTAINER_multihashmap_remove_all (session->history, hash)) &&
511 (session->next))
512 clear_member_session_history (session->next, hash);
513}
514
515
516void
517clear_member_session_history (struct GNUNET_MESSENGER_MemberSession *session,
518 const struct GNUNET_HashCode *hash)
519{
520 GNUNET_assert ((session) && (hash));
521
522 clear_member_chain_history (session, hash);
523}
524
525
526struct GNUNET_MESSENGER_MemberSessionHistoryEntry
527{
528 struct GNUNET_HashCode hash;
529 unsigned char ownership;
530};
531
532static void
533load_member_session_history (struct GNUNET_MESSENGER_MemberSession *session,
534 const char *path)
535{
536 GNUNET_assert ((session) && (path));
537
538 if (GNUNET_YES != GNUNET_DISK_file_test (path))
539 return;
540
541 enum GNUNET_DISK_AccessPermissions permission = (GNUNET_DISK_PERM_USER_READ
542 | GNUNET_DISK_PERM_USER_WRITE
543 );
544
545 struct GNUNET_DISK_FileHandle *handle = GNUNET_DISK_file_open (
546 path, GNUNET_DISK_OPEN_READ, permission
547 );
548
549 if (! handle)
550 return;
551
552 GNUNET_DISK_file_seek (handle, 0, GNUNET_DISK_SEEK_SET);
553
554 struct GNUNET_MESSENGER_MemberSessionHistoryEntry entry;
555 ssize_t len;
556
557 enum GNUNET_GenericReturnValue status;
558
559 do {
560 len = GNUNET_DISK_file_read (handle, &(entry.hash), sizeof(entry.hash));
561
562 if (len != sizeof(entry.hash))
563 break;
564
565 len = GNUNET_DISK_file_read (handle, &(entry.ownership),
566 sizeof(entry.ownership));
567
568 if (len != sizeof(entry.ownership))
569 break;
570
571 status = GNUNET_CONTAINER_multihashmap_put (session->history, &(entry.hash),
572 (entry.ownership? session :
573 NULL),
574 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
575 } while (status == GNUNET_OK);
576
577 GNUNET_DISK_file_close (handle);
578}
579
580
581void
582load_member_session (struct GNUNET_MESSENGER_Member *member,
583 const char *directory)
584{
585 GNUNET_assert ((member) && (directory));
586
587 char *config_file;
588 GNUNET_asprintf (&config_file, "%s%s", directory, "session.cfg");
589
590 struct GNUNET_MESSENGER_MemberSession *session = NULL;
591
592 if (GNUNET_YES != GNUNET_DISK_file_test (config_file))
593 goto free_config;
594
595 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
596 "Load session configuration of member: %s\n", config_file);
597
598 struct GNUNET_CONFIGURATION_Handle *cfg = GNUNET_CONFIGURATION_create ();
599
600 if (GNUNET_OK == GNUNET_CONFIGURATION_parse (cfg, config_file))
601 {
602 char *key_data;
603
604 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "session",
605 "key", &key_data))
606 goto destroy_config;
607
608 struct GNUNET_CRYPTO_PublicKey key;
609
610 enum GNUNET_GenericReturnValue key_return =
611 GNUNET_CRYPTO_public_key_from_string (key_data, &key);
612
613 GNUNET_free (key_data);
614
615 if (GNUNET_OK != key_return)
616 goto destroy_config;
617
618 session = create_member_session (member, &key);
619
620 unsigned long long numeric_value;
621
622 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (cfg, "session",
623 "start",
624 &numeric_value))
625 session->start.abs_value_us = numeric_value;
626
627 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (cfg, "session",
628 "closed",
629 &numeric_value))
630 session->closed = (GNUNET_YES == numeric_value? GNUNET_YES : GNUNET_NO);
631
632 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (cfg, "session",
633 "completed",
634 &numeric_value))
635 session->completed = (GNUNET_YES == numeric_value? GNUNET_YES :
636 GNUNET_NO);
637 }
638
639destroy_config:
640 GNUNET_CONFIGURATION_destroy (cfg);
641
642free_config:
643 GNUNET_free (config_file);
644
645 if (! session)
646 return;
647
648 char *history_file;
649 GNUNET_asprintf (&history_file, "%s%s", directory, "history.map");
650
651 load_member_session_history (session, history_file);
652 GNUNET_free (history_file);
653
654 char *messages_file;
655 GNUNET_asprintf (&messages_file, "%s%s", directory, "messages.list");
656
657 load_list_messages (&(session->messages), messages_file);
658 GNUNET_free (messages_file);
659
660 add_member_session (member, session);
661}
662
663
664static struct GNUNET_MESSENGER_MemberSession*
665get_cycle_safe_next_session (struct GNUNET_MESSENGER_MemberSession *session,
666 struct GNUNET_MESSENGER_MemberSession *next)
667{
668 if (! next)
669 return NULL;
670
671 struct GNUNET_MESSENGER_MemberSession *check = next;
672
673 do {
674 if (check == session)
675 return NULL;
676
677 check = check->next;
678 } while (check);
679
680 return next;
681}
682
683
684void
685load_member_session_next (struct GNUNET_MESSENGER_MemberSession *session,
686 const char *directory)
687{
688 GNUNET_assert ((session) && (directory));
689
690 char *config_file;
691 GNUNET_asprintf (&config_file, "%s%s", directory, "session.cfg");
692
693 if (GNUNET_YES != GNUNET_DISK_file_test (config_file))
694 goto free_config;
695
696 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
697 "Load next session configuration of member: %s\n", config_file);
698
699 struct GNUNET_CONFIGURATION_Handle *cfg = GNUNET_CONFIGURATION_create ();
700
701 if (GNUNET_OK == GNUNET_CONFIGURATION_parse (cfg, config_file))
702 {
703 char *key_data;
704
705 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "session",
706 "next_key",
707 &key_data))
708 goto destroy_config;
709
710 struct GNUNET_CRYPTO_PublicKey next_key;
711
712 enum GNUNET_GenericReturnValue key_return =
713 GNUNET_CRYPTO_public_key_from_string (key_data, &next_key);
714
715 GNUNET_free (key_data);
716
717 if (GNUNET_OK != key_return)
718 goto destroy_config;
719
720 struct GNUNET_ShortHashCode next_id;
721
722 if (GNUNET_OK != GNUNET_CONFIGURATION_get_data (cfg, "session", "next_id",
723 &next_id, sizeof(next_id)))
724 goto destroy_config;
725
726 struct GNUNET_MESSENGER_Member *member = get_store_member (
727 session->member->store, &next_id);
728
729 session->next = get_cycle_safe_next_session (
730 session, member? get_member_session (member, &next_key) : NULL
731 );
732
733 if (session->next)
734 session->next->prev = session;
735 }
736
737destroy_config:
738 GNUNET_CONFIGURATION_destroy (cfg);
739
740free_config:
741 GNUNET_free (config_file);
742}
743
744
745static enum GNUNET_GenericReturnValue
746iterate_save_member_session_history_hentries (void *cls,
747 const struct GNUNET_HashCode *key,
748 void *value)
749{
750 struct GNUNET_DISK_FileHandle *handle = cls;
751 unsigned char ownership = value? GNUNET_YES : GNUNET_NO;
752
753 GNUNET_DISK_file_write (handle, key, sizeof(*key));
754 GNUNET_DISK_file_write (handle, &ownership, sizeof(ownership));
755
756 return GNUNET_YES;
757}
758
759
760static void
761save_member_session_history (struct GNUNET_MESSENGER_MemberSession *session,
762 const char *path)
763{
764 GNUNET_assert ((session) && (path));
765
766 enum GNUNET_DISK_AccessPermissions permission = (GNUNET_DISK_PERM_USER_READ
767 | GNUNET_DISK_PERM_USER_WRITE
768 );
769
770 struct GNUNET_DISK_FileHandle *handle = GNUNET_DISK_file_open (
771 path, GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_WRITE, permission
772 );
773
774 if (! handle)
775 return;
776
777 GNUNET_DISK_file_seek (handle, 0, GNUNET_DISK_SEEK_SET);
778
779 GNUNET_CONTAINER_multihashmap_iterate (
780 session->history,
781 iterate_save_member_session_history_hentries,
782 handle
783 );
784
785 GNUNET_DISK_file_sync (handle);
786 GNUNET_DISK_file_close (handle);
787}
788
789
790void
791save_member_session (struct GNUNET_MESSENGER_MemberSession *session,
792 const char *directory)
793{
794 GNUNET_assert ((session) && (directory));
795
796 char *config_file;
797 GNUNET_asprintf (&config_file, "%s%s", directory, "session.cfg");
798
799 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
800 "Save session configuration of member: %s\n", config_file);
801
802 struct GNUNET_CONFIGURATION_Handle *cfg = GNUNET_CONFIGURATION_create ();
803
804 char *key_data = GNUNET_CRYPTO_public_key_to_string (
805 get_member_session_public_key (session));
806
807 if (key_data)
808 {
809 GNUNET_CONFIGURATION_set_value_string (cfg, "session", "key", key_data);
810
811 GNUNET_free (key_data);
812 }
813
814 if (session->next)
815 {
816 const struct GNUNET_ShortHashCode *next_id = get_member_session_id (
817 session->next);
818
819 char *next_id_data = GNUNET_STRINGS_data_to_string_alloc (next_id,
820 sizeof(*next_id));
821
822 if (next_id_data)
823 {
824 GNUNET_CONFIGURATION_set_value_string (cfg, "session", "next_id",
825 next_id_data);
826
827 GNUNET_free (next_id_data);
828 }
829
830 key_data = GNUNET_CRYPTO_public_key_to_string (
831 get_member_session_public_key (session->next));
832
833 if (key_data)
834 {
835 GNUNET_CONFIGURATION_set_value_string (cfg, "session", "next_key",
836 key_data);
837
838 GNUNET_free (key_data);
839 }
840 }
841
842 GNUNET_CONFIGURATION_set_value_number (cfg, "session", "start",
843 session->start.abs_value_us);
844
845 GNUNET_CONFIGURATION_set_value_number (cfg, "session", "closed",
846 session->closed);
847 GNUNET_CONFIGURATION_set_value_number (cfg, "session", "completed",
848 session->completed);
849
850 GNUNET_CONFIGURATION_write (cfg, config_file);
851 GNUNET_CONFIGURATION_destroy (cfg);
852
853 GNUNET_free (config_file);
854
855 char *history_file;
856 GNUNET_asprintf (&history_file, "%s%s", directory, "history.map");
857
858 save_member_session_history (session, history_file);
859 GNUNET_free (history_file);
860
861 char *messages_file;
862 GNUNET_asprintf (&messages_file, "%s%s", directory, "messages.list");
863
864 save_list_messages (&(session->messages), messages_file);
865 GNUNET_free (messages_file);
866}
diff --git a/src/service/messenger/gnunet-service-messenger_member_session.h b/src/service/messenger/gnunet-service-messenger_member_session.h
new file mode 100644
index 000000000..8cd944afa
--- /dev/null
+++ b/src/service/messenger/gnunet-service-messenger_member_session.h
@@ -0,0 +1,296 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2021--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_member_session.h
23 * @brief GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_SERVICE_MESSENGER_MEMBER_SESSION_H
27#define GNUNET_SERVICE_MESSENGER_MEMBER_SESSION_H
28
29#include "gnunet_util_lib.h"
30#include "gnunet_time_lib.h"
31
32#include "gnunet-service-messenger_list_messages.h"
33#include "gnunet-service-messenger_member.h"
34
35#include "messenger_api_contact.h"
36
37struct GNUNET_MESSENGER_MemberSession
38{
39 struct GNUNET_MESSENGER_Member *member;
40
41 struct GNUNET_CRYPTO_PublicKey public_key;
42 struct GNUNET_HashCode context;
43
44 struct GNUNET_MESSENGER_Contact *contact;
45
46 struct GNUNET_CONTAINER_MultiHashMap *history;
47 struct GNUNET_MESSENGER_ListMessages messages;
48
49 struct GNUNET_MESSENGER_MemberSession *prev;
50 struct GNUNET_MESSENGER_MemberSession *next;
51
52 struct GNUNET_TIME_Absolute start;
53
54 enum GNUNET_GenericReturnValue closed;
55 enum GNUNET_GenericReturnValue completed;
56};
57
58/**
59 * Creates and allocates a new member session of a <i>member</i> with a given
60 * public key.
61 *
62 * If the creation fails, NULL gets returned.
63 *
64 * @param[in,out] member Member
65 * @param[in] pubkey Public key
66 * @return New member session
67 */
68struct GNUNET_MESSENGER_MemberSession*
69create_member_session (struct GNUNET_MESSENGER_Member *member,
70 const struct GNUNET_CRYPTO_PublicKey *pubkey);
71
72/**
73 * Creates and allocates a new member session closing and replacing a given
74 * other <i>session</i> of the same member. The new session could have significant
75 * changes to the members public key or its member id depending on the used
76 * <i>message</i> to switch session. The new session will be linked to the old
77 * one.
78 *
79 * @param[in,out] session Old member session
80 * @param[in] message Message
81 * @param[in] hash Hash of message
82 * @return New member session
83 */
84struct GNUNET_MESSENGER_MemberSession*
85switch_member_session (struct GNUNET_MESSENGER_MemberSession *session,
86 const struct GNUNET_MESSENGER_Message *message,
87 const struct GNUNET_HashCode *hash);
88
89/**
90 * Destroys a member session and frees its memory fully.
91 *
92 * @param[in,out] session Member session
93 */
94void
95destroy_member_session (struct GNUNET_MESSENGER_MemberSession *session);
96
97/**
98 * Resets a given member <i>session</i> which re-opens a member
99 * session for new usage. Every connection to other sessions will be
100 * be dropped. The member sessions messages will be cleared but old
101 * history from uncompleted sessions however can be reused!
102 *
103 * @param[in,out] session Member session
104 * @param[in] hash Hash of initial message (JOIN message!)
105 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
106 */
107enum GNUNET_GenericReturnValue
108reset_member_session (struct GNUNET_MESSENGER_MemberSession *session,
109 const struct GNUNET_HashCode *hash);
110
111/**
112 * Closes a given member <i>session</i> which opens the request
113 * for completion of the given member session.
114 *
115 * Closing a session may complete a session and can't be used without
116 * a reset! ( @see #reset_member_session() )
117 *
118 * @param[in,out] session Member session
119 */
120void
121close_member_session (struct GNUNET_MESSENGER_MemberSession *session);
122
123/**
124 * Returns if the given member <i>session</i> has been closed.
125 *
126 * @param[in] session Member session
127 * @return #GNUNET_YES or #GNUNET_NO
128 */
129enum GNUNET_GenericReturnValue
130is_member_session_closed (const struct GNUNET_MESSENGER_MemberSession *session);
131
132/**
133 * Returns if the given member <i>session</i> has been completed.
134 *
135 * A completed member session can't verify any message as its own and
136 * it won't add any message to its history.
137 *
138 * @param[in] session Member session
139 * @return #GNUNET_YES or #GNUNET_NO
140 */
141enum GNUNET_GenericReturnValue
142is_member_session_completed (const struct
143 GNUNET_MESSENGER_MemberSession *session);
144
145/**
146 * Returns the timestamp of the member <i>session</i>'s start.
147 *
148 * @param[in] session Member session
149 * @return Absolute timestamp
150 */
151struct GNUNET_TIME_Absolute
152get_member_session_start (const struct GNUNET_MESSENGER_MemberSession *session);
153
154/**
155 * Returns the key of the room a given member <i>session</i> belongs to.
156 *
157 * @param[in] session Member session
158 * @return Key of room
159 */
160const struct GNUNET_HashCode*
161get_member_session_key (const struct GNUNET_MESSENGER_MemberSession *session);
162
163/**
164 * Returns the member id of a given member <i>session</i>.
165 *
166 * @param[in] session Member session
167 * @return Member id
168 */
169const struct GNUNET_ShortHashCode*
170get_member_session_id (const struct GNUNET_MESSENGER_MemberSession *session);
171
172/**
173 * Returns the public key of a given member <i>session</i>.
174 *
175 * @param[in] session Member session
176 * @return Public key
177 */
178const struct GNUNET_CRYPTO_PublicKey*
179get_member_session_public_key (const struct
180 GNUNET_MESSENGER_MemberSession *session);
181
182/**
183 * Returns the member context of a given member <i>session</i>.
184 *
185 * @param[in] session Member session
186 * @return Member context as hash
187 */
188const struct GNUNET_HashCode*
189get_member_session_context (const struct
190 GNUNET_MESSENGER_MemberSession *session);
191
192/**
193 * Returns the contact which is connected to a given member <i>session</i>.
194 *
195 * @param[in] session Member session
196 * @return Contact
197 */
198struct GNUNET_MESSENGER_Contact*
199get_member_session_contact (struct GNUNET_MESSENGER_MemberSession *session);
200
201/**
202 * Verifies a given member <i>session</i> as sender of a selected <i>message</i> and
203 * its <i>hash</i>. The function returns #GNUNET_OK if the message session is verified
204 * as sender, otherwise #GNUNET_SYSERR.
205 *
206 * @see #is_member_session_completed() for verification.
207 *
208 * @param[in] session Member session
209 * @param[in] message Message
210 * @param[in] hash Hash of message
211 * @return #GNUNET_OK on success, otherwise #GNUNET_SYSERR
212 */
213enum GNUNET_GenericReturnValue
214verify_member_session_as_sender (const struct
215 GNUNET_MESSENGER_MemberSession *session,
216 const struct GNUNET_MESSENGER_Message *message,
217 const struct GNUNET_HashCode *hash);
218
219/**
220 * Checks the history of a <i>session</i> for a specific message which is identified
221 * by its <i>hash</i> and if the <i>ownership</i> flag is set, if the message is
222 * owned by the sessions contact.
223 *
224 * @param[in] session Member session
225 * @param[in] hash Hash of message
226 * @param[in] ownership Ownership flag
227 * @return #GNUNET_YES if found, otherwise #GNUNET_NO
228 */
229enum GNUNET_GenericReturnValue
230check_member_session_history (const struct
231 GNUNET_MESSENGER_MemberSession *session,
232 const struct GNUNET_HashCode *hash,
233 enum GNUNET_GenericReturnValue ownership);
234
235/**
236 * Adds a given <i>message</i> to the history of a <i>session</i> using the messages
237 * <i>hash</i>. The ownership will be set automatically.
238 *
239 * @see #is_member_session_completed() for updating a history.
240 *
241 * @param[in,out] session Member session
242 * @param[in] message Message
243 * @param[in] hash Hash of message
244 */
245void
246update_member_session_history (struct GNUNET_MESSENGER_MemberSession *session,
247 const struct GNUNET_MESSENGER_Message *message,
248 const struct GNUNET_HashCode *hash);
249
250/**
251 * Removes a message from the history of a <i>session</i> using the messages
252 * <i>hash</i>.
253 *
254 * @param[in,out] session Member session
255 * @param[in] hash Hash of message
256 */
257void
258clear_member_session_history (struct GNUNET_MESSENGER_MemberSession *session,
259 const struct GNUNET_HashCode *hash);
260
261/**
262 * Loads data from a <i>directory</i> into a new allocated and created member
263 * session of a <i>member</i> if the required information can be read from the
264 * content of the given directory.
265 *
266 * @param[out] member Member
267 * @param[in] directory Path to a directory
268 */
269void
270load_member_session (struct GNUNET_MESSENGER_Member *member,
271 const char *directory);
272
273/**
274 * Loads the connection from one <i>session</i> to another through the
275 * next attribute. Necessary information will be loaded from a configuration
276 * file inside of a given <i>directory</i>.
277 *
278 * @param[in,out] session Member session
279 * @param[in] directory Path to a directory
280 */
281void
282load_member_session_next (struct GNUNET_MESSENGER_MemberSession *session,
283 const char *directory);
284
285/**
286 * Saves data from a member <i>session</i> into a <i>directory</i> which can be
287 * load to restore the member session completely.
288 *
289 * @param[in] session Member session
290 * @param[in] directory Path to a directory
291 */
292void
293save_member_session (struct GNUNET_MESSENGER_MemberSession *session,
294 const char *directory);
295
296#endif //GNUNET_SERVICE_MESSENGER_MEMBER_SESSION_H
diff --git a/src/service/messenger/gnunet-service-messenger_member_store.c b/src/service/messenger/gnunet-service-messenger_member_store.c
new file mode 100644
index 000000000..77e816c2e
--- /dev/null
+++ b/src/service/messenger/gnunet-service-messenger_member_store.c
@@ -0,0 +1,315 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_member_store.c
23 * @brief GNUnet MESSENGER service
24 */
25
26#include "platform.h"
27#include "gnunet-service-messenger_member_store.h"
28
29#include "gnunet-service-messenger_member.h"
30#include "gnunet-service-messenger_service.h"
31#include "gnunet-service-messenger_room.h"
32
33#include "messenger_api_message.h"
34
35void
36init_member_store (struct GNUNET_MESSENGER_MemberStore *store,
37 struct GNUNET_MESSENGER_SrvRoom *room)
38{
39 GNUNET_assert ((store) && (room));
40
41 store->room = room;
42 store->members = GNUNET_CONTAINER_multishortmap_create (8, GNUNET_NO);
43}
44
45
46static enum GNUNET_GenericReturnValue
47iterate_destroy_members (void *cls,
48 const struct GNUNET_ShortHashCode *key,
49 void *value)
50{
51 struct GNUNET_MESSENGER_Member *member = value;
52 destroy_member (member);
53 return GNUNET_YES;
54}
55
56
57void
58clear_member_store (struct GNUNET_MESSENGER_MemberStore *store)
59{
60 GNUNET_assert ((store) && (store->members));
61
62 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Clear member store of room: %s\n",
63 GNUNET_h2s (get_srv_room_key (store->room)));
64
65 GNUNET_CONTAINER_multishortmap_iterate (store->members,
66 iterate_destroy_members, NULL);
67 GNUNET_CONTAINER_multishortmap_destroy (store->members);
68}
69
70
71struct GNUNET_MESSENGER_ContactStore*
72get_member_contact_store (struct GNUNET_MESSENGER_MemberStore *store)
73{
74 GNUNET_assert ((store) && (store->room));
75
76 struct GNUNET_MESSENGER_SrvRoom *room = store->room;
77
78 return get_service_contact_store (room->service);
79}
80
81
82const struct GNUNET_HashCode*
83get_member_store_key (const struct GNUNET_MESSENGER_MemberStore *store)
84{
85 GNUNET_assert (store);
86
87 return get_srv_room_key ((const struct
88 GNUNET_MESSENGER_SrvRoom*) store->room);
89}
90
91
92static enum GNUNET_GenericReturnValue
93callback_scan_for_members (void *cls,
94 const char *filename)
95{
96 struct GNUNET_MESSENGER_MemberStore *store = cls;
97
98 if (GNUNET_YES == GNUNET_DISK_directory_test (filename, GNUNET_YES))
99 {
100 char *directory;
101
102 GNUNET_asprintf (&directory, "%s%c", filename, DIR_SEPARATOR);
103
104 load_member (store, directory);
105
106 GNUNET_free (directory);
107 }
108
109 return GNUNET_OK;
110}
111
112
113static enum GNUNET_GenericReturnValue
114iterate_load_next_member_sessions (void *cls,
115 const struct GNUNET_ShortHashCode *id,
116 void *value)
117{
118 const char *sync_dir = cls;
119
120 struct GNUNET_MESSENGER_Member *member = value;
121
122 if (! member)
123 return GNUNET_YES;
124
125 char *member_dir;
126 GNUNET_asprintf (&member_dir, "%s%s%c", sync_dir, GNUNET_sh2s (id),
127 DIR_SEPARATOR);
128
129 if (GNUNET_YES == GNUNET_DISK_directory_test (member_dir, GNUNET_YES))
130 load_member_next_sessions (member, member_dir);
131
132 GNUNET_free (member_dir);
133 return GNUNET_YES;
134}
135
136
137static enum GNUNET_GenericReturnValue
138iterate_sync_member_contacts (void *cls,
139 const struct GNUNET_ShortHashCode *id,
140 void *value)
141{
142 struct GNUNET_MESSENGER_Member *member = value;
143
144 if (! member)
145 return GNUNET_YES;
146
147 sync_member_contacts (member);
148 return GNUNET_YES;
149}
150
151
152void
153load_member_store (struct GNUNET_MESSENGER_MemberStore *store,
154 const char *directory)
155{
156 GNUNET_assert ((store) && (directory));
157
158 char *scan_dir;
159 GNUNET_asprintf (&scan_dir, "%s%s%c", directory, "members", DIR_SEPARATOR);
160
161 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Load member store from directory: %s\n",
162 scan_dir);
163
164 if (GNUNET_OK == GNUNET_DISK_directory_test (scan_dir, GNUNET_YES))
165 GNUNET_DISK_directory_scan (scan_dir, callback_scan_for_members, store);
166
167 GNUNET_CONTAINER_multishortmap_iterate (store->members,
168 iterate_load_next_member_sessions,
169 scan_dir);
170 GNUNET_CONTAINER_multishortmap_iterate (store->members,
171 iterate_sync_member_contacts, NULL);
172
173 GNUNET_free (scan_dir);
174}
175
176
177static enum GNUNET_GenericReturnValue
178iterate_save_members (void *cls,
179 const struct GNUNET_ShortHashCode *id,
180 void *value)
181{
182 const char *save_dir = cls;
183
184 struct GNUNET_MESSENGER_Member *member = value;
185
186 if (! member)
187 return GNUNET_YES;
188
189 char *member_dir;
190 GNUNET_asprintf (&member_dir, "%s%s%c", save_dir, GNUNET_sh2s (id),
191 DIR_SEPARATOR);
192
193 if ((GNUNET_YES == GNUNET_DISK_directory_test (member_dir, GNUNET_NO)) ||
194 (GNUNET_OK == GNUNET_DISK_directory_create (member_dir)))
195 save_member (member, member_dir);
196
197 GNUNET_free (member_dir);
198 return GNUNET_YES;
199}
200
201
202void
203save_member_store (struct GNUNET_MESSENGER_MemberStore *store,
204 const char *directory)
205{
206 GNUNET_assert ((store) && (directory));
207
208 char *save_dir;
209 GNUNET_asprintf (&save_dir, "%s%s%c", directory, "members", DIR_SEPARATOR);
210
211 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Save member store to directory: %s\n",
212 save_dir);
213
214 if ((GNUNET_YES == GNUNET_DISK_directory_test (save_dir, GNUNET_NO)) ||
215 (GNUNET_OK == GNUNET_DISK_directory_create (save_dir)))
216 GNUNET_CONTAINER_multishortmap_iterate (store->members,
217 iterate_save_members, save_dir);
218
219 GNUNET_free (save_dir);
220}
221
222
223struct GNUNET_MESSENGER_Member*
224get_store_member (const struct GNUNET_MESSENGER_MemberStore *store,
225 const struct GNUNET_ShortHashCode *id)
226{
227 GNUNET_assert ((store) && (store->members) && (id));
228
229 return GNUNET_CONTAINER_multishortmap_get (store->members, id);
230}
231
232
233struct GNUNET_MESSENGER_Member*
234get_store_member_of (struct GNUNET_MESSENGER_MemberStore *store,
235 const struct GNUNET_MESSENGER_Message *message)
236{
237 GNUNET_assert ((store) && (message));
238
239 if (GNUNET_YES == is_peer_message (message))
240 return NULL;
241
242 if (GNUNET_MESSENGER_KIND_JOIN == message->header.kind)
243 return add_store_member (store, &(message->header.sender_id));
244 else
245 return get_store_member (store, &(message->header.sender_id));
246}
247
248
249struct GNUNET_MESSENGER_Member*
250add_store_member (struct GNUNET_MESSENGER_MemberStore *store,
251 const struct GNUNET_ShortHashCode *id)
252{
253 GNUNET_assert ((store) && (store->members));
254
255 struct GNUNET_MESSENGER_Member *member = id? get_store_member (store, id) :
256 NULL;
257
258 if (member)
259 return member;
260
261 member = create_member (store, id);
262
263 if (! member)
264 return NULL;
265
266 if (GNUNET_OK != GNUNET_CONTAINER_multishortmap_put (store->members,
267 get_member_id (member),
268 member,
269 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
270 {
271 destroy_member (member);
272 return NULL;
273 }
274
275 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Added store member with id: %s\n",
276 GNUNET_sh2s (get_member_id (member)));
277
278 return member;
279}
280
281
282struct GNUNET_MESSENGER_ClosureIterateMembers
283{
284 GNUNET_MESSENGER_MemberIteratorCallback it;
285 void *cls;
286};
287
288static int
289iterate_store_members_it (void *cls,
290 const struct GNUNET_ShortHashCode *key,
291 void *value)
292{
293 struct GNUNET_MESSENGER_ClosureIterateMembers *iterate = cls;
294 struct GNUNET_MESSENGER_Member *member = value;
295
296 return iterate_member_sessions (member, iterate->it, iterate->cls);
297}
298
299
300int
301iterate_store_members (struct GNUNET_MESSENGER_MemberStore *store,
302 GNUNET_MESSENGER_MemberIteratorCallback it,
303 void *cls)
304{
305 GNUNET_assert ((store) && (store->members) && (it));
306
307 struct GNUNET_MESSENGER_ClosureIterateMembers iterate;
308
309 iterate.it = it;
310 iterate.cls = cls;
311
312 return GNUNET_CONTAINER_multishortmap_iterate (store->members,
313 iterate_store_members_it,
314 &iterate);
315}
diff --git a/src/service/messenger/gnunet-service-messenger_member_store.h b/src/service/messenger/gnunet-service-messenger_member_store.h
new file mode 100644
index 000000000..181593e6b
--- /dev/null
+++ b/src/service/messenger/gnunet-service-messenger_member_store.h
@@ -0,0 +1,158 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_member_store.h
23 * @brief GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_SERVICE_MESSENGER_MEMBER_STORE_H
27#define GNUNET_SERVICE_MESSENGER_MEMBER_STORE_H
28
29#include "gnunet_util_lib.h"
30
31#include "gnunet_messenger_service.h"
32
33struct GNUNET_MESSENGER_SrvRoom;
34
35struct GNUNET_MESSENGER_Member;
36struct GNUNET_MESSENGER_MemberSession;
37
38struct GNUNET_MESSENGER_MemberStore
39{
40 struct GNUNET_MESSENGER_SrvRoom *room;
41
42 struct GNUNET_CONTAINER_MultiShortmap *members;
43};
44
45typedef enum GNUNET_GenericReturnValue (*GNUNET_MESSENGER_MemberIteratorCallback) (
46 void *cls,
47 const struct GNUNET_CRYPTO_PublicKey *public_key,
48 struct GNUNET_MESSENGER_MemberSession *session);
49
50/**
51 * Initializes a member <i>store</i> as fully empty connected to a <i>room</i>.
52 *
53 * @param[out] store Member store
54 * @param room Room
55 */
56void
57init_member_store (struct GNUNET_MESSENGER_MemberStore *store,
58 struct GNUNET_MESSENGER_SrvRoom *room);
59
60/**
61 * Clears a member <i>store</i>, wipes its content and deallocates its memory.
62 *
63 * @param[in,out] store Member store
64 */
65void
66clear_member_store (struct GNUNET_MESSENGER_MemberStore *store);
67
68/**
69 * Returns the used contact store of a given member <i>store</i>.
70 *
71 * @param[in,out] store Member store
72 * @return Contact store
73 */
74struct GNUNET_MESSENGER_ContactStore*
75get_member_contact_store (struct GNUNET_MESSENGER_MemberStore *store);
76
77/**
78 * Returns the shared secret you need to access a room of the <i>store</i>.
79 *
80 * @param[in] store Member store
81 * @return Shared secret
82 */
83const struct GNUNET_HashCode*
84get_member_store_key (const struct GNUNET_MESSENGER_MemberStore *store);
85
86/**
87 * Loads members from a directory into a member <i>store</i>.
88 *
89 * @param[out] store Member store
90 * @param[in] directory Path to a directory
91 */
92void
93load_member_store (struct GNUNET_MESSENGER_MemberStore *store,
94 const char *directory);
95
96/**
97 * Saves members from a member <i>store</i> into a directory.
98 *
99 * @param[in] store Member store
100 * @param[in] directory Path to a directory
101 */
102void
103save_member_store (struct GNUNET_MESSENGER_MemberStore *store,
104 const char *directory);
105
106/**
107 * Returns the member in a <i>store</i> identified by a given <i>id</i>. If the <i>store</i>
108 * does not contain a member with the given <i>id</i>, NULL gets returned.
109 *
110 * @param[in] store Member store
111 * @param[in] id Member id
112 * @return Member or NULL
113 */
114struct GNUNET_MESSENGER_Member*
115get_store_member (const struct GNUNET_MESSENGER_MemberStore *store,
116 const struct GNUNET_ShortHashCode *id);
117
118/**
119 * Returns the member of a <i>store</i> using a sender id of a given <i>message</i>.
120 *
121 * If the message is a peer message or the member does not provide a matching session,
122 * NULL gets returned.
123 *
124 * @param[in,out] store Member store
125 * @param[in] message Message
126 * @return Member or NULL
127 */
128struct GNUNET_MESSENGER_Member*
129get_store_member_of (struct GNUNET_MESSENGER_MemberStore *store,
130 const struct GNUNET_MESSENGER_Message *message);
131
132/**
133 * Adds a member to a <i>store</i> under a specific <i>id</i> and returns it on success.
134 *
135 * @param[in,out] store Member store
136 * @param[in] id Member id
137 * @return Member or NULL
138 */
139struct GNUNET_MESSENGER_Member*
140add_store_member (struct GNUNET_MESSENGER_MemberStore *store,
141 const struct GNUNET_ShortHashCode *id);
142
143/**
144 * Iterate through all member sessions currently connected to the members of the given
145 * member <i>store</i> and call the provided iterator callback with a selected closure.
146 * The function will return the amount of members it iterated through.
147 *
148 * @param[in,out] store Member store
149 * @param[in] it Iterator callback
150 * @param[in,out] cls Closure
151 * @return Amount of members iterated through
152 */
153int
154iterate_store_members (struct GNUNET_MESSENGER_MemberStore *store,
155 GNUNET_MESSENGER_MemberIteratorCallback it,
156 void *cls);
157
158#endif //GNUNET_SERVICE_MESSENGER_MEMBER_STORE_H
diff --git a/src/service/messenger/gnunet-service-messenger_message_handle.c b/src/service/messenger/gnunet-service-messenger_message_handle.c
new file mode 100644
index 000000000..ee099d893
--- /dev/null
+++ b/src/service/messenger/gnunet-service-messenger_message_handle.c
@@ -0,0 +1,185 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_message_handle.c
23 * @brief GNUnet MESSENGER service
24 */
25
26#include "gnunet-service-messenger_message_handle.h"
27
28#include "gnunet-service-messenger_room.h"
29
30static void
31handle_member_session_switch (struct GNUNET_MESSENGER_MemberSession *session,
32 const struct GNUNET_MESSENGER_Message *message,
33 const struct GNUNET_HashCode *hash)
34{
35 struct GNUNET_MESSENGER_MemberSession *next = switch_member_session (session,
36 message,
37 hash);
38
39 if (next != session)
40 add_member_session (next->member, next);
41}
42
43
44void
45handle_message_join (struct GNUNET_MESSENGER_SrvRoom *room,
46 struct GNUNET_MESSENGER_SenderSession *session,
47 const struct GNUNET_MESSENGER_Message *message,
48 const struct GNUNET_HashCode *hash)
49{
50 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Member (%s) joins room (%s).\n",
51 GNUNET_sh2s (&(message->header.sender_id)), GNUNET_h2s (
52 get_srv_room_key (room)));
53
54 if (GNUNET_OK != reset_member_session (session->member, hash))
55 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Resetting member session failed!\n");
56
57 solve_srv_room_member_collisions (
58 room,
59 &(message->body.join.key),
60 &(message->header.sender_id),
61 GNUNET_TIME_absolute_ntoh (message->header.timestamp)
62 );
63}
64
65
66void
67handle_message_leave (struct GNUNET_MESSENGER_SrvRoom *room,
68 struct GNUNET_MESSENGER_SenderSession *session,
69 const struct GNUNET_MESSENGER_Message *message,
70 const struct GNUNET_HashCode *hash)
71{
72 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Member (%s) leaves room (%s).\n",
73 GNUNET_sh2s (&(message->header.sender_id)), GNUNET_h2s (
74 get_srv_room_key (room)));
75
76 close_member_session (session->member);
77}
78
79
80void
81handle_message_key (struct GNUNET_MESSENGER_SrvRoom *room,
82 struct GNUNET_MESSENGER_SenderSession *session,
83 const struct GNUNET_MESSENGER_Message *message,
84 const struct GNUNET_HashCode *hash)
85{
86 handle_member_session_switch (session->member, message, hash);
87}
88
89
90void
91handle_message_peer (struct GNUNET_MESSENGER_SrvRoom *room,
92 struct GNUNET_MESSENGER_SenderSession *session,
93 const struct GNUNET_MESSENGER_Message *message,
94 const struct GNUNET_HashCode *hash)
95{
96 struct GNUNET_MESSENGER_PeerStore *store = get_srv_room_peer_store (room);
97
98 if (0 == GNUNET_memcmp (session->peer, &(message->body.peer.peer)))
99 update_store_peer (store, &(message->body.peer.peer), GNUNET_YES);
100
101 if (GNUNET_NO == contains_list_tunnels (&(room->basement),
102 &(message->body.peer.peer)))
103 add_to_list_tunnels (&(room->basement), &(message->body.peer.peer), hash);
104
105 if (room->peer_message)
106 rebuild_srv_room_basement_structure (room);
107}
108
109
110void
111handle_message_id (struct GNUNET_MESSENGER_SrvRoom *room,
112 struct GNUNET_MESSENGER_SenderSession *session,
113 const struct GNUNET_MESSENGER_Message *message,
114 const struct GNUNET_HashCode *hash)
115{
116 handle_member_session_switch (session->member, message, hash);
117
118 solve_srv_room_member_collisions (
119 room,
120 get_member_session_public_key (session->member),
121 &(message->body.id.id),
122 GNUNET_TIME_absolute_ntoh (message->header.timestamp)
123 );
124}
125
126
127void
128handle_message_miss (struct GNUNET_MESSENGER_SrvRoom *room,
129 struct GNUNET_MESSENGER_SenderSession *session,
130 const struct GNUNET_MESSENGER_Message *message,
131 const struct GNUNET_HashCode *hash)
132{
133 struct GNUNET_MESSENGER_PeerStore *store = get_srv_room_peer_store (room);
134
135 if (0 == GNUNET_memcmp (session->peer, &(message->body.miss.peer)))
136 update_store_peer (store, &(message->body.miss.peer), GNUNET_NO);
137
138 struct GNUNET_MESSENGER_ListTunnel *element = find_list_tunnels (
139 &(room->basement), &(message->body.miss.peer), NULL);
140
141 if (! element)
142 return;
143
144 remove_from_list_tunnels (&(room->basement), element);
145
146 if (room->peer_message)
147 rebuild_srv_room_basement_structure (room);
148}
149
150
151void
152handle_message_delete (struct GNUNET_MESSENGER_SrvRoom *room,
153 struct GNUNET_MESSENGER_SenderSession *session,
154 const struct GNUNET_MESSENGER_Message *message,
155 const struct GNUNET_HashCode *hash)
156{
157 struct GNUNET_TIME_Relative delay = GNUNET_TIME_relative_ntoh (
158 message->body.deletion.delay);
159 struct GNUNET_TIME_Absolute action = GNUNET_TIME_absolute_ntoh (
160 message->header.timestamp);
161
162 action = GNUNET_TIME_absolute_add (action, delay);
163 delay = GNUNET_TIME_absolute_get_difference (GNUNET_TIME_absolute_get (),
164 action);
165
166 delete_srv_room_message (room, session->member,
167 &(message->body.deletion.hash), delay);
168}
169
170
171void
172handle_message_connection (struct GNUNET_MESSENGER_SrvRoom *room,
173 struct GNUNET_MESSENGER_SenderSession *session,
174 const struct GNUNET_MESSENGER_Message *message,
175 const struct GNUNET_HashCode *hash)
176{
177 struct GNUNET_MESSENGER_ListTunnel *element = find_list_tunnels (
178 &(room->basement), session->peer, NULL);
179
180 if (! element)
181 return;
182
183 memcpy (&(element->connection), &(message->body.connection),
184 sizeof (struct GNUNET_MESSENGER_MessageConnection));
185}
diff --git a/src/service/messenger/gnunet-service-messenger_message_handle.h b/src/service/messenger/gnunet-service-messenger_message_handle.h
new file mode 100644
index 000000000..a66c45192
--- /dev/null
+++ b/src/service/messenger/gnunet-service-messenger_message_handle.h
@@ -0,0 +1,151 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_message_handle.h
23 * @brief GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_SERVICE_MESSENGER_MESSAGE_HANDLE_H
27#define GNUNET_SERVICE_MESSENGER_MESSAGE_HANDLE_H
28
29#include "gnunet-service-messenger_sender_session.h"
30
31/**
32 * Handles a received or sent join message to make changes of current member information.
33 * (add matching member and clear member info)
34 *
35 * @param[in,out] room Room of the message
36 * @param[in,out] session Sender session
37 * @param[in] message JOIN-Message
38 * @param[in] hash Hash of the message
39 */
40void
41handle_message_join (struct GNUNET_MESSENGER_SrvRoom *room,
42 struct GNUNET_MESSENGER_SenderSession *session,
43 const struct GNUNET_MESSENGER_Message *message,
44 const struct GNUNET_HashCode *hash);
45
46/**
47 * Handles a received or sent leave message to make changes of current member information.
48 * (remove matching member and clear member info)
49 *
50 * @param[in,out] room Room of the message
51 * @param[in,out] session Sender session
52 * @param[in] message LEAVE-Message
53 * @param[in] hash Hash of the message
54 */
55void
56handle_message_leave (struct GNUNET_MESSENGER_SrvRoom *room,
57 struct GNUNET_MESSENGER_SenderSession *session,
58 const struct GNUNET_MESSENGER_Message *message,
59 const struct GNUNET_HashCode *hash);
60
61/**
62 * Handles a received or sent key message to change the key of a member and rearrange the contacts accordingly.
63 * (move the member in the contacts and change its key)
64 *
65 * @param[in,out] room Room of the message
66 * @param[in,out] session Sender session
67 * @param[in] message KEY-Message
68 * @param[in] hash Hash of the message
69 */
70void
71handle_message_key (struct GNUNET_MESSENGER_SrvRoom *room,
72 struct GNUNET_MESSENGER_SenderSession *session,
73 const struct GNUNET_MESSENGER_Message *message,
74 const struct GNUNET_HashCode *hash);
75
76/**
77 * Handles a received or sent peer message to make changes of the basement in the room.
78 * (add a new peer to the basement and restructure connections based on updated list of peers)
79 *
80 * @param[in,out] room Room of the message
81 * @param[in,out] session Sender session
82 * @param[in] message PEER-Message
83 * @param[in] hash Hash of the message
84 */
85void
86handle_message_peer (struct GNUNET_MESSENGER_SrvRoom *room,
87 struct GNUNET_MESSENGER_SenderSession *session,
88 const struct GNUNET_MESSENGER_Message *message,
89 const struct GNUNET_HashCode *hash);
90
91/**
92 * Handles a received or sent id message to change a members id.
93 * (change id of matching member)
94 *
95 * @param[in,out] room Room of the message
96 * @param[in,out] session Sender session
97 * @param[in] message ID-Message
98 * @param[in] hash Hash of the message
99 */
100void
101handle_message_id (struct GNUNET_MESSENGER_SrvRoom *room,
102 struct GNUNET_MESSENGER_SenderSession *session,
103 const struct GNUNET_MESSENGER_Message *message,
104 const struct GNUNET_HashCode *hash);
105
106/**
107 * Handles a received or sent miss message to drop a peer from the basement in the room.
108 * (remove a peer from the basement and restructure connections based on updated list of peers)
109 *
110 * @param[in,out] room Room of the message
111 * @param[in,out] session Sender session
112 * @param[in] message MISS-Message
113 * @param[in] hash Hash of the message
114 */
115void
116handle_message_miss (struct GNUNET_MESSENGER_SrvRoom *room,
117 struct GNUNET_MESSENGER_SenderSession *session,
118 const struct GNUNET_MESSENGER_Message *message,
119 const struct GNUNET_HashCode *hash);
120
121/**
122 * Handles a received or sent delete message to delete a specific message from the store.
123 * (remove a message from the store of a room under a given delay)
124 *
125 * @param[in,out] room Room of the message
126 * @param[in,out] session Sender session
127 * @param[in] message DELETE-Message
128 * @param[in] hash Hash of the message
129 */
130void
131handle_message_delete (struct GNUNET_MESSENGER_SrvRoom *room,
132 struct GNUNET_MESSENGER_SenderSession *session,
133 const struct GNUNET_MESSENGER_Message *message,
134 const struct GNUNET_HashCode *hash);
135
136/**
137 * Handles a received or sent connection message to update connection information about a peer.
138 * (update a peer in the basement)
139 *
140 * @param[in,out] room Room of the message
141 * @param[in,out] session Sender session
142 * @param[in] message DELETE-Message
143 * @param[in] hash Hash of the message
144 */
145void
146handle_message_connection (struct GNUNET_MESSENGER_SrvRoom *room,
147 struct GNUNET_MESSENGER_SenderSession *session,
148 const struct GNUNET_MESSENGER_Message *message,
149 const struct GNUNET_HashCode *hash);
150
151#endif //GNUNET_SERVICE_MESSENGER_MESSAGE_HANDLE_H
diff --git a/src/service/messenger/gnunet-service-messenger_message_kind.c b/src/service/messenger/gnunet-service-messenger_message_kind.c
new file mode 100644
index 000000000..f1a79b321
--- /dev/null
+++ b/src/service/messenger/gnunet-service-messenger_message_kind.c
@@ -0,0 +1,129 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_message_kind.c
23 * @brief GNUnet MESSENGER service
24 */
25
26#include "gnunet-service-messenger_message_kind.h"
27
28#include "gnunet-service-messenger_room.h"
29
30#include "messenger_api_message.h"
31
32struct GNUNET_MESSENGER_Message*
33create_message_info (struct GNUNET_MESSENGER_Service *service)
34{
35 if (! service)
36 return NULL;
37
38 struct GNUNET_MESSENGER_Message *message = create_message (
39 GNUNET_MESSENGER_KIND_INFO);
40
41 if (! message)
42 return NULL;
43
44 message->body.info.messenger_version = GNUNET_MESSENGER_VERSION;
45
46 return message;
47}
48
49
50struct GNUNET_MESSENGER_Message*
51create_message_peer (struct GNUNET_MESSENGER_Service *service)
52{
53 if (! service)
54 return NULL;
55
56 struct GNUNET_MESSENGER_Message *message = create_message (
57 GNUNET_MESSENGER_KIND_PEER);
58
59 if (! message)
60 return NULL;
61
62 if (GNUNET_OK == get_service_peer_identity (service,
63 &(message->body.peer.peer)))
64 return message;
65 else
66 {
67 destroy_message (message);
68 return NULL;
69 }
70}
71
72
73struct GNUNET_MESSENGER_Message*
74create_message_miss (const struct GNUNET_PeerIdentity *peer)
75{
76 if (! peer)
77 return NULL;
78
79 struct GNUNET_MESSENGER_Message *message = create_message (
80 GNUNET_MESSENGER_KIND_MISS);
81
82 if (! message)
83 {
84 return NULL;
85 }
86
87 GNUNET_memcpy (&(message->body.miss.peer), peer, sizeof(struct
88 GNUNET_PeerIdentity));
89
90 return message;
91}
92
93
94struct GNUNET_MESSENGER_Message*
95create_message_merge (const struct GNUNET_HashCode *previous)
96{
97 if (! previous)
98 return NULL;
99
100 struct GNUNET_MESSENGER_Message *message = create_message (
101 GNUNET_MESSENGER_KIND_MERGE);
102
103 if (! message)
104 return NULL;
105
106 GNUNET_memcpy (&(message->body.merge.previous), previous, sizeof(struct
107 GNUNET_HashCode));
108
109 return message;
110}
111
112
113struct GNUNET_MESSENGER_Message*
114create_message_connection (const struct GNUNET_MESSENGER_SrvRoom *room)
115{
116 if (! room)
117 return NULL;
118
119 struct GNUNET_MESSENGER_Message *message = create_message (
120 GNUNET_MESSENGER_KIND_CONNECTION);
121
122 if (! message)
123 return NULL;
124
125 message->body.connection.amount = get_srv_room_amount_of_tunnels (room);
126 message->body.connection.flags = get_srv_room_connection_flags (room);
127
128 return message;
129}
diff --git a/src/service/messenger/gnunet-service-messenger_message_kind.h b/src/service/messenger/gnunet-service-messenger_message_kind.h
new file mode 100644
index 000000000..7fc7a7cc0
--- /dev/null
+++ b/src/service/messenger/gnunet-service-messenger_message_kind.h
@@ -0,0 +1,86 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_message_kind.h
23 * @brief GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_SERVICE_MESSENGER_MESSAGE_KIND_H
27#define GNUNET_SERVICE_MESSENGER_MESSAGE_KIND_H
28
29#include "gnunet_util_lib.h"
30
31#include "gnunet-service-messenger_service.h"
32
33/**
34 * Creates and allocates a new info message containing the hosts service peer identity and version.
35 * (all values are stored as copy)
36 *
37 * @param[in,out] service Service
38 * @return New message
39 */
40struct GNUNET_MESSENGER_Message*
41create_message_info (struct GNUNET_MESSENGER_Service *service);
42
43/**
44 * Creates and allocates a new peer message containing a services peer identity.
45 * (all values are stored as copy)
46 *
47 * @param[in,out] service Service
48 * @return New message
49 */
50struct GNUNET_MESSENGER_Message*
51create_message_peer (struct GNUNET_MESSENGER_Service *service);
52
53/**
54 * Creates and allocates a new miss message containing the missing <i>peer</i> identity.
55 * (all values are stored as copy)
56 *
57 * @param[in] peer Missing peer identity
58 * @return New message
59 */
60struct GNUNET_MESSENGER_Message*
61create_message_miss (const struct GNUNET_PeerIdentity *peer);
62
63/**
64 * Creates and allocates a new merge message containing the hash of a second <i>previous</i> message
65 * besides the regular previous message mentioned in a messages header.
66 * (all values are stored as copy)
67 *
68 * @param[in] previous Hash of message
69 * @return New message
70 */
71struct GNUNET_MESSENGER_Message*
72create_message_merge (const struct GNUNET_HashCode *previous);
73
74/**
75 * Creates and allocates a new connection message containing the amount of the peer's connections
76 * in a given <i>room</i> as well as flags from the peer about its connections.
77 * (all values are stored as copy)
78 *
79 * @param[in] room Room
80 * @return New message
81 */
82struct GNUNET_MESSENGER_Message*
83create_message_connection (const struct GNUNET_MESSENGER_SrvRoom *room);
84
85
86#endif //GNUNET_SERVICE_MESSENGER_MESSAGE_KIND_H
diff --git a/src/service/messenger/gnunet-service-messenger_message_recv.c b/src/service/messenger/gnunet-service-messenger_message_recv.c
new file mode 100644
index 000000000..6d4d537b6
--- /dev/null
+++ b/src/service/messenger/gnunet-service-messenger_message_recv.c
@@ -0,0 +1,246 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_message_recv.c
23 * @brief GNUnet MESSENGER service
24 */
25
26#include "gnunet-service-messenger_message_recv.h"
27
28#include "gnunet-service-messenger_basement.h"
29#include "gnunet-service-messenger_message_kind.h"
30#include "gnunet-service-messenger_operation.h"
31
32static void
33forward_about_members (struct GNUNET_MESSENGER_SrvRoom *room,
34 struct GNUNET_MESSENGER_SrvTunnel *tunnel,
35 struct GNUNET_MESSENGER_MemberSession *session,
36 struct GNUNET_CONTAINER_MultiHashMap *map)
37{
38 if (session->prev)
39 forward_about_members (room, tunnel, session->prev, map);
40
41 struct GNUNET_MESSENGER_MessageStore *message_store =
42 get_srv_room_message_store (room);
43 struct GNUNET_MESSENGER_ListMessage *element;
44
45 for (element = session->messages.head; element; element = element->next)
46 {
47 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (map,
48 &(element->hash)))
49 continue;
50
51 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (map, &(element->hash),
52 NULL,
53 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
54
55 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
56 "Forwarding of session message could be duplicated!\n");
57
58 const struct GNUNET_MESSENGER_Message *message = get_store_message (
59 message_store, &(element->hash));
60
61 if (message)
62 forward_tunnel_message (tunnel, message, &(element->hash));
63 }
64}
65
66
67static enum GNUNET_GenericReturnValue
68iterate_forward_members (void *cls,
69 const struct GNUNET_CRYPTO_PublicKey *public_key,
70 struct GNUNET_MESSENGER_MemberSession *session)
71{
72 struct GNUNET_MESSENGER_SrvTunnel *tunnel = cls;
73
74 if (GNUNET_YES == is_member_session_completed (session))
75 return GNUNET_YES;
76
77 struct GNUNET_CONTAINER_MultiHashMap *map =
78 GNUNET_CONTAINER_multihashmap_create (4, GNUNET_NO);
79
80 forward_about_members (tunnel->room, tunnel, session, map);
81
82 GNUNET_CONTAINER_multihashmap_destroy (map);
83 return GNUNET_YES;
84}
85
86
87enum GNUNET_GenericReturnValue
88recv_message_info (struct GNUNET_MESSENGER_SrvRoom *room,
89 struct GNUNET_MESSENGER_SrvTunnel *tunnel,
90 const struct GNUNET_MESSENGER_Message *message,
91 const struct GNUNET_HashCode *hash)
92{
93 const uint32_t version = get_tunnel_messenger_version (tunnel);
94
95 if (GNUNET_OK != update_tunnel_messenger_version (tunnel,
96 message->body.info.
97 messenger_version))
98 {
99 disconnect_tunnel (tunnel);
100 return GNUNET_NO;
101 }
102
103 if (version == get_tunnel_messenger_version (tunnel))
104 return GNUNET_NO;
105
106 if (room->host)
107 send_tunnel_message (tunnel, room->host, create_message_info (
108 room->service));
109
110 struct GNUNET_PeerIdentity peer;
111 get_tunnel_peer_identity (tunnel, &peer);
112
113 if (GNUNET_YES != contains_list_tunnels (&(room->basement), &peer))
114 {
115 struct GNUNET_MESSENGER_MessageStore *message_store =
116 get_srv_room_message_store (room);
117
118 struct GNUNET_MESSENGER_ListTunnel *element;
119 for (element = room->basement.head; element; element = element->next)
120 {
121 if (! element->hash)
122 continue;
123
124 const struct GNUNET_MESSENGER_Message *message = get_store_message (
125 message_store, element->hash);
126
127 if (message)
128 forward_tunnel_message (tunnel, message, element->hash);
129 }
130 }
131
132 if (GNUNET_YES != contains_list_tunnels (&(room->basement), &peer))
133 {
134 struct GNUNET_MESSENGER_MemberStore *member_store =
135 get_srv_room_member_store (room);
136
137 iterate_store_members (member_store, iterate_forward_members, tunnel);
138 }
139
140 check_srv_room_peer_status (room, tunnel);
141 return GNUNET_NO;
142}
143
144
145enum GNUNET_GenericReturnValue
146recv_message_peer (struct GNUNET_MESSENGER_SrvRoom *room,
147 struct GNUNET_MESSENGER_SrvTunnel *tunnel,
148 const struct GNUNET_MESSENGER_Message *message,
149 const struct GNUNET_HashCode *hash)
150{
151 struct GNUNET_PeerIdentity peer;
152 GNUNET_PEER_resolve (tunnel->peer, &peer);
153
154 if (0 == GNUNET_memcmp (&peer, &(message->body.peer.peer)))
155 {
156 if (! tunnel->peer_message)
157 tunnel->peer_message = GNUNET_new (struct GNUNET_HashCode);
158
159 GNUNET_memcpy (tunnel->peer_message, &hash, sizeof(hash));
160 }
161
162 update_to_list_tunnels (&(room->basement), &(message->body.peer.peer), hash);
163 return GNUNET_YES;
164}
165
166
167enum GNUNET_GenericReturnValue
168recv_message_miss (struct GNUNET_MESSENGER_SrvRoom *room,
169 struct GNUNET_MESSENGER_SrvTunnel *tunnel,
170 const struct GNUNET_MESSENGER_Message *message,
171 const struct GNUNET_HashCode *hash)
172{
173 struct GNUNET_MESSENGER_Service *service = room->service;
174
175 if ((GNUNET_YES == service->auto_routing) &&
176 (service->min_routers > count_of_tunnels (&(room->basement))))
177 open_srv_room (room, NULL);
178
179 return GNUNET_YES;
180}
181
182
183static void
184callback_found_message (void *cls,
185 struct GNUNET_MESSENGER_SrvRoom *room,
186 const struct GNUNET_MESSENGER_Message *message,
187 const struct GNUNET_HashCode *hash)
188{
189 struct GNUNET_MESSENGER_SrvTunnel *tunnel = cls;
190
191 if (! message)
192 {
193 struct GNUNET_MESSENGER_OperationStore *operation_store =
194 get_srv_room_operation_store (room);
195
196 use_store_operation (
197 operation_store,
198 hash,
199 GNUNET_MESSENGER_OP_REQUEST,
200 GNUNET_MESSENGER_REQUEST_DELAY
201 );
202 }
203 else
204 forward_tunnel_message (tunnel, message, hash);
205}
206
207
208/*
209 * Function returns GNUNET_NO to drop forwarding the request.
210 * It will only be forwarded if it can't be answered!
211 */
212enum GNUNET_GenericReturnValue
213recv_message_request (struct GNUNET_MESSENGER_SrvRoom *room,
214 struct GNUNET_MESSENGER_SrvTunnel *tunnel,
215 const struct GNUNET_MESSENGER_Message *message,
216 const struct GNUNET_HashCode *hash)
217{
218 struct GNUNET_MESSENGER_MemberStore *member_store =
219 get_srv_room_member_store (room);
220 struct GNUNET_MESSENGER_Member *member = get_store_member_of (member_store,
221 message);
222
223 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Request for message (%s)\n",
224 GNUNET_h2s (hash));
225
226 if (! member)
227 return GNUNET_NO;
228
229 struct GNUNET_MESSENGER_MemberSession *session = get_member_session_of (
230 member, message, hash);
231
232 if ((! session) || (GNUNET_YES != check_member_session_history (session,
233 &(message->
234 body.request
235 .hash),
236 GNUNET_NO)))
237 return GNUNET_NO;
238
239 if (GNUNET_NO == request_srv_room_message (room,
240 &(message->body.request.hash),
241 session, callback_found_message,
242 tunnel))
243 return GNUNET_YES;
244
245 return GNUNET_NO;
246}
diff --git a/src/service/messenger/gnunet-service-messenger_message_recv.h b/src/service/messenger/gnunet-service-messenger_message_recv.h
new file mode 100644
index 000000000..58eb1d5cc
--- /dev/null
+++ b/src/service/messenger/gnunet-service-messenger_message_recv.h
@@ -0,0 +1,96 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_message_recv.h
23 * @brief GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_SERVICE_MESSENGER_MESSAGE_RECV_H
27#define GNUNET_SERVICE_MESSENGER_MESSAGE_RECV_H
28
29#include "gnunet-service-messenger_tunnel.h"
30
31/**
32 * Handles a received info message to change the current member id to the one generated by
33 * the host connected to. (all current tunnels will be informed about the id change)
34 *
35 * @param[in,out] room Room of the message
36 * @param[in,out] tunnel Receiving connection
37 * @param[in] message INFO-Message
38 * @param[in] hash Hash of the message
39 * @return #GNUNET_NO to not forward the message
40 */
41enum GNUNET_GenericReturnValue
42recv_message_info (struct GNUNET_MESSENGER_SrvRoom *room,
43 struct GNUNET_MESSENGER_SrvTunnel *tunnel,
44 const struct GNUNET_MESSENGER_Message *message,
45 const struct GNUNET_HashCode *hash);
46
47/**
48 * Handles a received peer message to link it to its origin tunnel if the peer identity matches.
49 * (the peer message and the member id can potentially be linked to the tunnel)
50 *
51 * @param[in,out] room Room of the message
52 * @param[in,out] tunnel Receiving connection
53 * @param[in] message PEER-Message
54 * @param[in] hash Hash of the message
55 * @return #GNUNET_YES to forward the message
56 */
57enum GNUNET_GenericReturnValue
58recv_message_peer (struct GNUNET_MESSENGER_SrvRoom *room,
59 struct GNUNET_MESSENGER_SrvTunnel *tunnel,
60 const struct GNUNET_MESSENGER_Message *message,
61 const struct GNUNET_HashCode *hash);
62
63/**
64 * Handles a received miss message to react to activity in the basement of a room.
65 * (the miss message can cause automatic opening of the room)
66 *
67 * @param[in,out] room Room of the message
68 * @param[in,out] tunnel Receiving connection
69 * @param[in] message MISS-Message
70 * @param[in] hash Hash of the message
71 * @return #GNUNET_YES to forward the message
72 */
73enum GNUNET_GenericReturnValue
74recv_message_miss (struct GNUNET_MESSENGER_SrvRoom *room,
75 struct GNUNET_MESSENGER_SrvTunnel *tunnel,
76 const struct GNUNET_MESSENGER_Message *message,
77 const struct GNUNET_HashCode *hash);
78
79/**
80 * Handles a received request message by checking for the requested message and forwarding it back
81 * if the message was found.
82 * (this can also cause this peer to send a new request instead of only forwarding the received one)
83 *
84 * @param[in,out] room Room of the message
85 * @param[in,out] tunnel Receiving connection
86 * @param[in] message REQUEST-Message
87 * @param[in] hash Hash of the message
88 * @return #GNUNET_YES or #GNUNET_NO depending on required forwarding
89 */
90enum GNUNET_GenericReturnValue
91recv_message_request (struct GNUNET_MESSENGER_SrvRoom *room,
92 struct GNUNET_MESSENGER_SrvTunnel *tunnel,
93 const struct GNUNET_MESSENGER_Message *message,
94 const struct GNUNET_HashCode *hash);
95
96#endif //GNUNET_SERVICE_MESSENGER_MESSAGE_RECV_H
diff --git a/src/service/messenger/gnunet-service-messenger_message_send.c b/src/service/messenger/gnunet-service-messenger_message_send.c
new file mode 100644
index 000000000..05032e455
--- /dev/null
+++ b/src/service/messenger/gnunet-service-messenger_message_send.c
@@ -0,0 +1,220 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_message_send.c
23 * @brief GNUnet MESSENGER service
24 */
25
26#include "gnunet-service-messenger_message_send.h"
27
28#include "gnunet-service-messenger_handle.h"
29#include "gnunet-service-messenger_member.h"
30#include "gnunet-service-messenger_member_session.h"
31#include "gnunet-service-messenger_message_kind.h"
32#include "gnunet-service-messenger_operation.h"
33#include "gnunet-service-messenger_room.h"
34#include "gnunet_common.h"
35
36struct GNUNET_MESSENGER_MemberNotify
37{
38 struct GNUNET_MESSENGER_SrvRoom *room;
39 struct GNUNET_MESSENGER_SrvHandle *handle;
40 struct GNUNET_MESSENGER_MemberSession *session;
41};
42
43static void
44notify_about_members (struct GNUNET_MESSENGER_MemberNotify *notify,
45 struct GNUNET_MESSENGER_MemberSession *session,
46 struct GNUNET_CONTAINER_MultiHashMap *map,
47 enum GNUNET_GenericReturnValue check_permission)
48{
49 if (session->prev)
50 notify_about_members (notify, session->prev, map, GNUNET_YES);
51
52 struct GNUNET_MESSENGER_MessageStore *message_store =
53 get_srv_room_message_store (notify->room);
54 struct GNUNET_MESSENGER_ListMessage *element;
55
56 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
57 "Notify through all of member session: %s\n",
58 GNUNET_sh2s (get_member_session_id (session)));
59
60 for (element = session->messages.head; element; element = element->next)
61 {
62 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (map,
63 &(element->hash)))
64 continue;
65
66 if ((GNUNET_YES == check_permission) &&
67 (GNUNET_YES != check_member_session_history (notify->session,
68 &(element->hash),
69 GNUNET_NO)))
70 {
71 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
72 "Permission for notification of session message denied!\n");
73 continue;
74 }
75
76 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (map, &(element->hash),
77 NULL,
78 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
79
80 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
81 "Notification of session message could be duplicated!\n");
82
83 const struct GNUNET_MESSENGER_Message *message = get_store_message (
84 message_store, &(element->hash));
85
86 if ((! message) || (GNUNET_YES == is_peer_message (message)))
87 {
88 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
89 "Session message for notification is invalid!\n");
90 continue;
91 }
92
93 struct GNUNET_MESSENGER_SenderSession sender;
94 sender.member = session;
95
96 notify_srv_handle_message (notify->handle, notify->room, &sender, message,
97 &(element->hash), GNUNET_NO);
98 }
99}
100
101
102static enum GNUNET_GenericReturnValue
103iterate_notify_about_members (void *cls,
104 const struct
105 GNUNET_CRYPTO_PublicKey *public_key,
106 struct GNUNET_MESSENGER_MemberSession *session)
107{
108 struct GNUNET_MESSENGER_MemberNotify *notify = cls;
109
110 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Notify about member session: %s\n",
111 GNUNET_sh2s (get_member_session_id (session)));
112
113 if ((notify->session == session) || (GNUNET_YES ==
114 is_member_session_completed (session)))
115 return GNUNET_YES;
116
117 struct GNUNET_CONTAINER_MultiHashMap *map =
118 GNUNET_CONTAINER_multihashmap_create (4, GNUNET_NO);
119
120 notify_about_members (notify, session, map, GNUNET_NO);
121
122 GNUNET_CONTAINER_multihashmap_destroy (map);
123 return GNUNET_YES;
124}
125
126
127void
128send_message_join (struct GNUNET_MESSENGER_SrvRoom *room,
129 struct GNUNET_MESSENGER_SrvHandle *handle,
130 const struct GNUNET_MESSENGER_Message *message,
131 const struct GNUNET_HashCode *hash)
132{
133 set_srv_handle_key (handle, &(message->body.join.key));
134
135 struct GNUNET_MESSENGER_MemberStore *member_store =
136 get_srv_room_member_store (room);
137 struct GNUNET_MESSENGER_Member *member = add_store_member (member_store,
138 &(message->header.
139 sender_id));
140
141 struct GNUNET_MESSENGER_MemberSession *session = get_member_session_of (
142 member, message, hash);
143
144 if (! session)
145 {
146 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
147 "A valid session is required to join a room!\n");
148 goto skip_member_notification;
149 }
150
151 struct GNUNET_MESSENGER_MemberNotify notify;
152
153 notify.room = room;
154 notify.handle = handle;
155 notify.session = session;
156
157 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
158 "Notify about all member sessions except: %s\n",
159 GNUNET_sh2s (get_member_session_id (session)));
160
161 iterate_store_members (get_srv_room_member_store (room),
162 iterate_notify_about_members, &notify);
163
164skip_member_notification:
165 check_srv_room_peer_status (room, NULL);
166}
167
168
169void
170send_message_key (struct GNUNET_MESSENGER_SrvRoom *room,
171 struct GNUNET_MESSENGER_SrvHandle *handle,
172 const struct GNUNET_MESSENGER_Message *message,
173 const struct GNUNET_HashCode *hash)
174{
175 set_srv_handle_key (handle, &(message->body.key.key));
176}
177
178
179void
180send_message_peer (struct GNUNET_MESSENGER_SrvRoom *room,
181 struct GNUNET_MESSENGER_SrvHandle *handle,
182 const struct GNUNET_MESSENGER_Message *message,
183 const struct GNUNET_HashCode *hash)
184{
185 if (! room->peer_message)
186 room->peer_message = GNUNET_new (struct GNUNET_HashCode);
187
188 GNUNET_memcpy (room->peer_message, hash, sizeof(struct GNUNET_HashCode));
189
190 send_srv_room_message (room, room->host, create_message_connection (room));
191}
192
193
194void
195send_message_id (struct GNUNET_MESSENGER_SrvRoom *room,
196 struct GNUNET_MESSENGER_SrvHandle *handle,
197 const struct GNUNET_MESSENGER_Message *message,
198 const struct GNUNET_HashCode *hash)
199{
200 change_srv_handle_member_id (handle, get_srv_room_key (room),
201 &(message->body.id.id));
202}
203
204
205void
206send_message_request (struct GNUNET_MESSENGER_SrvRoom *room,
207 struct GNUNET_MESSENGER_SrvHandle *handle,
208 const struct GNUNET_MESSENGER_Message *message,
209 const struct GNUNET_HashCode *hash)
210{
211 struct GNUNET_MESSENGER_OperationStore *operation_store =
212 get_srv_room_operation_store (room);
213
214 use_store_operation (
215 operation_store,
216 &(message->body.request.hash),
217 GNUNET_MESSENGER_OP_REQUEST,
218 GNUNET_MESSENGER_REQUEST_DELAY
219 );
220}
diff --git a/src/service/messenger/gnunet-service-messenger_message_send.h b/src/service/messenger/gnunet-service-messenger_message_send.h
new file mode 100644
index 000000000..ee4d8b0a4
--- /dev/null
+++ b/src/service/messenger/gnunet-service-messenger_message_send.h
@@ -0,0 +1,105 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_message_send.h
23 * @brief GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_SERVICE_MESSENGER_MESSAGE_SEND_H
27#define GNUNET_SERVICE_MESSENGER_MESSAGE_SEND_H
28
29#include "gnunet-service-messenger_room.h"
30
31/**
32 * Handles a sent join message to ensure growth of the decentralized room structure.
33 * (if the service provides a peer message for this room currently, it will be forwarded)
34 *
35 * @param[in,out] room Room of the message
36 * @param[in,out] handle Sending handle
37 * @param[in] message JOIN-Message
38 * @param[in] hash Hash of the message
39 */
40void
41send_message_join (struct GNUNET_MESSENGER_SrvRoom *room,
42 struct GNUNET_MESSENGER_SrvHandle *handle,
43 const struct GNUNET_MESSENGER_Message *message,
44 const struct GNUNET_HashCode *hash);
45
46/**
47 * Handles a sent key message to ensure changes to the public key of the sending handle.
48 *
49 * @param[in,out] room Room of the message
50 * @param[in,out] handle Sending handle
51 * @param[in] message KEY-Message
52 * @param[in] hash Hash of the message
53 */
54void
55send_message_key (struct GNUNET_MESSENGER_SrvRoom *room,
56 struct GNUNET_MESSENGER_SrvHandle *handle,
57 const struct GNUNET_MESSENGER_Message *message,
58 const struct GNUNET_HashCode *hash);
59
60/**
61 * Handles a sent peer message to update the rooms peer message of this service.
62 * (a set peer message indicates this service being a part of the decentralized room structure)
63 *
64 * @param[in,out] room Room of the message
65 * @param[in,out] handle Sending handle
66 * @param[in] message PEER-Message
67 * @param[in] hash Hash of the message
68 */
69void
70send_message_peer (struct GNUNET_MESSENGER_SrvRoom *room,
71 struct GNUNET_MESSENGER_SrvHandle *handle,
72 const struct GNUNET_MESSENGER_Message *message,
73 const struct GNUNET_HashCode *hash);
74
75/**
76 * Handles a sent id message to update the handles member id in the room.
77 * (changing member id is useful to prevent collisions)
78 *
79 * @param[in,out] room Room of the message
80 * @param[in,out] handle Sending handle
81 * @param[in] message ID-Message
82 * @param[in] hash Hash of the message
83 */
84void
85send_message_id (struct GNUNET_MESSENGER_SrvRoom *room,
86 struct GNUNET_MESSENGER_SrvHandle *handle,
87 const struct GNUNET_MESSENGER_Message *message,
88 const struct GNUNET_HashCode *hash);
89
90/**
91 * Handles a sent request message to trigger the request operation for this service.
92 * (the request operation will deactivate the possibility of spamming requests)
93 *
94 * @param[in,out] room Room of the message
95 * @param[in,out] handle Sending handle
96 * @param[in] message REQUEST-Message
97 * @param[in] hash Hash of the message
98 */
99void
100send_message_request (struct GNUNET_MESSENGER_SrvRoom *room,
101 struct GNUNET_MESSENGER_SrvHandle *handle,
102 const struct GNUNET_MESSENGER_Message *message,
103 const struct GNUNET_HashCode *hash);
104
105#endif //GNUNET_SERVICE_MESSENGER_MESSAGE_SEND_H
diff --git a/src/service/messenger/gnunet-service-messenger_message_state.c b/src/service/messenger/gnunet-service-messenger_message_state.c
new file mode 100644
index 000000000..7229eb6ba
--- /dev/null
+++ b/src/service/messenger/gnunet-service-messenger_message_state.c
@@ -0,0 +1,119 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2023 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_message_state.c
23 * @brief GNUnet MESSENGER service
24 */
25
26#include "gnunet-service-messenger_message_state.h"
27
28void
29init_message_state (struct GNUNET_MESSENGER_MessageState *state)
30{
31 GNUNET_assert (state);
32
33 init_list_messages (&(state->last_messages));
34}
35
36
37void
38clear_message_state (struct GNUNET_MESSENGER_MessageState *state)
39{
40 GNUNET_assert (state);
41
42 clear_list_messages (&(state->last_messages));
43}
44
45
46void
47get_message_state_chain_hash (const struct GNUNET_MESSENGER_MessageState *state,
48 struct GNUNET_HashCode *hash)
49{
50 GNUNET_assert ((state) && (hash));
51
52 if (state->last_messages.head)
53 GNUNET_memcpy (hash, &(state->last_messages.head->hash), sizeof(*hash));
54 else
55 memset (hash, 0, sizeof(*hash));
56}
57
58
59const struct GNUNET_HashCode*
60get_message_state_merge_hash (const struct GNUNET_MESSENGER_MessageState *state)
61{
62 GNUNET_assert (state);
63
64 if (state->last_messages.head == state->last_messages.tail)
65 return NULL;
66
67 return &(state->last_messages.tail->hash);
68}
69
70
71void
72update_message_state (struct GNUNET_MESSENGER_MessageState *state,
73 enum GNUNET_GenericReturnValue requested,
74 const struct GNUNET_MESSENGER_Message *message,
75 const struct GNUNET_HashCode *hash)
76{
77 GNUNET_assert ((state) && (message) && (hash));
78
79 if ((GNUNET_YES == requested) ||
80 (GNUNET_MESSENGER_KIND_INFO == message->header.kind) ||
81 (GNUNET_MESSENGER_KIND_REQUEST == message->header.kind))
82 return;
83
84 if (GNUNET_MESSENGER_KIND_MERGE == message->header.kind)
85 remove_from_list_messages (&(state->last_messages),
86 &(message->body.merge.previous));
87 remove_from_list_messages (&(state->last_messages),
88 &(message->header.previous));
89
90 add_to_list_messages (&(state->last_messages), hash);
91}
92
93
94void
95load_message_state (struct GNUNET_MESSENGER_MessageState *state,
96 const char *path)
97{
98 GNUNET_assert ((state) && (path));
99
100 char *last_messages_file;
101 GNUNET_asprintf (&last_messages_file, "%s%s", path, "last_messages.list");
102
103 load_list_messages (&(state->last_messages), last_messages_file);
104 GNUNET_free (last_messages_file);
105}
106
107
108void
109save_message_state (const struct GNUNET_MESSENGER_MessageState *state,
110 const char *path)
111{
112 GNUNET_assert ((state) && (path));
113
114 char *last_messages_file;
115 GNUNET_asprintf (&last_messages_file, "%s%s", path, "last_messages.list");
116
117 save_list_messages (&(state->last_messages), last_messages_file);
118 GNUNET_free (last_messages_file);
119}
diff --git a/src/service/messenger/gnunet-service-messenger_message_state.h b/src/service/messenger/gnunet-service-messenger_message_state.h
new file mode 100644
index 000000000..9723c7654
--- /dev/null
+++ b/src/service/messenger/gnunet-service-messenger_message_state.h
@@ -0,0 +1,66 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_message_state.h
23 * @brief GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_SERVICE_MESSENGER_MESSAGE_STATE_H
27#define GNUNET_SERVICE_MESSENGER_MESSAGE_STATE_H
28
29#include "gnunet_messenger_service.h"
30
31#include "gnunet-service-messenger_list_messages.h"
32
33struct GNUNET_MESSENGER_MessageState
34{
35 struct GNUNET_MESSENGER_ListMessages last_messages;
36};
37
38void
39init_message_state (struct GNUNET_MESSENGER_MessageState *state);
40
41void
42clear_message_state (struct GNUNET_MESSENGER_MessageState *state);
43
44void
45get_message_state_chain_hash (const struct GNUNET_MESSENGER_MessageState *state,
46 struct GNUNET_HashCode *hash);
47
48const struct GNUNET_HashCode*
49get_message_state_merge_hash (const struct
50 GNUNET_MESSENGER_MessageState *state);
51
52void
53update_message_state (struct GNUNET_MESSENGER_MessageState *state,
54 enum GNUNET_GenericReturnValue requested,
55 const struct GNUNET_MESSENGER_Message *message,
56 const struct GNUNET_HashCode *hash);
57
58void
59load_message_state (struct GNUNET_MESSENGER_MessageState *state,
60 const char *path);
61
62void
63save_message_state (const struct GNUNET_MESSENGER_MessageState *state,
64 const char *path);
65
66#endif //GNUNET_SERVICE_MESSENGER_MESSAGE_STATE_H
diff --git a/src/service/messenger/gnunet-service-messenger_message_store.c b/src/service/messenger/gnunet-service-messenger_message_store.c
new file mode 100644
index 000000000..1eb275f9b
--- /dev/null
+++ b/src/service/messenger/gnunet-service-messenger_message_store.c
@@ -0,0 +1,677 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2023 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_message_store.c
23 * @brief GNUnet MESSENGER service
24 */
25
26#include "gnunet-service-messenger_message_store.h"
27#include "messenger_api_message.h"
28
29void
30init_message_store (struct GNUNET_MESSENGER_MessageStore *store)
31{
32 GNUNET_assert (store);
33
34 store->storage_messages = NULL;
35
36 store->entries = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
37 store->messages = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
38 store->links = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
39
40 store->rewrite_entries = GNUNET_NO;
41 store->write_links = GNUNET_NO;
42}
43
44
45static enum GNUNET_GenericReturnValue
46iterate_destroy_entries (void *cls,
47 const struct GNUNET_HashCode *key,
48 void *value)
49{
50 struct GNUNET_MESSENGER_MessageEntry *entry = value;
51
52 GNUNET_free (entry);
53
54 return GNUNET_YES;
55}
56
57
58static enum GNUNET_GenericReturnValue
59iterate_destroy_messages (void *cls,
60 const struct GNUNET_HashCode *key,
61 void *value)
62{
63 struct GNUNET_MESSENGER_Message *message = value;
64
65 destroy_message (message);
66
67 return GNUNET_YES;
68}
69
70
71static enum GNUNET_GenericReturnValue
72iterate_destroy_links (void *cls,
73 const struct GNUNET_HashCode *key,
74 void *value)
75{
76 struct GNUNET_HashCode *previous = value;
77
78 GNUNET_free (previous);
79
80 return GNUNET_YES;
81}
82
83
84void
85clear_message_store (struct GNUNET_MESSENGER_MessageStore *store)
86{
87 GNUNET_assert (store);
88
89 if (store->storage_messages)
90 {
91 GNUNET_DISK_file_close (store->storage_messages);
92
93 store->storage_messages = NULL;
94 }
95
96 GNUNET_CONTAINER_multihashmap_iterate (store->entries,
97 iterate_destroy_entries, NULL);
98 GNUNET_CONTAINER_multihashmap_iterate (store->messages,
99 iterate_destroy_messages, NULL);
100 GNUNET_CONTAINER_multihashmap_iterate (store->links, iterate_destroy_links,
101 NULL);
102
103 GNUNET_CONTAINER_multihashmap_destroy (store->entries);
104 GNUNET_CONTAINER_multihashmap_destroy (store->messages);
105 GNUNET_CONTAINER_multihashmap_destroy (store->links);
106}
107
108
109struct GNUNET_MESSENGER_MessageEntryStorage
110{
111 struct GNUNET_HashCode hash;
112 struct GNUNET_MESSENGER_MessageEntry entry;
113};
114
115#define load_message_store_attribute_failed(file, attribute) \
116 sizeof(attribute) != GNUNET_DISK_file_read (file, &(attribute), \
117 sizeof(attribute))
118
119#define save_message_store_attribute_failed(file, attribute) \
120 sizeof(attribute) != GNUNET_DISK_file_write (file, &(attribute), \
121 sizeof(attribute))
122
123static void
124load_message_store_entries (struct GNUNET_MESSENGER_MessageStore *store,
125 const char *filename)
126{
127 enum GNUNET_DISK_AccessPermissions permission = (GNUNET_DISK_PERM_USER_READ);
128
129 struct GNUNET_DISK_FileHandle *entries = GNUNET_DISK_file_open (filename,
130 GNUNET_DISK_OPEN_READ,
131 permission);
132
133 if (! entries)
134 return;
135
136 struct GNUNET_MESSENGER_MessageEntryStorage storage;
137 struct GNUNET_MESSENGER_MessageEntry *entry;
138
139 memset (&storage, 0, sizeof(storage));
140
141 do
142 {
143 entry = NULL;
144
145 if ((load_message_store_attribute_failed (entries, storage.hash)) ||
146 (load_message_store_attribute_failed (entries, storage.entry.offset)) ||
147 (load_message_store_attribute_failed (entries, storage.entry.length)))
148 break;
149
150 entry = GNUNET_new (struct GNUNET_MESSENGER_MessageEntry);
151
152 GNUNET_memcpy (entry, &(storage.entry), sizeof(*entry));
153
154 if ((GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (store->entries,
155 &(storage.hash)))
156 ||
157 (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (store->entries,
158 &(storage.hash), entry,
159 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)))
160 {
161 store->rewrite_entries = GNUNET_YES;
162 break;
163 }
164 }
165 while (entry);
166
167 if (entry)
168 GNUNET_free (entry);
169
170 GNUNET_DISK_file_close (entries);
171}
172
173
174struct GNUNET_MESSENGER_MessageLinkStorage
175{
176 struct GNUNET_HashCode hash;
177 struct GNUNET_MESSENGER_MessageLink link;
178};
179
180static void
181load_message_store_links (struct GNUNET_MESSENGER_MessageStore *store,
182 const char *filename)
183{
184 enum GNUNET_DISK_AccessPermissions permission = (GNUNET_DISK_PERM_USER_READ);
185
186 struct GNUNET_DISK_FileHandle *entries = GNUNET_DISK_file_open (filename,
187 GNUNET_DISK_OPEN_READ,
188 permission);
189
190 if (! entries)
191 return;
192
193 struct GNUNET_MESSENGER_MessageLinkStorage storage;
194 struct GNUNET_MESSENGER_MessageLink *link;
195
196 memset (&storage, 0, sizeof(storage));
197
198 do
199 {
200 link = NULL;
201
202 if ((load_message_store_attribute_failed (entries, storage.hash)) ||
203 (load_message_store_attribute_failed (entries,
204 storage.link.multiple)) ||
205 (load_message_store_attribute_failed (entries, storage.link.first)) ||
206 ((GNUNET_YES == storage.link.multiple) &&
207 (load_message_store_attribute_failed (entries, storage.link.second))))
208 break;
209
210 link = GNUNET_new (struct GNUNET_MESSENGER_MessageLink);
211
212 GNUNET_memcpy (link, &(storage.link), sizeof(*link));
213
214 if ((GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (store->links,
215 &(storage.hash)))
216 ||
217 (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (store->links,
218 &(storage.hash), link,
219 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)))
220
221 break;
222 }
223 while (link);
224
225 if (link)
226 GNUNET_free (link);
227
228 GNUNET_DISK_file_close (entries);
229}
230
231
232void
233load_message_store (struct GNUNET_MESSENGER_MessageStore *store,
234 const char *directory)
235{
236 GNUNET_assert ((store) && (directory));
237
238 enum GNUNET_DISK_AccessPermissions permission = (GNUNET_DISK_PERM_USER_READ
239 | GNUNET_DISK_PERM_USER_WRITE
240 );
241
242 if (store->storage_messages)
243 GNUNET_DISK_file_close (store->storage_messages);
244
245 char *filename;
246 GNUNET_asprintf (&filename, "%s%s", directory, "messages.store");
247
248 if (GNUNET_YES == GNUNET_DISK_file_test (filename))
249 store->storage_messages = GNUNET_DISK_file_open (filename,
250 GNUNET_DISK_OPEN_READWRITE,
251 permission);
252 else
253 store->storage_messages = NULL;
254
255 GNUNET_free (filename);
256
257 if (! store->storage_messages)
258 return;
259
260 GNUNET_asprintf (&filename, "%s%s", directory, "entries.store");
261
262 if (GNUNET_YES == GNUNET_DISK_file_test (filename))
263 load_message_store_entries (store, filename);
264
265 GNUNET_free (filename);
266
267 GNUNET_asprintf (&filename, "%s%s", directory, "links.store");
268
269 if (GNUNET_YES == GNUNET_DISK_file_test (filename))
270 load_message_store_links (store, filename);
271
272 GNUNET_free (filename);
273}
274
275
276struct GNUNET_MESSENGER_ClosureMessageSave
277{
278 struct GNUNET_MESSENGER_MessageStore *store;
279
280 struct GNUNET_DISK_FileHandle *storage;
281};
282
283static enum GNUNET_GenericReturnValue
284iterate_save_entries (void *cls,
285 const struct GNUNET_HashCode *key,
286 void *value)
287{
288 struct GNUNET_MESSENGER_ClosureMessageSave *save = cls;
289 struct GNUNET_MESSENGER_MessageEntry *entry = value;
290
291 GNUNET_DISK_file_write (save->storage, key, sizeof(*key));
292 GNUNET_DISK_file_write (save->storage, &(entry->offset),
293 sizeof(entry->offset));
294 GNUNET_DISK_file_write (save->storage, &(entry->length),
295 sizeof(entry->length));
296
297 return GNUNET_YES;
298}
299
300
301static enum GNUNET_GenericReturnValue
302iterate_save_messages (void *cls,
303 const struct GNUNET_HashCode *key,
304 void *value)
305{
306 struct GNUNET_MESSENGER_ClosureMessageSave *save = cls;
307
308 if (GNUNET_NO != GNUNET_CONTAINER_multihashmap_contains (save->store->entries,
309 key))
310 return GNUNET_YES;
311
312 struct GNUNET_MESSENGER_Message *message = value;
313 struct GNUNET_MESSENGER_MessageEntryStorage storage;
314
315 GNUNET_memcpy (&(storage.hash), key, sizeof(storage.hash));
316
317 storage.entry.length = get_message_size (message, GNUNET_YES);
318 storage.entry.offset = GNUNET_DISK_file_seek (save->store->storage_messages,
319 0, GNUNET_DISK_SEEK_END);
320
321 if ((GNUNET_SYSERR == storage.entry.offset) ||
322 (save_message_store_attribute_failed (save->storage, storage.hash)) ||
323 (save_message_store_attribute_failed (save->storage,
324 storage.entry.offset)) ||
325 (save_message_store_attribute_failed (save->storage,
326 storage.entry.length)))
327 return GNUNET_YES;
328
329 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Storing message with hash: %s\n",
330 GNUNET_h2s (&(storage.hash)));
331
332 char *buffer = GNUNET_malloc (storage.entry.length);
333
334 encode_message (message, storage.entry.length, buffer, GNUNET_YES);
335
336 GNUNET_DISK_file_write (save->store->storage_messages, buffer,
337 storage.entry.length);
338
339 GNUNET_free (buffer);
340 return GNUNET_YES;
341}
342
343
344static enum GNUNET_GenericReturnValue
345iterate_save_links (void *cls,
346 const struct GNUNET_HashCode *key,
347 void *value)
348{
349 struct GNUNET_MESSENGER_ClosureMessageSave *save = cls;
350 struct GNUNET_MESSENGER_MessageLink *link = value;
351
352 GNUNET_DISK_file_write (save->storage, key, sizeof(*key));
353 GNUNET_DISK_file_write (save->storage, &(link->multiple),
354 sizeof(link->multiple));
355 GNUNET_DISK_file_write (save->storage, &(link->first), sizeof(link->first));
356
357 if (GNUNET_YES == link->multiple)
358 GNUNET_DISK_file_write (save->storage, &(link->second),
359 sizeof(link->second));
360
361 return GNUNET_YES;
362}
363
364
365void
366save_message_store (struct GNUNET_MESSENGER_MessageStore *store,
367 const char *directory)
368{
369 GNUNET_assert ((store) && (directory));
370
371 struct GNUNET_MESSENGER_ClosureMessageSave save;
372
373 enum GNUNET_DISK_AccessPermissions permission = (GNUNET_DISK_PERM_USER_READ
374 | GNUNET_DISK_PERM_USER_WRITE
375 );
376
377 char *filename;
378
379 if (GNUNET_YES != store->write_links)
380 goto save_entries;
381
382 GNUNET_asprintf (&filename, "%s%s", directory, "links.store");
383
384 save.store = store;
385 save.storage = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_WRITE
386 | GNUNET_DISK_OPEN_CREATE, permission);
387
388 GNUNET_free (filename);
389
390 if (! save.storage)
391 goto save_entries;
392
393 if (GNUNET_SYSERR == GNUNET_DISK_file_seek (save.storage, 0,
394 GNUNET_DISK_SEEK_SET))
395 goto close_links;
396
397 GNUNET_CONTAINER_multihashmap_iterate (store->links, iterate_save_links,
398 &save);
399 store->write_links = GNUNET_NO;
400
401close_links:
402 GNUNET_DISK_file_close (save.storage);
403
404save_entries:
405 GNUNET_asprintf (&filename, "%s%s", directory, "entries.store");
406
407 save.store = store;
408 save.storage = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_WRITE
409 | GNUNET_DISK_OPEN_CREATE, permission);
410
411 GNUNET_free (filename);
412
413 if (! save.storage)
414 return;
415
416 if (GNUNET_YES == store->rewrite_entries)
417 {
418 if (GNUNET_SYSERR == GNUNET_DISK_file_seek (save.storage, 0,
419 GNUNET_DISK_SEEK_SET))
420 goto close_entries;
421
422 GNUNET_CONTAINER_multihashmap_iterate (store->entries, iterate_save_entries,
423 &save);
424 store->rewrite_entries = GNUNET_NO;
425 }
426 else if (GNUNET_SYSERR == GNUNET_DISK_file_seek (save.storage, 0,
427 GNUNET_DISK_SEEK_END))
428 goto close_entries;
429
430 if (store->storage_messages)
431 GNUNET_DISK_file_close (store->storage_messages);
432
433 GNUNET_asprintf (&filename, "%s%s", directory, "messages.store");
434
435 store->storage_messages = GNUNET_DISK_file_open (filename,
436 GNUNET_DISK_OPEN_READWRITE
437 | GNUNET_DISK_OPEN_CREATE,
438 permission);
439
440 GNUNET_free (filename);
441
442 if (store->storage_messages)
443 {
444 GNUNET_CONTAINER_multihashmap_iterate (store->messages,
445 iterate_save_messages, &save);
446
447 GNUNET_DISK_file_sync (store->storage_messages);
448 GNUNET_DISK_file_sync (save.storage);
449 }
450
451close_entries:
452 GNUNET_DISK_file_close (save.storage);
453}
454
455
456enum GNUNET_GenericReturnValue
457contains_store_message (const struct GNUNET_MESSENGER_MessageStore *store,
458 const struct GNUNET_HashCode *hash)
459{
460 GNUNET_assert ((store) && (hash));
461
462 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (store->messages,
463 hash))
464 return GNUNET_YES;
465
466 return GNUNET_CONTAINER_multihashmap_contains (store->entries, hash);
467}
468
469
470const struct GNUNET_MESSENGER_Message*
471get_store_message (struct GNUNET_MESSENGER_MessageStore *store,
472 const struct GNUNET_HashCode *hash)
473{
474 GNUNET_assert ((store) && (hash));
475
476 struct GNUNET_MESSENGER_Message *message = GNUNET_CONTAINER_multihashmap_get (
477 store->messages, hash);
478
479 if (message)
480 return message;
481
482 if (! store->storage_messages)
483 return NULL;
484
485 const struct GNUNET_MESSENGER_MessageEntry *entry =
486 GNUNET_CONTAINER_multihashmap_get (store->entries, hash);
487
488 if (! entry)
489 return NULL;
490
491 if (entry->offset != GNUNET_DISK_file_seek (store->storage_messages,
492 entry->offset,
493 GNUNET_DISK_SEEK_SET))
494 return message;
495
496 char *buffer = GNUNET_malloc (entry->length);
497
498 if (! buffer)
499 return NULL;
500
501 if ((GNUNET_DISK_file_read (store->storage_messages, buffer, entry->length) !=
502 entry->length) ||
503 (entry->length < get_message_kind_size (GNUNET_MESSENGER_KIND_UNKNOWN,
504 GNUNET_YES)))
505 goto free_buffer;
506
507 message = create_message (GNUNET_MESSENGER_KIND_UNKNOWN);
508
509 enum GNUNET_GenericReturnValue decoding;
510 decoding = decode_message (message, entry->length, buffer,
511 GNUNET_YES, NULL);
512
513 struct GNUNET_HashCode check;
514 hash_message (message, entry->length, buffer, &check);
515
516 if ((GNUNET_YES != decoding) || (GNUNET_CRYPTO_hash_cmp (hash, &check) != 0))
517 {
518 if (GNUNET_YES != GNUNET_CONTAINER_multihashmap_remove (store->entries,
519 hash, entry))
520 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
521 "Corrupted entry could not be removed from store: %s\n",
522 GNUNET_h2s (hash));
523
524 store->rewrite_entries = GNUNET_YES;
525
526 goto free_message;
527 }
528
529 if (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (store->messages, hash,
530 message,
531 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
532
533 goto free_buffer;
534
535 free_message : destroy_message (message);
536 message = NULL;
537
538free_buffer:
539 GNUNET_free (buffer);
540
541 return message;
542}
543
544
545const struct GNUNET_MESSENGER_MessageLink*
546get_store_message_link (struct GNUNET_MESSENGER_MessageStore *store,
547 const struct GNUNET_HashCode *hash,
548 enum GNUNET_GenericReturnValue deleted_only)
549{
550 if (deleted_only)
551 goto get_link;
552
553 const struct GNUNET_MESSENGER_Message *message = get_store_message (store,
554 hash);
555
556 if (! message)
557 goto get_link;
558
559 static struct GNUNET_MESSENGER_MessageLink link;
560
561 GNUNET_memcpy (&(link.first), &(message->header.previous),
562 sizeof(link.first));
563
564 link.multiple = GNUNET_MESSENGER_KIND_MERGE == message->header.kind?
565 GNUNET_YES : GNUNET_NO;
566
567 if (GNUNET_YES == link.multiple)
568 GNUNET_memcpy (&(link.second), &(message->body.merge.previous),
569 sizeof(link.second));
570 else
571 GNUNET_memcpy (&(link.second), &(message->header.previous),
572 sizeof(link.second));
573
574 return &link;
575
576get_link:
577 return GNUNET_CONTAINER_multihashmap_get (store->links, hash);
578}
579
580
581enum GNUNET_GenericReturnValue
582put_store_message (struct GNUNET_MESSENGER_MessageStore *store,
583 const struct GNUNET_HashCode *hash,
584 struct GNUNET_MESSENGER_Message *message)
585{
586 GNUNET_assert ((store) && (hash) && (message));
587
588 return GNUNET_CONTAINER_multihashmap_put (store->messages, hash, message,
589 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
590}
591
592
593static void
594add_link (struct GNUNET_MESSENGER_MessageStore *store,
595 const struct GNUNET_HashCode *hash,
596 const struct GNUNET_MESSENGER_Message *message)
597{
598 struct GNUNET_MESSENGER_MessageLink *link = GNUNET_new (struct
599 GNUNET_MESSENGER_MessageLink);
600
601 GNUNET_memcpy (&(link->first), &(message->header.previous),
602 sizeof(link->first));
603
604 link->multiple = GNUNET_MESSENGER_KIND_MERGE == message->header.kind?
605 GNUNET_YES : GNUNET_NO;
606
607 if (GNUNET_YES == link->multiple)
608 GNUNET_memcpy (&(link->second), &(message->body.merge.previous),
609 sizeof(link->second));
610 else
611 GNUNET_memcpy (&(link->second), &(message->header.previous),
612 sizeof(link->second));
613
614 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (store->links, hash, link,
615 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
616
617 GNUNET_free (link);
618 else
619 store->write_links = GNUNET_YES;
620}
621
622
623enum GNUNET_GenericReturnValue
624delete_store_message (struct GNUNET_MESSENGER_MessageStore *store,
625 const struct GNUNET_HashCode *hash)
626{
627 GNUNET_assert ((store) && (hash));
628
629 const struct GNUNET_MESSENGER_MessageEntry *entry =
630 GNUNET_CONTAINER_multihashmap_get (store->entries, hash);
631
632 if (! entry)
633 goto clear_memory;
634
635 const struct GNUNET_MESSENGER_Message *message = get_store_message (store,
636 hash);
637
638 if (message)
639 add_link (store, hash, message);
640
641 if (! store->storage_messages)
642 goto clear_entry;
643
644 if (entry->offset != GNUNET_DISK_file_seek (store->storage_messages,
645 entry->offset,
646 GNUNET_DISK_SEEK_SET))
647 return GNUNET_SYSERR;
648
649 char *clear_buffer = GNUNET_malloc (entry->length);
650
651 if (! clear_buffer)
652 return GNUNET_SYSERR;
653
654 GNUNET_CRYPTO_zero_keys (clear_buffer, entry->length);
655
656 if ((entry->length != GNUNET_DISK_file_write (store->storage_messages,
657 clear_buffer, entry->length)) ||
658 (GNUNET_OK
659 !=
660 GNUNET_DISK_file_sync (
661 store->storage_messages)))
662 {
663 GNUNET_free (clear_buffer);
664 return GNUNET_SYSERR;
665 }
666
667 GNUNET_free (clear_buffer);
668
669clear_entry:
670 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (store->entries, hash,
671 entry))
672 store->rewrite_entries = GNUNET_YES;
673
674clear_memory:
675 GNUNET_CONTAINER_multihashmap_remove_all (store->messages, hash);
676 return GNUNET_OK;
677}
diff --git a/src/service/messenger/gnunet-service-messenger_message_store.h b/src/service/messenger/gnunet-service-messenger_message_store.h
new file mode 100644
index 000000000..9daf8fd11
--- /dev/null
+++ b/src/service/messenger/gnunet-service-messenger_message_store.h
@@ -0,0 +1,167 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2023 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_message_store.h
23 * @brief GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_SERVICE_MESSENGER_MESSAGE_STORE_H
27#define GNUNET_SERVICE_MESSENGER_MESSAGE_STORE_H
28
29#include "gnunet_util_lib.h"
30
31struct GNUNET_MESSENGER_MessageEntry
32{
33 off_t offset;
34 uint16_t length;
35};
36
37struct GNUNET_MESSENGER_Message;
38
39struct GNUNET_MESSENGER_MessageLink
40{
41 uint8_t multiple;
42
43 struct GNUNET_HashCode first;
44 struct GNUNET_HashCode second;
45};
46
47struct GNUNET_MESSENGER_MessageStore
48{
49 struct GNUNET_DISK_FileHandle *storage_messages;
50
51 struct GNUNET_CONTAINER_MultiHashMap *entries;
52 struct GNUNET_CONTAINER_MultiHashMap *messages;
53 struct GNUNET_CONTAINER_MultiHashMap *links;
54
55 enum GNUNET_GenericReturnValue rewrite_entries;
56 enum GNUNET_GenericReturnValue write_links;
57};
58
59/**
60 * Initializes a message <i>store</i> as fully empty.
61 *
62 * @param[out] store Message store
63 */
64void
65init_message_store (struct GNUNET_MESSENGER_MessageStore *store);
66
67/**
68 * Clears a message <i>store</i>, wipes its content and deallocates its memory.
69 *
70 * @param[in,out] store Message store
71 */
72void
73clear_message_store (struct GNUNET_MESSENGER_MessageStore *store);
74
75/**
76 * Loads messages from a <i>directory</i> into a message <i>store</i>.
77 *
78 * @param[out] store Message store
79 * @param[in] directory Path to a directory
80 */
81void
82load_message_store (struct GNUNET_MESSENGER_MessageStore *store,
83 const char *directory);
84
85/**
86 * Saves messages from a message <i>store</i> into a <i>directory</i>.
87 *
88 * @param[in] store Message store
89 * @param[in] directory Path to a directory
90 */
91void
92save_message_store (struct GNUNET_MESSENGER_MessageStore *store,
93 const char *directory);
94
95/**
96 * Checks if a message matching a given <i>hash</i> is stored in a message <i>store</i>.
97 * The function returns #GNUNET_YES if a match is found, #GNUNET_NO otherwise.
98 *
99 * The message has not to be loaded from disk into memory for this check!
100 *
101 * @param[in] store Message store
102 * @param[in] hash Hash of message
103 * @return #GNUNET_YES on match, otherwise #GNUNET_NO
104 */
105enum GNUNET_GenericReturnValue
106contains_store_message (const struct GNUNET_MESSENGER_MessageStore *store,
107 const struct GNUNET_HashCode *hash);
108
109/**
110 * Returns the message from a message <i>store</i> matching a given <i>hash</i>. If no matching
111 * message is found, NULL gets returned.
112 *
113 * This function requires the message to be loaded into memory!
114 * @see contains_store_message()
115 *
116 * @param[in,out] store Message store
117 * @param[in] hash Hash of message
118 * @return Message or NULL
119 */
120const struct GNUNET_MESSENGER_Message*
121get_store_message (struct GNUNET_MESSENGER_MessageStore *store,
122 const struct GNUNET_HashCode *hash);
123
124/**
125 * Returns the message link from a message <i>store</i> matching a given <i>hash</i>. If the
126 * flag is set to #GNUNET_YES, only links from deleted messages will be returned or NULL.
127 *
128 * Otherwise message links will also returned for messages found in the store under the given
129 * hash. The link which will be returned copies link information from the message for
130 * temporary usage.
131 *
132 * @param[in,out] store Message store
133 * @param[in] hash Hash of message
134 * @param[in] deleted_only Flag
135 * @return Message link or NULL
136 */
137const struct GNUNET_MESSENGER_MessageLink*
138get_store_message_link (struct GNUNET_MESSENGER_MessageStore *store,
139 const struct GNUNET_HashCode *hash,
140 enum GNUNET_GenericReturnValue deleted_only);
141
142/**
143 * Stores a message into the message store. The result indicates if the operation was successful.
144 *
145 * @param[in,out] store Message store
146 * @param[in] hash Hash of message
147 * @param[in,out] message Message
148 * @return #GNUNET_OK on success, otherwise #GNUNET_NO
149 */
150enum GNUNET_GenericReturnValue
151put_store_message (struct GNUNET_MESSENGER_MessageStore *store,
152 const struct GNUNET_HashCode *hash,
153 struct GNUNET_MESSENGER_Message *message);
154
155/**
156 * Deletes a message in the message store. It will be removed from disk space and memory. The result
157 * indicates if the operation was successful.
158 *
159 * @param[in,out] store Message store
160 * @param[in] hash Hash of message
161 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
162 */
163enum GNUNET_GenericReturnValue
164delete_store_message (struct GNUNET_MESSENGER_MessageStore *store,
165 const struct GNUNET_HashCode *hash);
166
167#endif //GNUNET_SERVICE_MESSENGER_MESSAGE_STORE_H
diff --git a/src/service/messenger/gnunet-service-messenger_operation.c b/src/service/messenger/gnunet-service-messenger_operation.c
new file mode 100644
index 000000000..66cefb9ac
--- /dev/null
+++ b/src/service/messenger/gnunet-service-messenger_operation.c
@@ -0,0 +1,238 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2021, 2023 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_operation.c
23 * @brief GNUnet MESSENGER service
24 */
25
26#include "gnunet-service-messenger_operation.h"
27
28#include "gnunet-service-messenger_operation_store.h"
29
30struct GNUNET_MESSENGER_Operation*
31create_operation (const struct GNUNET_HashCode *hash)
32{
33 GNUNET_assert (hash);
34
35 struct GNUNET_MESSENGER_Operation *op = GNUNET_new (struct
36 GNUNET_MESSENGER_Operation);
37
38 op->type = GNUNET_MESSENGER_OP_UNKNOWN;
39 GNUNET_memcpy (&(op->hash), hash, sizeof(*hash));
40 op->timestamp = GNUNET_TIME_absolute_get_zero_ ();
41 op->store = NULL;
42 op->task = NULL;
43
44 return op;
45}
46
47
48void
49destroy_operation (struct GNUNET_MESSENGER_Operation *op)
50{
51 GNUNET_assert (op);
52
53 if (op->task)
54 GNUNET_SCHEDULER_cancel (op->task);
55
56 GNUNET_free (op);
57}
58
59
60static void
61callback_operation (void *cls);
62
63struct GNUNET_MESSENGER_Operation*
64load_operation (struct GNUNET_MESSENGER_OperationStore *store,
65 const char *path)
66{
67 GNUNET_assert ((store) && (path));
68
69 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Load operation configuration: %s\n",
70 path);
71
72 struct GNUNET_CONFIGURATION_Handle *cfg = GNUNET_CONFIGURATION_create ();
73 struct GNUNET_MESSENGER_Operation *op = NULL;
74
75 if (GNUNET_OK != GNUNET_CONFIGURATION_parse (cfg, path))
76 goto destroy_config;
77
78 struct GNUNET_HashCode hash;
79
80 if (GNUNET_OK != GNUNET_CONFIGURATION_get_data (cfg, "operation", "hash",
81 &hash, sizeof(hash)))
82 goto destroy_config;
83
84 op = create_operation (&hash);
85
86 unsigned long long type_number;
87 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, "operation",
88 "type", &type_number))
89 switch (type_number)
90 {
91 case GNUNET_MESSENGER_OP_REQUEST:
92 op->type = GNUNET_MESSENGER_OP_REQUEST;
93 break;
94 case GNUNET_MESSENGER_OP_DELETE:
95 op->type = GNUNET_MESSENGER_OP_DELETE;
96 break;
97 case GNUNET_MESSENGER_OP_MERGE:
98 op->type = GNUNET_MESSENGER_OP_MERGE;
99 break;
100 default:
101 break;
102 }
103
104 if ((GNUNET_MESSENGER_OP_UNKNOWN == op->type) ||
105 (GNUNET_OK != GNUNET_CONFIGURATION_get_data (cfg, "operation",
106 "timestamp",
107 &(op->timestamp),
108 sizeof(op->timestamp))))
109 {
110 destroy_operation (op);
111 op = NULL;
112 goto destroy_config;
113 }
114
115 const struct GNUNET_TIME_Relative delay = GNUNET_TIME_absolute_get_remaining (
116 op->timestamp);
117
118 op->task = GNUNET_SCHEDULER_add_delayed_with_priority (
119 delay,
120 GNUNET_SCHEDULER_PRIORITY_BACKGROUND,
121 callback_operation,
122 op
123 );
124
125 op->store = store;
126
127destroy_config:
128 GNUNET_CONFIGURATION_destroy (cfg);
129
130 return op;
131}
132
133
134void
135save_operation (const struct GNUNET_MESSENGER_Operation *op,
136 const char *path)
137{
138 GNUNET_assert ((path) && (op));
139
140 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Save operation configuration: %s\n",
141 path);
142
143 struct GNUNET_CONFIGURATION_Handle *cfg = GNUNET_CONFIGURATION_create ();
144
145 char *hash_data;
146 hash_data = GNUNET_STRINGS_data_to_string_alloc (&(op->hash),
147 sizeof(op->hash));
148
149 if (hash_data)
150 {
151 GNUNET_CONFIGURATION_set_value_string (cfg, "operation", "hash", hash_data);
152
153 GNUNET_free (hash_data);
154 }
155
156 GNUNET_CONFIGURATION_set_value_number (cfg, "operation", "type", op->type);
157
158 char *timestamp_data;
159 timestamp_data = GNUNET_STRINGS_data_to_string_alloc (&(op->timestamp),
160 sizeof(op->timestamp));
161
162 if (timestamp_data)
163 {
164 GNUNET_CONFIGURATION_set_value_string (cfg, "operation", "timestamp",
165 timestamp_data);
166
167 GNUNET_free (timestamp_data);
168 }
169
170 GNUNET_CONFIGURATION_write (cfg, path);
171 GNUNET_CONFIGURATION_destroy (cfg);
172}
173
174
175extern void
176callback_store_operation (struct GNUNET_MESSENGER_OperationStore *store,
177 enum GNUNET_MESSENGER_OperationType type,
178 const struct GNUNET_HashCode *hash);
179
180static void
181callback_operation (void *cls)
182{
183 struct GNUNET_MESSENGER_Operation *op = cls;
184
185 op->task = NULL;
186
187 callback_store_operation (op->store, op->type, &(op->hash));
188}
189
190
191enum GNUNET_GenericReturnValue
192start_operation (struct GNUNET_MESSENGER_Operation *op,
193 enum GNUNET_MESSENGER_OperationType type,
194 struct GNUNET_MESSENGER_OperationStore *store,
195 struct GNUNET_TIME_Relative delay)
196{
197 GNUNET_assert ((op) && (store));
198
199 if (op->task)
200 return GNUNET_SYSERR;
201
202 const struct GNUNET_TIME_Absolute timestamp = GNUNET_TIME_absolute_add (
203 GNUNET_TIME_absolute_get (),
204 delay
205 );
206
207 op->task = GNUNET_SCHEDULER_add_delayed_with_priority (
208 delay,
209 GNUNET_SCHEDULER_PRIORITY_BACKGROUND,
210 callback_operation,
211 op
212 );
213
214 op->type = type;
215 op->timestamp = timestamp;
216 op->store = store;
217
218 return GNUNET_OK;
219}
220
221
222enum GNUNET_GenericReturnValue
223stop_operation (struct GNUNET_MESSENGER_Operation *op)
224{
225 GNUNET_assert (op);
226
227 if (! op->task)
228 return GNUNET_SYSERR;
229
230 GNUNET_SCHEDULER_cancel (op->task);
231 op->task = NULL;
232
233 op->type = GNUNET_MESSENGER_OP_UNKNOWN;
234 op->timestamp = GNUNET_TIME_absolute_get_zero_ ();
235 op->store = NULL;
236
237 return GNUNET_OK;
238}
diff --git a/src/service/messenger/gnunet-service-messenger_operation.h b/src/service/messenger/gnunet-service-messenger_operation.h
new file mode 100644
index 000000000..26282bea8
--- /dev/null
+++ b/src/service/messenger/gnunet-service-messenger_operation.h
@@ -0,0 +1,128 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2021--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_operation.h
23 * @brief GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_SERVICE_MESSENGER_OPERATION_H
27#define GNUNET_SERVICE_MESSENGER_OPERATION_H
28
29#include "gnunet_util_lib.h"
30#include "gnunet_scheduler_lib.h"
31#include "gnunet_time_lib.h"
32
33enum GNUNET_MESSENGER_OperationType
34{
35 GNUNET_MESSENGER_OP_REQUEST = 1,
36 GNUNET_MESSENGER_OP_DELETE = 2,
37 GNUNET_MESSENGER_OP_MERGE = 3,
38
39 GNUNET_MESSENGER_OP_UNKNOWN = 0
40};
41
42struct GNUNET_MESSENGER_OperationStore;
43
44struct GNUNET_MESSENGER_Operation
45{
46 enum GNUNET_MESSENGER_OperationType type;
47
48 struct GNUNET_HashCode hash;
49 struct GNUNET_TIME_Absolute timestamp;
50
51 struct GNUNET_MESSENGER_OperationStore *store;
52 struct GNUNET_SCHEDULER_Task *task;
53};
54
55/**
56 * Creates and allocates a new operation under a given <i>hash</i>.
57 *
58 * @param[in] hash Hash of message
59 */
60struct GNUNET_MESSENGER_Operation*
61create_operation (const struct GNUNET_HashCode *hash);
62
63/**
64 * Destroys an operation and frees its memory fully.
65 *
66 * @param[in,out] op Operation
67 */
68void
69destroy_operation (struct GNUNET_MESSENGER_Operation *op);
70
71/**
72 * Loads data from a configuration file at a selected <i>path</i> into
73 * a new allocated and created operation for a specific operation
74 * <i>store</i> if the required information could be read successfully.
75 *
76 * The method will return the new operation and it will be started
77 * automatically to match its timestamp of execution.
78 *
79 * If the method fails to restore any valid operation from the file,
80 * NULL gets returned instead.
81 *
82 * @param[in,out] store Operation store
83 * @param[in] path Path of a configuration file
84 */
85struct GNUNET_MESSENGER_Operation*
86load_operation (struct GNUNET_MESSENGER_OperationStore *store,
87 const char *path);
88
89/**
90 * Saves data from an <i>operation</i> into a configuration file at a
91 * selected <i>path</i> which can be load to restore the operation
92 * completely and continue its process.
93 *
94 * @param[in] op Operation
95 * @param[in] path Path of a configuration file
96 */
97void
98save_operation (const struct GNUNET_MESSENGER_Operation *op,
99 const char *path);
100
101/**
102 * Starts an inactive operation with a given <i>delay</i> in a
103 * specific operation <i>store</i>. The method will replace the
104 * operations type to process it correctly. An operation can't be
105 * started twice, it has to be stopped or fully processed first.
106 *
107 * @param[in,out] op Operation
108 * @param[in] type Type of operation
109 * @param[in,out] store Operation store
110 * @param[in] delay Delay
111 * @return #GNUNET_OK on success, otherwise #GNUNET_SYSERR
112 */
113enum GNUNET_GenericReturnValue
114start_operation (struct GNUNET_MESSENGER_Operation *op,
115 enum GNUNET_MESSENGER_OperationType type,
116 struct GNUNET_MESSENGER_OperationStore *store,
117 struct GNUNET_TIME_Relative delay);
118
119/**
120 * Stops an active operation and resets its type to be
121 * #GNUNET_MESSENGER_OP_UNKNOWN.
122 *
123 * @return #GNUNET_OK on success, otherwise #GNUNET_SYSERR
124 */
125enum GNUNET_GenericReturnValue
126stop_operation (struct GNUNET_MESSENGER_Operation *op);
127
128#endif //GNUNET_SERVICE_MESSENGER_OPERATION_H
diff --git a/src/service/messenger/gnunet-service-messenger_operation_store.c b/src/service/messenger/gnunet-service-messenger_operation_store.c
new file mode 100644
index 000000000..630ed6dbd
--- /dev/null
+++ b/src/service/messenger/gnunet-service-messenger_operation_store.c
@@ -0,0 +1,268 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2021--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_operation_store.c
23 * @brief GNUnet MESSENGER service
24 */
25
26#include "platform.h"
27#include "gnunet-service-messenger_operation_store.h"
28
29#include "gnunet-service-messenger_operation.h"
30#include "gnunet-service-messenger_room.h"
31
32void
33init_operation_store (struct GNUNET_MESSENGER_OperationStore *store,
34 struct GNUNET_MESSENGER_SrvRoom *room)
35{
36 GNUNET_assert ((store) && (room));
37
38 store->room = room;
39 store->operations = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
40}
41
42
43static enum GNUNET_GenericReturnValue
44iterate_destroy_operations (void *cls,
45 const struct GNUNET_HashCode *key,
46 void *value)
47{
48 struct GNUNET_MESSENGER_Operation *op = value;
49
50 destroy_operation (op);
51
52 return GNUNET_YES;
53}
54
55
56void
57clear_operation_store (struct GNUNET_MESSENGER_OperationStore *store)
58{
59 GNUNET_assert (store);
60
61 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Clear operation store of room: %s\n",
62 GNUNET_h2s (get_srv_room_key (store->room)));
63
64 GNUNET_CONTAINER_multihashmap_iterate (store->operations,
65 iterate_destroy_operations, NULL);
66 GNUNET_CONTAINER_multihashmap_destroy (store->operations);
67}
68
69
70static enum GNUNET_GenericReturnValue
71callback_scan_for_operations (void *cls,
72 const char *filename)
73{
74 struct GNUNET_MESSENGER_OperationStore *store = cls;
75
76 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
77 return GNUNET_OK;
78
79 if ((strlen (filename) <= 4) || (0 != strcmp (filename + strlen (filename)
80 - 4, ".cfg")))
81 return GNUNET_OK;
82
83 struct GNUNET_MESSENGER_Operation *op = load_operation (store, filename);
84
85 if ((op) && (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (
86 store->operations,
87 &(op->hash), op,
88 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)))
89 {
90 destroy_operation (op);
91 }
92
93 return GNUNET_OK;
94}
95
96
97void
98load_operation_store (struct GNUNET_MESSENGER_OperationStore *store,
99 const char *directory)
100{
101 GNUNET_assert ((store) && (directory));
102
103 char *load_dir;
104 GNUNET_asprintf (&load_dir, "%s%s%c", directory, "operations", DIR_SEPARATOR);
105
106 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
107 "Load operation store from directory: %s\n",
108 load_dir);
109
110 if (GNUNET_OK == GNUNET_DISK_directory_test (load_dir, GNUNET_YES))
111 GNUNET_DISK_directory_scan (load_dir, callback_scan_for_operations, store);
112
113 GNUNET_free (load_dir);
114}
115
116
117static enum GNUNET_GenericReturnValue
118iterate_save_operations (void *cls,
119 const struct GNUNET_HashCode *key,
120 void *value)
121{
122 const char *save_dir = cls;
123
124 struct GNUNET_MESSENGER_Operation *op = value;
125
126 if (! op)
127 return GNUNET_YES;
128
129 char *op_dir;
130 GNUNET_asprintf (&op_dir, "%s%s.cfg", save_dir, GNUNET_h2s (key));
131 save_operation (op, op_dir);
132
133 GNUNET_free (op_dir);
134 return GNUNET_YES;
135}
136
137
138void
139save_operation_store (const struct GNUNET_MESSENGER_OperationStore *store,
140 const char *directory)
141{
142 GNUNET_assert ((store) && (directory));
143
144 char *save_dir;
145 GNUNET_asprintf (&save_dir, "%s%s%c", directory, "operations", DIR_SEPARATOR);
146
147 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
148 "Save operation store to directory: %s\n",
149 save_dir);
150
151 if ((GNUNET_YES == GNUNET_DISK_directory_test (save_dir, GNUNET_NO)) ||
152 (GNUNET_OK == GNUNET_DISK_directory_create (save_dir)))
153 GNUNET_CONTAINER_multihashmap_iterate (store->operations,
154 iterate_save_operations, save_dir);
155
156 GNUNET_free (save_dir);
157}
158
159
160enum GNUNET_MESSENGER_OperationType
161get_store_operation_type (const struct GNUNET_MESSENGER_OperationStore *store,
162 const struct GNUNET_HashCode *hash)
163{
164 GNUNET_assert ((store) && (hash));
165
166 struct GNUNET_MESSENGER_Operation *op = GNUNET_CONTAINER_multihashmap_get (
167 store->operations, hash);
168
169 if (! op)
170 return GNUNET_MESSENGER_OP_UNKNOWN;
171
172 return op->type;
173}
174
175
176enum GNUNET_GenericReturnValue
177use_store_operation (struct GNUNET_MESSENGER_OperationStore *store,
178 const struct GNUNET_HashCode *hash,
179 enum GNUNET_MESSENGER_OperationType type,
180 struct GNUNET_TIME_Relative delay)
181{
182 GNUNET_assert ((store) && (hash));
183
184 struct GNUNET_MESSENGER_Operation *op = GNUNET_CONTAINER_multihashmap_get (
185 store->operations, hash);
186
187 if (op)
188 goto use_op;
189
190 op = create_operation (hash);
191
192 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (store->operations, hash,
193 op,
194 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
195 {
196 destroy_operation (op);
197
198 return GNUNET_SYSERR;
199 }
200
201use_op:
202 if ((op->type != GNUNET_MESSENGER_OP_UNKNOWN) &&
203 (type == GNUNET_MESSENGER_OP_DELETE))
204 stop_operation (op);
205
206 return start_operation (op, type, store, delay);
207}
208
209
210void
211cancel_store_operation (struct GNUNET_MESSENGER_OperationStore *store,
212 const struct GNUNET_HashCode *hash)
213{
214 GNUNET_assert ((store) && (hash));
215
216 struct GNUNET_MESSENGER_Operation *op = GNUNET_CONTAINER_multihashmap_get (
217 store->operations, hash);
218
219 if (! op)
220 return;
221
222 stop_operation (op);
223
224 if (GNUNET_YES != GNUNET_CONTAINER_multihashmap_remove (store->operations,
225 hash, op))
226 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
227 "Canceled operation could not be removed: %s\n",
228 GNUNET_h2s (hash));
229
230 destroy_operation (op);
231}
232
233
234extern void
235callback_room_deletion (struct GNUNET_MESSENGER_SrvRoom *room,
236 const struct GNUNET_HashCode *hash);
237
238extern void
239callback_room_merge (struct GNUNET_MESSENGER_SrvRoom *room,
240 const struct GNUNET_HashCode *hash);
241
242void
243callback_store_operation (struct GNUNET_MESSENGER_OperationStore *store,
244 enum GNUNET_MESSENGER_OperationType type,
245 const struct GNUNET_HashCode *hash)
246{
247 GNUNET_assert ((store) && (hash));
248
249 struct GNUNET_HashCode op_hash;
250 GNUNET_memcpy (&op_hash, hash, sizeof(op_hash));
251 cancel_store_operation (store, &op_hash);
252
253 struct GNUNET_MESSENGER_SrvRoom *room = store->room;
254
255 switch (type)
256 {
257 case GNUNET_MESSENGER_OP_REQUEST:
258 break;
259 case GNUNET_MESSENGER_OP_DELETE:
260 callback_room_deletion (room, &op_hash);
261 break;
262 case GNUNET_MESSENGER_OP_MERGE:
263 callback_room_merge (room, &op_hash);
264 break;
265 default:
266 break;
267 }
268}
diff --git a/src/service/messenger/gnunet-service-messenger_operation_store.h b/src/service/messenger/gnunet-service-messenger_operation_store.h
new file mode 100644
index 000000000..9b1c3259a
--- /dev/null
+++ b/src/service/messenger/gnunet-service-messenger_operation_store.h
@@ -0,0 +1,129 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2021, 2023 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_operation_store.h
23 * @brief GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_SERVICE_MESSENGER_OPERATION_STORE_H
27#define GNUNET_SERVICE_MESSENGER_OPERATION_STORE_H
28
29#include "gnunet_util_lib.h"
30#include "gnunet_time_lib.h"
31
32struct GNUNET_MESSENGER_SrvRoom;
33
34struct GNUNET_MESSENGER_OperationStore
35{
36 struct GNUNET_MESSENGER_SrvRoom *room;
37
38 struct GNUNET_CONTAINER_MultiHashMap *operations;
39};
40
41/**
42 * Initializes an operation <i>store</i> as fully empty with a given <i>room</i>.
43 *
44 * @param[out] store Operation store
45 * @param[in,out] room Room
46 */
47void
48init_operation_store (struct GNUNET_MESSENGER_OperationStore *store,
49 struct GNUNET_MESSENGER_SrvRoom *room);
50
51/**
52 * Clears an operation <i>store</i>, stops all operations and deallocates its memory.
53 *
54 * @param[in,out] store Operation store
55 */
56void
57clear_operation_store (struct GNUNET_MESSENGER_OperationStore *store);
58
59/**
60 * Loads operations from a <i>directory</i> into an operation <i>store</i>.
61 *
62 * @param[out] store Operation store
63 * @param[in] directory Path to a directory
64 */
65void
66load_operation_store (struct GNUNET_MESSENGER_OperationStore *store,
67 const char *directory);
68
69/**
70 * Saves operations from an operation <i>store</i> into a <i>directory</i>.
71 *
72 * @param[in] store Operation store
73 * @param[in] directory Path to a directory
74 */
75void
76save_operation_store (const struct GNUNET_MESSENGER_OperationStore *store,
77 const char *directory);
78
79/**
80 * Returns the type of the active operation under a given <i>hash</i> in
81 * a specific operation <i>store</i>. If there is no active operation under
82 * the given <i>hash</i>, #GNUNET_MESSENGER_OP_UNKNOWN gets returned instead.
83 *
84 * @param[in] store Operation store
85 * @param[in] hash Hash of message
86 * @return Type of operation or #GNUNET_MESSENGER_OP_UNKNOWN
87 */
88enum GNUNET_MESSENGER_OperationType
89get_store_operation_type (const struct GNUNET_MESSENGER_OperationStore *store,
90 const struct GNUNET_HashCode *hash);
91
92/**
93 * Tries to use an operation under a given <i>hash</i> in a specific
94 * operation <i>store</i>. The operation will use the selected <i>type</i>
95 * if successful. The operation will be delayed by a given <i>delay</i>.
96 *
97 * If the selected type is #GNUNET_MESSENGER_OP_DELETE any active operation
98 * under the given hash will be stopped and replaced.
99 *
100 * If the new operation could be started successfully the method returns
101 * #GNUNET_OK, otherwise #GNUNET_SYSERR.
102 *
103 * @param[in,out] store Operation store
104 * @param[in] hash Hash of message
105 * @param[in] type Operation type
106 * @param[in] delay Delay
107 * @return #GNUNET_OK on success, otherwise #GNUNET_SYSERR
108 */
109enum GNUNET_GenericReturnValue
110use_store_operation (struct GNUNET_MESSENGER_OperationStore *store,
111 const struct GNUNET_HashCode *hash,
112 enum GNUNET_MESSENGER_OperationType type,
113 struct GNUNET_TIME_Relative delay);
114
115/**
116 * Stops any active operation under a given <i>hash</i> in a specific
117 * operation <i>store</i>.
118 *
119 * Beware that calling this method will also implicitly free the memory
120 * of any active operation under the given hash!
121 *
122 * @param[in,out] store Operation store
123 * @param[in] hash Hash of message
124 */
125void
126cancel_store_operation (struct GNUNET_MESSENGER_OperationStore *store,
127 const struct GNUNET_HashCode *hash);
128
129#endif //GNUNET_SERVICE_MESSENGER_OPERATION_STORE_H
diff --git a/src/service/messenger/gnunet-service-messenger_peer_store.c b/src/service/messenger/gnunet-service-messenger_peer_store.c
new file mode 100644
index 000000000..fdfbf599b
--- /dev/null
+++ b/src/service/messenger/gnunet-service-messenger_peer_store.c
@@ -0,0 +1,384 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2023--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_peer_store.c
23 * @brief GNUnet MESSENGER service
24 */
25
26#include "gnunet-service-messenger_peer_store.h"
27
28#include "gnunet-service-messenger_service.h"
29#include "gnunet_common.h"
30#include "messenger_api_message.h"
31#include "messenger_api_util.h"
32
33struct GNUNET_MESSENGER_PeerStoreEntry
34{
35 struct GNUNET_PeerIdentity peer;
36 enum GNUNET_GenericReturnValue active;
37};
38
39void
40init_peer_store (struct GNUNET_MESSENGER_PeerStore *store,
41 struct GNUNET_MESSENGER_Service *service)
42{
43 GNUNET_assert ((store) && (service));
44
45 store->service = service;
46 store->peers = GNUNET_CONTAINER_multishortmap_create (4, GNUNET_NO);
47}
48
49
50static enum GNUNET_GenericReturnValue
51iterate_destroy_peers (void *cls, const struct GNUNET_ShortHashCode *id,
52 void *value)
53{
54 struct GNUNET_MESSENGER_PeerStoreEntry *entry = value;
55 GNUNET_free (entry);
56 return GNUNET_YES;
57}
58
59
60void
61clear_peer_store (struct GNUNET_MESSENGER_PeerStore *store)
62{
63 GNUNET_assert ((store) && (store->peers));
64
65 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Clear peer store\n");
66
67 GNUNET_CONTAINER_multishortmap_iterate (store->peers, iterate_destroy_peers,
68 NULL);
69 GNUNET_CONTAINER_multishortmap_destroy (store->peers);
70
71 store->peers = NULL;
72}
73
74
75void
76load_peer_store (struct GNUNET_MESSENGER_PeerStore *store,
77 const char *path)
78{
79 GNUNET_assert ((store) && (path));
80
81 if (GNUNET_YES != GNUNET_DISK_file_test (path))
82 return;
83
84 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Load peer store from path: %s\n",
85 path);
86
87 enum GNUNET_DISK_AccessPermissions permission = (GNUNET_DISK_PERM_USER_READ
88 | GNUNET_DISK_PERM_USER_WRITE
89 );
90
91 struct GNUNET_DISK_FileHandle *handle = GNUNET_DISK_file_open (
92 path, GNUNET_DISK_OPEN_READ, permission
93 );
94
95 if (! handle)
96 return;
97
98 GNUNET_DISK_file_seek (handle, 0, GNUNET_DISK_SEEK_SET);
99
100 struct GNUNET_MESSENGER_PeerStoreEntry *entry;
101 struct GNUNET_ShortHashCode peer_id;
102 struct GNUNET_PeerIdentity peer;
103 ssize_t len;
104
105 do {
106 len = GNUNET_DISK_file_read (handle, &peer, sizeof(peer));
107
108 if (len != sizeof(peer))
109 break;
110
111
112 entry = GNUNET_new (struct GNUNET_MESSENGER_PeerStoreEntry);
113
114 if (! entry)
115 continue;
116
117 GNUNET_memcpy (&(entry->peer), &peer, sizeof(entry->peer));
118 entry->active = GNUNET_YES;
119
120 convert_peer_identity_to_id (&peer, &peer_id);
121
122 if (GNUNET_OK == GNUNET_CONTAINER_multishortmap_put (
123 store->peers, &peer_id, entry,
124 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE))
125 continue;
126
127 GNUNET_free (entry);
128 } while (len == sizeof(peer));
129
130 GNUNET_DISK_file_close (handle);
131}
132
133
134static enum GNUNET_GenericReturnValue
135iterate_save_peers (void *cls, const struct GNUNET_ShortHashCode *id,
136 void *value)
137{
138 struct GNUNET_DISK_FileHandle *handle = cls;
139 struct GNUNET_MESSENGER_PeerStoreEntry *entry = value;
140
141 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Save peer store entry: %s\n",
142 GNUNET_sh2s (id));
143
144 if ((! entry) || (GNUNET_YES != entry->active))
145 return GNUNET_YES;
146
147 GNUNET_DISK_file_write (handle, &(entry->peer), sizeof(entry->peer));
148 return GNUNET_YES;
149}
150
151
152void
153save_peer_store (const struct GNUNET_MESSENGER_PeerStore *store,
154 const char *path)
155{
156 GNUNET_assert ((store) && (path));
157
158 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Save peer store to path: %s\n",
159 path);
160
161 enum GNUNET_DISK_AccessPermissions permission = (GNUNET_DISK_PERM_USER_READ
162 | GNUNET_DISK_PERM_USER_WRITE
163 );
164
165 struct GNUNET_DISK_FileHandle *handle = GNUNET_DISK_file_open (
166 path, GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_WRITE, permission
167 );
168
169 if (! handle)
170 return;
171
172 GNUNET_DISK_file_seek (handle, 0, GNUNET_DISK_SEEK_SET);
173 GNUNET_CONTAINER_multishortmap_iterate (store->peers, iterate_save_peers,
174 handle);
175
176 GNUNET_DISK_file_sync (handle);
177 GNUNET_DISK_file_close (handle);
178}
179
180
181struct GNUNET_MESSENGER_ClosureVerifyPeer
182{
183 const struct GNUNET_MESSENGER_Message *message;
184 const struct GNUNET_HashCode *hash;
185 struct GNUNET_PeerIdentity *sender;
186};
187
188static enum GNUNET_GenericReturnValue
189verify_store_peer (void *cls, const struct GNUNET_ShortHashCode *id,
190 void *value)
191{
192 struct GNUNET_MESSENGER_ClosureVerifyPeer *verify = cls;
193 struct GNUNET_MESSENGER_PeerStoreEntry *entry = value;
194
195 if (! entry)
196 return GNUNET_YES;
197
198 if (GNUNET_OK == verify_message_by_peer (verify->message,
199 verify->hash, &(entry->peer)))
200 {
201 verify->sender = &(entry->peer);
202 return GNUNET_NO;
203 }
204
205 return GNUNET_YES;
206}
207
208
209static struct GNUNET_MESSENGER_PeerStoreEntry*
210add_peer_store_entry (struct GNUNET_MESSENGER_PeerStore *store,
211 const struct GNUNET_PeerIdentity *peer,
212 const struct GNUNET_ShortHashCode *id,
213 enum GNUNET_GenericReturnValue active)
214{
215 GNUNET_assert ((store) && (peer));
216
217 struct GNUNET_MESSENGER_PeerStoreEntry *entry;
218 entry = GNUNET_new (struct GNUNET_MESSENGER_PeerStoreEntry);
219
220 if (! entry)
221 return NULL;
222
223 GNUNET_memcpy (&(entry->peer), peer, sizeof(entry->peer));
224 entry->active = active;
225
226 if (GNUNET_OK != GNUNET_CONTAINER_multishortmap_put (
227 store->peers, id, entry,
228 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE))
229 {
230 GNUNET_free (entry);
231 return NULL;
232 }
233
234 return entry;
235}
236
237
238static const struct GNUNET_PeerIdentity*
239get_store_service_peer_identity (struct GNUNET_MESSENGER_PeerStore *store)
240{
241 static struct GNUNET_PeerIdentity peer;
242
243 if (GNUNET_OK != get_service_peer_identity (store->service, &peer))
244 return NULL;
245
246 return &peer;
247}
248
249
250struct GNUNET_PeerIdentity*
251get_store_peer_of (struct GNUNET_MESSENGER_PeerStore *store,
252 const struct GNUNET_MESSENGER_Message *message,
253 const struct GNUNET_HashCode *hash)
254{
255 GNUNET_assert ((store) && (store->peers) && (message) && (hash));
256
257 if (GNUNET_YES != is_peer_message (message))
258 return NULL;
259
260 struct GNUNET_MESSENGER_ClosureVerifyPeer verify;
261 verify.message = message;
262 verify.hash = hash;
263 verify.sender = NULL;
264
265 GNUNET_CONTAINER_multishortmap_get_multiple (store->peers,
266 &(message->header.sender_id),
267 verify_store_peer, &verify);
268
269 if (verify.sender)
270 return verify.sender;
271
272 const struct GNUNET_PeerIdentity *peer;
273 enum GNUNET_GenericReturnValue active;
274
275 if (GNUNET_MESSENGER_KIND_PEER == message->header.kind)
276 {
277 peer = &(message->body.peer.peer);
278 active = GNUNET_YES;
279 }
280 else if (GNUNET_MESSENGER_KIND_MISS == message->header.kind)
281 {
282 peer = &(message->body.miss.peer);
283 active = GNUNET_NO;
284 }
285 else
286 {
287 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
288 "Peer message does not contain a peer identity\n");
289
290 peer = get_store_service_peer_identity (store);
291 active = GNUNET_NO;
292
293 if (! peer)
294 return NULL;
295 }
296
297 struct GNUNET_ShortHashCode peer_id;
298 convert_peer_identity_to_id (peer, &peer_id);
299
300 if (0 != GNUNET_memcmp (&peer_id, &(message->header.sender_id)))
301 {
302 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
303 "Sender id does not match peer identity\n");
304 return NULL;
305 }
306
307 if (GNUNET_OK != verify_message_by_peer (message, hash, peer))
308 {
309 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
310 "Verification of message with peer identity failed!\n");
311 }
312
313 struct GNUNET_MESSENGER_PeerStoreEntry *entry;
314 entry = add_peer_store_entry (store, peer, &peer_id, active);
315
316 if (! entry)
317 {
318 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
319 "Initialization of entry in peer store failed: %s\n",
320 GNUNET_sh2s (&peer_id));
321
322 return NULL;
323 }
324
325 return &(entry->peer);
326}
327
328
329struct GNUNET_MESSENGER_ClosureFindPeer
330{
331 const struct GNUNET_PeerIdentity *requested;
332 struct GNUNET_MESSENGER_PeerStoreEntry *match;
333};
334
335static enum GNUNET_GenericReturnValue
336find_store_peer (void *cls, const struct GNUNET_ShortHashCode *id, void *value)
337{
338 struct GNUNET_MESSENGER_ClosureFindPeer *find = cls;
339 struct GNUNET_MESSENGER_PeerStoreEntry *entry = value;
340
341 if (! entry)
342 return GNUNET_YES;
343
344 if (0 == GNUNET_memcmp (find->requested, &(entry->peer)))
345 {
346 find->match = entry;
347 return GNUNET_NO;
348 }
349
350 return GNUNET_YES;
351}
352
353
354void
355update_store_peer (struct GNUNET_MESSENGER_PeerStore *store,
356 const struct GNUNET_PeerIdentity *peer,
357 enum GNUNET_GenericReturnValue active)
358{
359 GNUNET_assert ((store) && (store->peers) && (peer));
360
361 struct GNUNET_ShortHashCode peer_id;
362 convert_peer_identity_to_id (peer, &peer_id);
363
364 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Update peer store entry: %s\n",
365 GNUNET_sh2s (&peer_id));
366
367 struct GNUNET_MESSENGER_ClosureFindPeer find;
368 find.requested = peer;
369 find.match = NULL;
370
371 GNUNET_CONTAINER_multishortmap_get_multiple (store->peers, &peer_id,
372 find_store_peer, &find);
373
374 if (find.match)
375 {
376 find.match->active = active;
377 return;
378 }
379
380 if (! add_peer_store_entry (store, peer, &peer_id, active))
381 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
382 "Initial update of entry in peer store failed: %s\n",
383 GNUNET_sh2s (&peer_id));
384}
diff --git a/src/service/messenger/gnunet-service-messenger_peer_store.h b/src/service/messenger/gnunet-service-messenger_peer_store.h
new file mode 100644
index 000000000..7badfad2c
--- /dev/null
+++ b/src/service/messenger/gnunet-service-messenger_peer_store.h
@@ -0,0 +1,108 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2023--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_peer_store.h
23 * @brief GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_SERVICE_MESSENGER_PEER_STORE_H
27#define GNUNET_SERVICE_MESSENGER_PEER_STORE_H
28
29#include "gnunet_util_lib.h"
30
31struct GNUNET_MESSENGER_Message;
32struct GNUNET_MESSENGER_Service;
33
34struct GNUNET_MESSENGER_PeerStore
35{
36 struct GNUNET_MESSENGER_Service *service;
37 struct GNUNET_CONTAINER_MultiShortmap *peers;
38};
39
40/**
41 * Initializes a peer store as fully empty.
42 *
43 * @param[out] store Peer store
44 * @param[in,out] service Messenger service
45 */
46void
47init_peer_store (struct GNUNET_MESSENGER_PeerStore *store,
48 struct GNUNET_MESSENGER_Service *service);
49
50/**
51 * Clears a peer store, wipes its content and deallocates its memory.
52 *
53 * @param[in,out] store Peer store
54 */
55void
56clear_peer_store (struct GNUNET_MESSENGER_PeerStore *store);
57
58/**
59 * Loads peer identities from a <i>file</i> into a peer <i>store</i>.
60 *
61 * @param[out] store Peer store
62 * @param[in] path Path to a file
63 */
64void
65load_peer_store (struct GNUNET_MESSENGER_PeerStore *store,
66 const char *path);
67
68/**
69 * Saves peer identities from a peer <i>store</i> into a <i>file</i>.
70 *
71 * @param[in] store Peer store
72 * @param[in] path Path to a file
73 */
74void
75save_peer_store (const struct GNUNET_MESSENGER_PeerStore *store,
76 const char *path);
77
78/**
79 * Returns the peer identity inside the <i>store</i> which verifies the
80 * signature of a given <i>message</i> as valid. The specific peer identity
81 * has to be added to the <i>store</i> previously. Otherwise the function
82 * returns NULL.
83 *
84 * @param[in,out] store Peer store
85 * @param[in] message Message
86 * @param[in] hash Hash of message
87 * @return Peer identity or NULL
88 */
89struct GNUNET_PeerIdentity*
90get_store_peer_of (struct GNUNET_MESSENGER_PeerStore *store,
91 const struct GNUNET_MESSENGER_Message *message,
92 const struct GNUNET_HashCode *hash);
93
94/**
95 * Adds a <i>peer</i> identity to the <i>store</i> if necessary. It ensures
96 * that the given <i>peer</i> can be verified as sender of a message
97 * afterwards by the <i>store</i>.
98 *
99 * @param[in,out] store Peer store
100 * @param[in] peer Peer identity
101 * @param[in] active Whether the peer is active or not
102 */
103void
104update_store_peer (struct GNUNET_MESSENGER_PeerStore *store,
105 const struct GNUNET_PeerIdentity *peer,
106 enum GNUNET_GenericReturnValue active);
107
108#endif //GNUNET_SERVICE_MESSENGER_PEER_STORE_H
diff --git a/src/service/messenger/gnunet-service-messenger_room.c b/src/service/messenger/gnunet-service-messenger_room.c
new file mode 100644
index 000000000..570d2f990
--- /dev/null
+++ b/src/service/messenger/gnunet-service-messenger_room.c
@@ -0,0 +1,1524 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_room.c
23 * @brief GNUnet MESSENGER service
24 */
25
26#include "platform.h"
27#include "gnunet-service-messenger_room.h"
28
29#include "gnunet-service-messenger_basement.h"
30#include "gnunet-service-messenger_member.h"
31#include "gnunet-service-messenger_member_session.h"
32#include "gnunet-service-messenger_sender_session.h"
33#include "gnunet-service-messenger_message_kind.h"
34#include "gnunet-service-messenger_message_handle.h"
35#include "gnunet-service-messenger_message_send.h"
36#include "gnunet-service-messenger_operation.h"
37#include "gnunet-service-messenger_service.h"
38#include "gnunet-service-messenger_tunnel.h"
39
40#include "messenger_api_util.h"
41
42static void
43idle_request_room_messages (void *cls);
44
45struct GNUNET_MESSENGER_SrvRoom*
46create_srv_room (struct GNUNET_MESSENGER_SrvHandle *handle,
47 const struct GNUNET_HashCode *key)
48{
49 GNUNET_assert ((handle) && (key));
50
51 struct GNUNET_MESSENGER_SrvRoom *room = GNUNET_new (struct
52 GNUNET_MESSENGER_SrvRoom);
53
54 room->service = handle->service;
55 room->host = handle;
56 room->port = NULL;
57
58 GNUNET_memcpy (&(room->key), key, sizeof(struct GNUNET_HashCode));
59
60 room->tunnels = GNUNET_CONTAINER_multipeermap_create (8, GNUNET_NO);
61
62 init_peer_store (get_srv_room_peer_store (room), room->service);
63 init_member_store (get_srv_room_member_store (room), room);
64 init_message_store (get_srv_room_message_store (room));
65 init_operation_store (get_srv_room_operation_store (room), room);
66
67 init_list_tunnels (&(room->basement));
68 init_message_state (&(room->state));
69
70 room->peer_message = NULL;
71
72 init_list_messages (&(room->handling));
73 room->idle = NULL;
74
75 if (room->service->dir)
76 load_srv_room (room);
77
78 room->idle = GNUNET_SCHEDULER_add_with_priority (
79 GNUNET_SCHEDULER_PRIORITY_IDLE, idle_request_room_messages, room);
80
81 return room;
82}
83
84
85static enum GNUNET_GenericReturnValue
86iterate_destroy_tunnels (void *cls,
87 const struct GNUNET_PeerIdentity *key,
88 void *value)
89{
90 struct GNUNET_MESSENGER_SrvTunnel *tunnel = value;
91 destroy_tunnel (tunnel);
92 return GNUNET_YES;
93}
94
95
96static void
97close_srv_room (struct GNUNET_MESSENGER_SrvRoom *room);
98
99static void
100handle_room_messages (struct GNUNET_MESSENGER_SrvRoom *room);
101
102void
103destroy_srv_room (struct GNUNET_MESSENGER_SrvRoom *room,
104 enum GNUNET_GenericReturnValue deletion)
105{
106 GNUNET_assert (room);
107
108 if (room->idle)
109 {
110 GNUNET_SCHEDULER_cancel (room->idle);
111 room->idle = NULL;
112 }
113
114 close_srv_room (room);
115
116 GNUNET_CONTAINER_multipeermap_iterate (room->tunnels, iterate_destroy_tunnels,
117 NULL);
118 handle_room_messages (room);
119
120 if (! (room->service->dir))
121 goto skip_saving;
122
123 if (GNUNET_YES == deletion)
124 remove_srv_room (room);
125 else
126 save_srv_room (room);
127
128skip_saving:
129 clear_peer_store (get_srv_room_peer_store (room));
130 clear_member_store (get_srv_room_member_store (room));
131 clear_message_store (get_srv_room_message_store (room));
132 clear_operation_store (get_srv_room_operation_store (room));
133
134 GNUNET_CONTAINER_multipeermap_destroy (room->tunnels);
135 clear_list_tunnels (&(room->basement));
136 clear_message_state (&(room->state));
137
138 if (room->peer_message)
139 GNUNET_free (room->peer_message);
140
141 GNUNET_free (room);
142}
143
144
145struct GNUNET_MESSENGER_PeerStore*
146get_srv_room_peer_store (struct GNUNET_MESSENGER_SrvRoom *room)
147{
148 GNUNET_assert (room);
149
150 return &(room->peer_store);
151}
152
153
154struct GNUNET_MESSENGER_MemberStore*
155get_srv_room_member_store (struct GNUNET_MESSENGER_SrvRoom *room)
156{
157 GNUNET_assert (room);
158
159 return &(room->member_store);
160}
161
162
163struct GNUNET_MESSENGER_MessageStore*
164get_srv_room_message_store (struct GNUNET_MESSENGER_SrvRoom *room)
165{
166 GNUNET_assert (room);
167
168 return &(room->message_store);
169}
170
171
172struct GNUNET_MESSENGER_OperationStore*
173get_srv_room_operation_store (struct GNUNET_MESSENGER_SrvRoom *room)
174{
175 GNUNET_assert (room);
176
177 return &(room->operation_store);
178}
179
180
181static enum GNUNET_GenericReturnValue
182send_room_info (struct GNUNET_MESSENGER_SrvRoom *room,
183 struct GNUNET_MESSENGER_SrvHandle *handle,
184 struct GNUNET_MESSENGER_SrvTunnel *tunnel)
185{
186 if ((! handle) || (! is_tunnel_connected (tunnel)))
187 return GNUNET_NO;
188
189 return send_tunnel_message (tunnel, handle, create_message_info (
190 room->service));
191}
192
193
194static void*
195callback_room_connect (void *cls,
196 struct GNUNET_CADET_Channel *channel,
197 const struct GNUNET_PeerIdentity *source)
198{
199 struct GNUNET_MESSENGER_SrvRoom *room = cls;
200
201 struct GNUNET_MESSENGER_SrvTunnel *tunnel = create_tunnel (room, source);
202
203 if ((tunnel) &&
204 (GNUNET_OK != GNUNET_CONTAINER_multipeermap_put (room->tunnels, source,
205 tunnel,
206 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)))
207 {
208 destroy_tunnel (tunnel);
209 tunnel = NULL;
210 }
211
212 if (! tunnel)
213 {
214 delayed_disconnect_channel (channel);
215 return NULL;
216 }
217
218 bind_tunnel (tunnel, channel);
219
220 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
221 "New tunnel in room (%s) established to peer: %s\n",
222 GNUNET_h2s (get_srv_room_key (room)), GNUNET_i2s (source));
223
224 if (GNUNET_YES == send_room_info (room, room->host, tunnel))
225 return tunnel;
226
227 disconnect_tunnel (tunnel);
228
229 if (GNUNET_YES == GNUNET_CONTAINER_multipeermap_remove (room->tunnels, source,
230 tunnel))
231 destroy_tunnel (tunnel);
232
233 return NULL;
234}
235
236
237static enum GNUNET_GenericReturnValue
238join_room (struct GNUNET_MESSENGER_SrvRoom *room,
239 struct GNUNET_MESSENGER_SrvHandle *handle,
240 struct GNUNET_MESSENGER_Member *member,
241 const struct GNUNET_ShortHashCode *id)
242{
243 GNUNET_assert ((room) && (handle) && (member));
244
245 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Joining room: %s (%s)\n", GNUNET_h2s (
246 get_srv_room_key (room)),
247 GNUNET_sh2s (get_member_id (member)));
248
249 const struct GNUNET_ShortHashCode *member_id = get_member_id (member);
250
251 if (GNUNET_OK != change_srv_handle_member_id (handle, get_srv_room_key (room),
252 member_id))
253 return GNUNET_NO;
254
255 enum GNUNET_GenericReturnValue reset;
256 if ((! id) || (0 != GNUNET_memcmp (id, member_id)))
257 reset = GNUNET_YES;
258 else
259 reset = GNUNET_NO;
260
261 notify_srv_handle_member_id (handle, room, member_id, reset);
262 return GNUNET_YES;
263}
264
265
266static enum GNUNET_GenericReturnValue
267join_room_locally (struct GNUNET_MESSENGER_SrvRoom *room,
268 struct GNUNET_MESSENGER_SrvHandle *handle)
269{
270 const struct GNUNET_ShortHashCode *member_id = get_srv_handle_member_id (
271 handle, get_srv_room_key (room));
272
273 struct GNUNET_MESSENGER_MemberStore *member_store =
274 get_srv_room_member_store (room);
275 struct GNUNET_MESSENGER_Member *member = add_store_member (member_store,
276 member_id);
277
278 if (GNUNET_NO == join_room (room, handle, member, member_id))
279 return GNUNET_NO;
280
281 return GNUNET_YES;
282}
283
284
285extern enum GNUNET_GenericReturnValue
286check_tunnel_message (void *cls,
287 const struct GNUNET_MessageHeader *header);
288
289extern void
290handle_tunnel_message (void *cls,
291 const struct GNUNET_MessageHeader *header);
292
293extern void
294callback_tunnel_disconnect (void *cls,
295 const struct GNUNET_CADET_Channel *channel);
296
297
298enum GNUNET_GenericReturnValue
299open_srv_room (struct GNUNET_MESSENGER_SrvRoom *room,
300 struct GNUNET_MESSENGER_SrvHandle *handle)
301{
302 GNUNET_assert (room);
303
304 if (handle)
305 room->host = handle;
306
307 if (room->port)
308 {
309 if (! handle)
310 return GNUNET_YES;
311
312 return join_room_locally (room, handle);
313 }
314
315 struct GNUNET_CADET_Handle *cadet = get_srv_room_cadet (room);
316 const struct GNUNET_HashCode *key = get_srv_room_key (room);
317
318 struct GNUNET_MQ_MessageHandler handlers[] = { GNUNET_MQ_hd_var_size (
319 tunnel_message,
320 GNUNET_MESSAGE_TYPE_CADET_CLI,
321 struct
322 GNUNET_MessageHeader, NULL),
323 GNUNET_MQ_handler_end () };
324
325 struct GNUNET_HashCode port;
326 convert_messenger_key_to_port (key, &port);
327 room->port = GNUNET_CADET_open_port (cadet, &port, callback_room_connect,
328 room, NULL, callback_tunnel_disconnect,
329 handlers);
330
331 if (room->port)
332 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Port of room (%s) was opened!\n",
333 GNUNET_h2s (get_srv_room_key (room)));
334 else
335 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
336 "Port of room (%s) could not be opened!\n",
337 GNUNET_h2s (get_srv_room_key (room)));
338
339 if (! handle)
340 goto complete_opening;
341
342 const struct GNUNET_ShortHashCode *member_id = get_srv_handle_member_id (
343 handle, get_srv_room_key (room));
344
345 struct GNUNET_MESSENGER_MemberStore *member_store =
346 get_srv_room_member_store (room);
347 struct GNUNET_MESSENGER_Member *member = add_store_member (member_store,
348 member_id);
349
350 if ((GNUNET_NO == join_room (room, handle, member, member_id)) &&
351 (room->port))
352 {
353 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
354 "You could not join the room, therefore it keeps closed!\n");
355
356 close_srv_room (room);
357 return GNUNET_NO;
358 }
359
360complete_opening:
361 if (! room->port)
362 return GNUNET_NO;
363
364 return send_srv_room_message (room, handle, create_message_peer (
365 room->service));
366}
367
368
369static void
370close_srv_room (struct GNUNET_MESSENGER_SrvRoom *room)
371{
372 GNUNET_assert (room);
373
374 if (! room->port)
375 return;
376
377 struct GNUNET_PeerIdentity peer;
378 if ((room->peer_message) &&
379 (GNUNET_OK == get_service_peer_identity (room->service, &peer)))
380 send_srv_room_message (room, room->host, create_message_miss (&peer));
381
382 GNUNET_CADET_close_port (room->port);
383 room->port = NULL;
384}
385
386
387enum GNUNET_GenericReturnValue
388enter_srv_room_at (struct GNUNET_MESSENGER_SrvRoom *room,
389 struct GNUNET_MESSENGER_SrvHandle *handle,
390 const struct GNUNET_PeerIdentity *door)
391{
392 GNUNET_assert ((room) && (handle) && (door));
393
394 struct GNUNET_PeerIdentity peer;
395
396 if ((GNUNET_OK == get_service_peer_identity (room->service, &peer)) &&
397 (0 == GNUNET_memcmp (&peer, door)))
398 return join_room_locally (room, handle);
399
400 struct GNUNET_MESSENGER_SrvTunnel *tunnel =
401 GNUNET_CONTAINER_multipeermap_get (room->tunnels, door);
402
403 if (! tunnel)
404 {
405 tunnel = create_tunnel (room, door);
406
407 if (GNUNET_OK != GNUNET_CONTAINER_multipeermap_put (room->tunnels, door,
408 tunnel,
409 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE))
410 {
411 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
412 "You could not connect to that door!\n");
413 destroy_tunnel (tunnel);
414 return GNUNET_NO;
415 }
416 }
417
418 if (GNUNET_SYSERR == connect_tunnel (tunnel))
419 {
420 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
421 "Connection failure during entrance!\n");
422 GNUNET_CONTAINER_multipeermap_remove (room->tunnels, door, tunnel);
423 destroy_tunnel (tunnel);
424 return GNUNET_NO;
425 }
426
427 return join_room_locally (room, handle);
428}
429
430
431static void
432sign_srv_room_message_by_peer (const void *cls,
433 struct GNUNET_MESSENGER_Message *message,
434 uint16_t length,
435 char *buffer,
436 const struct GNUNET_HashCode *hash)
437{
438 const struct GNUNET_MESSENGER_SrvHandle *handle = cls;
439
440 GNUNET_assert ((handle) && (handle->service));
441
442 sign_message_by_peer (message, length, buffer, hash, handle->service->config);
443}
444
445
446struct GNUNET_MQ_Envelope*
447pack_srv_room_message (const struct GNUNET_MESSENGER_SrvRoom *room,
448 const struct GNUNET_MESSENGER_SrvHandle *handle,
449 struct GNUNET_MESSENGER_Message *message,
450 struct GNUNET_HashCode *hash,
451 enum GNUNET_MESSENGER_PackMode mode)
452{
453 GNUNET_assert ((room) && (handle) && (message) && (hash));
454
455 if (GNUNET_YES != is_peer_message (message))
456 return pack_message (message, hash, NULL, mode, NULL);
457
458 message->header.timestamp = GNUNET_TIME_absolute_hton (
459 GNUNET_TIME_absolute_get ());
460
461 struct GNUNET_PeerIdentity peer;
462 if (GNUNET_OK != get_service_peer_identity (handle->service, &peer))
463 return NULL;
464
465 convert_peer_identity_to_id (&peer, &(message->header.sender_id));
466 get_message_state_chain_hash (&(room->state), &(message->header.previous));
467
468 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
469 "Packing message with peer signature: %s\n",
470 GNUNET_sh2s (&(message->header.sender_id)));
471
472 message->header.signature.type = htonl (GNUNET_PUBLIC_KEY_TYPE_EDDSA);
473 return pack_message (message, hash, sign_srv_room_message_by_peer, mode,
474 handle);
475}
476
477
478struct GNUNET_MESSENGER_ClosureSendRoom
479{
480 struct GNUNET_MESSENGER_SrvRoom *room;
481 struct GNUNET_MESSENGER_SrvHandle *handle;
482 struct GNUNET_MESSENGER_SrvTunnel *exclude;
483 struct GNUNET_MESSENGER_Message *message;
484 struct GNUNET_HashCode *hash;
485 enum GNUNET_GenericReturnValue packed;
486};
487
488static enum GNUNET_GenericReturnValue
489iterate_send_room_message (void *cls,
490 const struct GNUNET_PeerIdentity *key,
491 void *value)
492{
493 struct GNUNET_MESSENGER_SrvTunnel *tunnel = value;
494
495 if ((! is_tunnel_connected (tunnel)) ||
496 (get_tunnel_messenger_version (tunnel) < GNUNET_MESSENGER_VERSION))
497 return GNUNET_YES;
498
499 struct GNUNET_MESSENGER_ClosureSendRoom *closure = cls;
500
501 if (tunnel == closure->exclude)
502 return GNUNET_YES;
503
504 struct GNUNET_MQ_Envelope *env = NULL;
505
506 if (closure->packed == GNUNET_NO)
507 {
508 env = pack_srv_room_message (closure->room, closure->handle,
509 closure->message, closure->hash,
510 GNUNET_MESSENGER_PACK_MODE_ENVELOPE);
511
512 if (env)
513 closure->packed = GNUNET_YES;
514 }
515 else
516 env = pack_message (closure->message, NULL, NULL,
517 GNUNET_MESSENGER_PACK_MODE_ENVELOPE, NULL);
518
519 if (env)
520 send_tunnel_envelope (tunnel, env, closure->hash);
521
522 return GNUNET_YES;
523}
524
525
526enum GNUNET_GenericReturnValue
527update_room_message (struct GNUNET_MESSENGER_SrvRoom *room,
528 struct GNUNET_MESSENGER_Message *message,
529 const struct GNUNET_HashCode *hash);
530
531void
532callback_room_handle_message (struct GNUNET_MESSENGER_SrvRoom *room,
533 const struct GNUNET_MESSENGER_Message *message,
534 const struct GNUNET_HashCode *hash);
535
536enum GNUNET_GenericReturnValue
537send_srv_room_message (struct GNUNET_MESSENGER_SrvRoom *room,
538 struct GNUNET_MESSENGER_SrvHandle *handle,
539 struct GNUNET_MESSENGER_Message *message)
540{
541 GNUNET_assert ((room) && (handle));
542
543 if (! message)
544 return GNUNET_NO;
545
546 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
547 "Sending message from handle in room: %s (%s)\n",
548 GNUNET_h2s (&(room->key)),
549 GNUNET_MESSENGER_name_of_kind (message->header.kind));
550
551 struct GNUNET_HashCode hash;
552 struct GNUNET_MESSENGER_ClosureSendRoom closure;
553
554 closure.room = room;
555 closure.handle = handle;
556 closure.exclude = NULL;
557 closure.message = message;
558 closure.hash = &hash;
559 closure.packed = GNUNET_NO;
560
561 GNUNET_CONTAINER_multipeermap_iterate (room->tunnels,
562 iterate_send_room_message, &closure);
563
564 if (GNUNET_NO == closure.packed)
565 pack_srv_room_message (room, handle, message, &hash,
566 GNUNET_MESSENGER_PACK_MODE_UNKNOWN);
567
568 enum GNUNET_GenericReturnValue new_message;
569 new_message = update_room_message (room, message, &hash);
570
571 if (GNUNET_YES != new_message)
572 {
573 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Sending duplicate message failed!\n");
574 return GNUNET_SYSERR;
575 }
576
577 switch (message->header.kind)
578 {
579 case GNUNET_MESSENGER_KIND_JOIN:
580 send_message_join (room, handle, message, &hash);
581 break;
582 case GNUNET_MESSENGER_KIND_KEY:
583 send_message_key (room, handle, message, &hash);
584 break;
585 case GNUNET_MESSENGER_KIND_PEER:
586 send_message_peer (room, handle, message, &hash);
587 break;
588 case GNUNET_MESSENGER_KIND_ID:
589 send_message_id (room, handle, message, &hash);
590 break;
591 case GNUNET_MESSENGER_KIND_REQUEST:
592 send_message_request (room, handle, message, &hash);
593 break;
594 default:
595 break;
596 }
597
598 callback_room_handle_message (room, message, &hash);
599 return GNUNET_YES;
600}
601
602
603void
604forward_srv_room_message (struct GNUNET_MESSENGER_SrvRoom *room,
605 struct GNUNET_MESSENGER_SrvTunnel *tunnel,
606 struct GNUNET_MESSENGER_Message *message,
607 const struct GNUNET_HashCode *hash)
608{
609 GNUNET_assert ((room) && (tunnel));
610
611 if (! message)
612 return;
613
614 struct GNUNET_MESSENGER_ClosureSendRoom closure;
615 struct GNUNET_HashCode message_hash;
616
617 GNUNET_memcpy (&message_hash, hash, sizeof(struct GNUNET_HashCode));
618
619 closure.room = room;
620 closure.handle = NULL;
621 closure.exclude = tunnel;
622 closure.message = message;
623 closure.hash = &message_hash;
624 closure.packed = GNUNET_YES;
625
626 GNUNET_CONTAINER_multipeermap_iterate (room->tunnels,
627 iterate_send_room_message, &closure);
628}
629
630
631void
632check_srv_room_peer_status (struct GNUNET_MESSENGER_SrvRoom *room,
633 struct GNUNET_MESSENGER_SrvTunnel *tunnel)
634{
635 if (! room->peer_message)
636 return;
637
638 struct GNUNET_MESSENGER_MessageStore *message_store =
639 get_srv_room_message_store (room);
640
641 const struct GNUNET_MESSENGER_Message *message = get_store_message (
642 message_store, room->peer_message);
643
644 if (! message)
645 {
646 GNUNET_free (room->peer_message);
647 room->peer_message = NULL;
648 return;
649 }
650
651 if (tunnel)
652 forward_tunnel_message (tunnel, message, room->peer_message);
653}
654
655
656void
657merge_srv_room_last_messages (struct GNUNET_MESSENGER_SrvRoom *room,
658 struct GNUNET_MESSENGER_SrvHandle *handle)
659{
660 GNUNET_assert (room);
661
662 if (! handle)
663 return;
664
665 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
666 "Merging messages by handle in room: %s\n",
667 GNUNET_h2s (&(room->key)));
668
669 const struct GNUNET_HashCode *hash;
670
671merge_next:
672 hash = get_message_state_merge_hash (&(room->state));
673
674 if (! hash)
675 return;
676
677 send_srv_room_message (room, handle, create_message_merge (hash));
678 goto merge_next;
679}
680
681
682void
683callback_room_deletion (struct GNUNET_MESSENGER_SrvRoom *room,
684 const struct GNUNET_HashCode *hash)
685{
686 if (GNUNET_OK != delete_store_message (get_srv_room_message_store (room),
687 hash))
688 {
689 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Deletion of message failed! (%s)\n",
690 GNUNET_h2s (hash));
691 return;
692 }
693}
694
695
696void
697callback_room_merge (struct GNUNET_MESSENGER_SrvRoom *room,
698 const struct GNUNET_HashCode *hash)
699{
700 if (! room->host)
701 return;
702
703 send_srv_room_message (room, room->host, create_message_merge (hash));
704}
705
706
707enum GNUNET_GenericReturnValue
708delete_srv_room_message (struct GNUNET_MESSENGER_SrvRoom *room,
709 struct GNUNET_MESSENGER_MemberSession *session,
710 const struct GNUNET_HashCode *hash,
711 const struct GNUNET_TIME_Relative delay)
712{
713 GNUNET_assert ((room) && (session) && (hash));
714
715 const struct GNUNET_TIME_Relative forever =
716 GNUNET_TIME_relative_get_forever_ ();
717
718 if (0 == GNUNET_memcmp (&forever, &delay))
719 {
720 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
721 "Deletion is delayed forever: operation is impossible!\n");
722 return GNUNET_SYSERR;
723 }
724
725 struct GNUNET_MESSENGER_MessageStore *message_store =
726 get_srv_room_message_store (room);
727
728 const struct GNUNET_MESSENGER_Message *message = get_store_message (
729 message_store, hash);
730
731 if (! message)
732 return GNUNET_YES;
733
734 if (GNUNET_YES != check_member_session_history (session, hash, GNUNET_YES))
735 {
736 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
737 "Unpermitted request for deletion by member (%s) of message (%s)!\n",
738 GNUNET_sh2s (get_member_session_id (session)), GNUNET_h2s (
739 hash));
740
741 return GNUNET_NO;
742 }
743
744 struct GNUNET_MESSENGER_OperationStore *operation_store =
745 get_srv_room_operation_store (room);
746
747 if (GNUNET_OK != use_store_operation (operation_store, hash,
748 GNUNET_MESSENGER_OP_DELETE, delay))
749 {
750 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
751 "Deletion has failed: operation denied!\n");
752 return GNUNET_SYSERR;
753 }
754
755 return GNUNET_YES;
756}
757
758
759struct GNUNET_CADET_Handle*
760get_srv_room_cadet (struct GNUNET_MESSENGER_SrvRoom *room)
761{
762 GNUNET_assert (room);
763
764 return room->service->cadet;
765}
766
767
768const struct GNUNET_HashCode*
769get_srv_room_key (const struct GNUNET_MESSENGER_SrvRoom *room)
770{
771 GNUNET_assert (room);
772
773 return &(room->key);
774}
775
776
777const struct GNUNET_MESSENGER_SrvTunnel*
778get_srv_room_tunnel (const struct GNUNET_MESSENGER_SrvRoom *room,
779 const struct GNUNET_PeerIdentity *peer)
780{
781 GNUNET_assert ((room) && (peer));
782
783 return GNUNET_CONTAINER_multipeermap_get (room->tunnels, peer);
784}
785
786
787static enum GNUNET_GenericReturnValue
788request_room_message_step (struct GNUNET_MESSENGER_SrvRoom *room,
789 const struct GNUNET_HashCode *hash,
790 const struct GNUNET_MESSENGER_MemberSession *session,
791 GNUNET_MESSENGER_MessageRequestCallback callback,
792 void *cls)
793{
794 const struct GNUNET_MESSENGER_Message *message;
795
796 struct GNUNET_MESSENGER_MessageStore *message_store =
797 get_srv_room_message_store (room);
798
799 const struct GNUNET_MESSENGER_MessageLink *link = get_store_message_link (
800 message_store, hash, GNUNET_YES
801 );
802
803 if (! link)
804 goto forward;
805
806 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
807 "Requesting link of message with hash: %s\n",
808 GNUNET_h2s (hash));
809
810 enum GNUNET_GenericReturnValue result;
811 result = request_room_message_step (room, &(link->first), session,
812 callback, cls);
813
814 if ((GNUNET_YES == link->multiple) &&
815 (GNUNET_YES == request_room_message_step (room, &(link->second), session,
816 callback, cls)))
817 return GNUNET_YES;
818 else
819 return result;
820
821forward:
822 message = get_store_message (message_store, hash);
823
824 if (! message)
825 {
826 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
827 "Requested message is missing in local storage: %s\n",
828 GNUNET_h2s (hash));
829 return GNUNET_NO;
830 }
831
832 if (GNUNET_YES != check_member_session_history (session, hash, GNUNET_NO))
833 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
834 "Unpermitted request for access by member (%s) of message (%s)!\n",
835 GNUNET_sh2s (get_member_session_id (session)), GNUNET_h2s (
836 hash));
837 else if (callback)
838 callback (cls, room, message, hash);
839
840 return GNUNET_YES;
841}
842
843
844enum GNUNET_GenericReturnValue
845request_srv_room_message (struct GNUNET_MESSENGER_SrvRoom *room,
846 const struct GNUNET_HashCode *hash,
847 const struct GNUNET_MESSENGER_MemberSession *session,
848 GNUNET_MESSENGER_MessageRequestCallback callback,
849 void *cls)
850{
851 GNUNET_assert ((room) && (hash));
852
853 enum GNUNET_GenericReturnValue result;
854 result = request_room_message_step (room, hash, session, callback, cls);
855
856 if ((GNUNET_NO == result) && (callback))
857 callback (cls, room, NULL, hash);
858
859 return result;
860}
861
862
863void
864callback_room_disconnect (struct GNUNET_MESSENGER_SrvRoom *room,
865 void *cls)
866{
867 struct GNUNET_MESSENGER_SrvTunnel *tunnel = cls;
868
869 if (! room->host)
870 return;
871
872 struct GNUNET_PeerIdentity identity;
873 get_tunnel_peer_identity (tunnel, &identity);
874
875 if ((GNUNET_YES != GNUNET_CONTAINER_multipeermap_remove (room->tunnels,
876 &identity,
877 tunnel)) ||
878 (GNUNET_YES == GNUNET_CONTAINER_multipeermap_contains (room->tunnels,
879 &identity)))
880 return;
881
882 if (GNUNET_YES == contains_list_tunnels (&(room->basement), &identity))
883 send_srv_room_message (room, room->host, create_message_miss (&identity));
884
885 if ((0 < GNUNET_CONTAINER_multipeermap_size (room->tunnels)) ||
886 (GNUNET_NO == room->service->auto_connecting))
887 return;
888
889 struct GNUNET_MESSENGER_ListTunnel *element;
890 element = find_list_tunnels_alternate (&(room->basement), &identity);
891
892 if (! element)
893 return;
894
895 GNUNET_PEER_resolve (element->peer, &identity);
896 enter_srv_room_at (room, room->host, &identity);
897}
898
899
900enum GNUNET_GenericReturnValue
901callback_verify_room_message (struct GNUNET_MESSENGER_SrvRoom *room,
902 void *cls,
903 struct GNUNET_MESSENGER_Message *message,
904 struct GNUNET_HashCode *hash)
905{
906 if (GNUNET_MESSENGER_KIND_UNKNOWN == message->header.kind)
907 {
908 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
909 "Message error: Kind is unknown! (%d)\n", message->header.kind);
910 return GNUNET_SYSERR;
911 }
912
913 struct GNUNET_MESSENGER_MessageStore *message_store =
914 get_srv_room_message_store (room);
915
916 const struct GNUNET_MESSENGER_Message *previous = get_store_message (
917 message_store, &(message->header.previous));
918
919 if (! previous)
920 goto skip_time_comparison;
921
922 struct GNUNET_TIME_Absolute timestamp = GNUNET_TIME_absolute_ntoh (
923 message->header.timestamp);
924 struct GNUNET_TIME_Absolute last = GNUNET_TIME_absolute_ntoh (
925 previous->header.timestamp);
926
927 if (GNUNET_TIME_relative_get_zero_ ().rel_value_us !=
928 GNUNET_TIME_absolute_get_difference (timestamp, last).rel_value_us)
929 {
930 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
931 "Message warning: Timestamp does not check out!\n");
932 }
933
934skip_time_comparison:
935 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receiving message of kind: %s!\n",
936 GNUNET_MESSENGER_name_of_kind (message->header.kind));
937
938 return GNUNET_OK;
939}
940
941
942static void
943idle_request_room_messages (void *cls)
944{
945 struct GNUNET_MESSENGER_SrvRoom *room = cls;
946
947 room->idle = NULL;
948
949 struct GNUNET_MESSENGER_OperationStore *operation_store =
950 get_srv_room_operation_store (room);
951 const struct GNUNET_HashCode *hash = get_message_state_merge_hash (
952 &(room->state));
953
954 if ((hash) &&
955 (GNUNET_MESSENGER_OP_UNKNOWN == get_store_operation_type (operation_store,
956 hash)))
957 use_store_operation (
958 operation_store,
959 hash,
960 GNUNET_MESSENGER_OP_MERGE,
961 GNUNET_MESSENGER_MERGE_DELAY
962 );
963
964 room->idle = GNUNET_SCHEDULER_add_delayed_with_priority (
965 GNUNET_MESSENGER_IDLE_DELAY,
966 GNUNET_SCHEDULER_PRIORITY_IDLE,
967 idle_request_room_messages,
968 cls
969 );
970}
971
972
973void
974solve_srv_room_member_collisions (struct GNUNET_MESSENGER_SrvRoom *room,
975 const struct
976 GNUNET_CRYPTO_PublicKey *public_key,
977 const struct GNUNET_ShortHashCode *member_id,
978 struct GNUNET_TIME_Absolute timestamp)
979{
980 GNUNET_assert ((room) && (public_key) && (member_id));
981
982 struct GNUNET_MESSENGER_MemberStore *member_store =
983 get_srv_room_member_store (room);
984 struct GNUNET_MESSENGER_Member *member = get_store_member (member_store,
985 member_id);
986
987 if ((! member) || (1 >= GNUNET_CONTAINER_multihashmap_size (
988 member->sessions)))
989 return;
990
991 struct GNUNET_MESSENGER_ListHandles *handles = &(room->service->handles);
992 struct GNUNET_MESSENGER_ListHandle *element;
993
994 const struct GNUNET_CRYPTO_PublicKey *pubkey;
995
996 for (element = handles->head; element; element = element->next)
997 {
998 if (0 != GNUNET_memcmp (member_id, get_srv_handle_member_id (
999 element->handle, get_srv_room_key (room))))
1000 continue;
1001
1002 pubkey = get_srv_handle_key (element->handle);
1003
1004 if (0 == GNUNET_memcmp (public_key, pubkey))
1005 continue;
1006
1007 struct GNUNET_MESSENGER_MemberSession *session = get_member_session (member,
1008 pubkey);
1009
1010 if (! session)
1011 continue;
1012
1013 struct GNUNET_TIME_Absolute start = get_member_session_start (session);
1014
1015 if (GNUNET_TIME_relative_get_zero_ ().rel_value_us !=
1016 GNUNET_TIME_absolute_get_difference (start, timestamp).rel_value_us)
1017 continue;
1018
1019 struct GNUNET_ShortHashCode random_id;
1020 generate_free_member_id (&random_id, member_store->members);
1021
1022 notify_srv_handle_member_id (element->handle, room, &random_id, GNUNET_NO);
1023 }
1024}
1025
1026
1027void
1028rebuild_srv_room_basement_structure (struct GNUNET_MESSENGER_SrvRoom *room)
1029{
1030 GNUNET_assert (room);
1031
1032 struct GNUNET_PeerIdentity peer;
1033 size_t src;
1034
1035 if (GNUNET_OK != get_service_peer_identity (room->service, &peer))
1036 return;
1037
1038 size_t count = count_of_tunnels (&(room->basement));
1039
1040 if (! find_list_tunnels (&(room->basement), &peer, &src))
1041 return;
1042
1043 if ((count > room->service->min_routers) &&
1044 (GNUNET_NO == is_srv_handle_routing (room->host, &(room->key))) &&
1045 (GNUNET_OK == verify_list_tunnels_flag_token (&(room->basement),
1046 &peer,
1047 GNUNET_MESSENGER_FLAG_CONNECTION_AUTO)))
1048 {
1049 close_srv_room (room);
1050 return;
1051 }
1052
1053 struct GNUNET_MESSENGER_ListTunnel *element = room->basement.head;
1054 struct GNUNET_MESSENGER_SrvTunnel *tunnel;
1055
1056 size_t dst = 0;
1057
1058 while (element)
1059 {
1060 GNUNET_PEER_resolve (element->peer, &peer);
1061
1062 tunnel = GNUNET_CONTAINER_multipeermap_get (room->tunnels, &peer);
1063
1064 if (! tunnel)
1065 {
1066 element = remove_from_list_tunnels (&(room->basement), element);
1067 continue;
1068 }
1069
1070 if (GNUNET_YES == required_connection_between (count, src, dst))
1071 {
1072 if (GNUNET_SYSERR == connect_tunnel (tunnel))
1073 {
1074 element = remove_from_list_tunnels (&(room->basement), element);
1075 continue;
1076 }
1077 }
1078 else
1079 disconnect_tunnel (tunnel);
1080
1081 element = element->next;
1082 dst++;
1083 }
1084}
1085
1086
1087uint32_t
1088get_srv_room_amount_of_tunnels (const struct GNUNET_MESSENGER_SrvRoom *room)
1089{
1090 GNUNET_assert (room);
1091
1092 return GNUNET_CONTAINER_multipeermap_size (room->tunnels);
1093}
1094
1095
1096uint32_t
1097get_srv_room_connection_flags (const struct GNUNET_MESSENGER_SrvRoom *room)
1098{
1099 GNUNET_assert (room);
1100
1101 uint32_t flags = GNUNET_MESSENGER_FLAG_CONNECTION_NONE;
1102
1103 if (GNUNET_YES == room->service->auto_routing)
1104 flags |= GNUNET_MESSENGER_FLAG_CONNECTION_AUTO;
1105
1106 return flags;
1107}
1108
1109
1110static void
1111handle_room_messages (struct GNUNET_MESSENGER_SrvRoom *room)
1112{
1113 struct GNUNET_MESSENGER_MessageStore *message_store =
1114 get_srv_room_message_store (room);
1115 struct GNUNET_MESSENGER_MemberStore *member_store =
1116 get_srv_room_member_store (room);
1117 struct GNUNET_MESSENGER_PeerStore *peer_store = get_srv_room_peer_store (
1118 room);
1119
1120 const struct GNUNET_HashCode *key = get_srv_room_key (room);
1121
1122 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1123 "Handling room messages: %s\n", GNUNET_h2s (key));
1124
1125 while (room->handling.head)
1126 {
1127 struct GNUNET_MESSENGER_ListMessage *element = room->handling.head;
1128
1129 const struct GNUNET_MESSENGER_Message *message = get_store_message (
1130 message_store, &(element->hash));
1131
1132 if (! message)
1133 goto finish_handling;
1134
1135 struct GNUNET_MESSENGER_SenderSession session;
1136
1137 if (GNUNET_YES == is_peer_message (message))
1138 {
1139 session.peer = get_store_peer_of (peer_store, message, &(element->hash));
1140
1141 if (! session.peer)
1142 goto finish_handling;
1143 }
1144 else
1145 {
1146 struct GNUNET_MESSENGER_Member *member = get_store_member_of (
1147 member_store, message);
1148
1149 if (! member)
1150 goto finish_handling;
1151
1152 session.member = get_member_session_of (member, message,
1153 &(element->hash));
1154
1155 if (! session.member)
1156 goto finish_handling;
1157 }
1158
1159 handle_service_message (room->service, room, &session, message,
1160 &(element->hash));
1161
1162finish_handling:
1163 GNUNET_CONTAINER_DLL_remove (room->handling.head, room->handling.tail,
1164 element);
1165 GNUNET_free (element);
1166 }
1167}
1168
1169
1170enum GNUNET_GenericReturnValue
1171update_room_message (struct GNUNET_MESSENGER_SrvRoom *room,
1172 struct GNUNET_MESSENGER_Message *message,
1173 const struct GNUNET_HashCode *hash)
1174{
1175 GNUNET_assert ((room) && (message) && (hash));
1176
1177 struct GNUNET_MESSENGER_OperationStore *operation_store =
1178 get_srv_room_operation_store (room);
1179
1180 enum GNUNET_GenericReturnValue requested;
1181 requested = (GNUNET_MESSENGER_OP_REQUEST ==
1182 get_store_operation_type (operation_store, hash)?
1183 GNUNET_YES : GNUNET_NO);
1184
1185 if (GNUNET_YES == requested)
1186 cancel_store_operation (operation_store, hash);
1187
1188 struct GNUNET_MESSENGER_MessageStore *message_store =
1189 get_srv_room_message_store (room);
1190
1191 const struct GNUNET_MESSENGER_Message *old_message = get_store_message (
1192 message_store, hash);
1193
1194 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Handle a message in room (%s).\n",
1195 GNUNET_h2s (get_srv_room_key (room)));
1196
1197 if ((old_message) || (GNUNET_OK != put_store_message (message_store, hash,
1198 message)))
1199 {
1200 if (old_message != message)
1201 destroy_message (message);
1202
1203 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Duplicate message got dropped!\n");
1204 return GNUNET_NO;
1205 }
1206
1207 update_message_state (&(room->state), requested, message, hash);
1208
1209 if ((GNUNET_YES == requested) ||
1210 (GNUNET_MESSENGER_KIND_INFO == message->header.kind) ||
1211 (GNUNET_MESSENGER_KIND_REQUEST == message->header.kind))
1212 return GNUNET_YES;
1213
1214 if ((GNUNET_MESSENGER_KIND_MERGE == message->header.kind) &&
1215 (GNUNET_MESSENGER_OP_MERGE == get_store_operation_type (operation_store,
1216 &(message->body.
1217 merge.previous))))
1218 cancel_store_operation (operation_store, &(message->body.merge.previous));
1219
1220 if (GNUNET_MESSENGER_OP_MERGE == get_store_operation_type (operation_store,
1221 &(message->header.
1222 previous)))
1223 cancel_store_operation (operation_store, &(message->header.previous));
1224
1225 return GNUNET_YES;
1226}
1227
1228
1229struct GNUNET_MESSENGER_MemberSessionCompletion
1230{
1231 struct GNUNET_MESSENGER_MemberSessionCompletion *prev;
1232 struct GNUNET_MESSENGER_MemberSessionCompletion *next;
1233
1234 struct GNUNET_MESSENGER_MemberSession *session;
1235};
1236
1237struct GNUNET_MESSENGER_MemberUpdate
1238{
1239 const struct GNUNET_MESSENGER_Message *message;
1240 const struct GNUNET_HashCode *hash;
1241
1242 struct GNUNET_MESSENGER_MemberSessionCompletion *head;
1243 struct GNUNET_MESSENGER_MemberSessionCompletion *tail;
1244};
1245
1246static enum GNUNET_GenericReturnValue
1247iterate_update_member_sessions (void *cls,
1248 const struct
1249 GNUNET_CRYPTO_PublicKey *public_key,
1250 struct GNUNET_MESSENGER_MemberSession *session)
1251{
1252 struct GNUNET_MESSENGER_MemberUpdate *update = cls;
1253
1254 update_member_session_history (session, update->message, update->hash);
1255
1256 if (GNUNET_YES == is_member_session_completed (session))
1257 {
1258 struct GNUNET_MESSENGER_MemberSessionCompletion *element = GNUNET_new (
1259 struct GNUNET_MESSENGER_MemberSessionCompletion
1260 );
1261
1262 element->session = session;
1263
1264 GNUNET_CONTAINER_DLL_insert_tail (update->head, update->tail, element);
1265 }
1266
1267 return GNUNET_YES;
1268}
1269
1270
1271static void
1272remove_room_member_session (struct GNUNET_MESSENGER_SrvRoom *room,
1273 struct GNUNET_MESSENGER_MemberSession *session);
1274
1275void
1276callback_room_handle_message (struct GNUNET_MESSENGER_SrvRoom *room,
1277 const struct GNUNET_MESSENGER_Message *message,
1278 const struct GNUNET_HashCode *hash)
1279{
1280 GNUNET_assert ((room) && (message) && (hash));
1281
1282 struct GNUNET_MESSENGER_PeerStore *peer_store = get_srv_room_peer_store (
1283 room);
1284 struct GNUNET_MESSENGER_MemberStore *member_store =
1285 get_srv_room_member_store (room);
1286
1287 struct GNUNET_MESSENGER_SenderSession session;
1288
1289 if (GNUNET_YES == is_peer_message (message))
1290 {
1291 session.peer = get_store_peer_of (peer_store, message, hash);
1292
1293 if (! session.peer)
1294 {
1295 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1296 "Message handling dropped: Peer is missing!\n");
1297 return;
1298 }
1299 }
1300 else
1301 {
1302 struct GNUNET_MESSENGER_Member *member = get_store_member_of (member_store,
1303 message);
1304
1305 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Callback for message (%s)\n",
1306 GNUNET_h2s (hash));
1307
1308 if (! member)
1309 {
1310 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1311 "Message handling dropped: Member is missing!\n");
1312 return;
1313 }
1314
1315 session.member = get_member_session_of (member, message, hash);
1316
1317 if (! session.member)
1318 {
1319 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1320 "Message handling dropped: Session is missing!\n");
1321 return;
1322 }
1323 }
1324
1325 struct GNUNET_MESSENGER_MemberUpdate update;
1326 update.message = message;
1327 update.hash = hash;
1328
1329 update.head = NULL;
1330 update.tail = NULL;
1331
1332 iterate_store_members (member_store, iterate_update_member_sessions, &update);
1333
1334 while (update.head)
1335 {
1336 struct GNUNET_MESSENGER_MemberSessionCompletion *element = update.head;
1337
1338 remove_room_member_session (room, element->session);
1339
1340 GNUNET_CONTAINER_DLL_remove (update.head, update.tail, element);
1341 GNUNET_free (element);
1342 }
1343
1344 enum GNUNET_GenericReturnValue start_handle;
1345 start_handle = room->handling.head ? GNUNET_NO : GNUNET_YES;
1346
1347 add_to_list_messages (&(room->handling), hash);
1348
1349 switch (message->header.kind)
1350 {
1351 case GNUNET_MESSENGER_KIND_JOIN:
1352 handle_message_join (room, &session, message, hash);
1353 break;
1354 case GNUNET_MESSENGER_KIND_LEAVE:
1355 handle_message_leave (room, &session, message, hash);
1356 break;
1357 case GNUNET_MESSENGER_KIND_KEY:
1358 handle_message_key (room, &session, message, hash);
1359 break;
1360 case GNUNET_MESSENGER_KIND_PEER:
1361 handle_message_peer (room, &session, message, hash);
1362 break;
1363 case GNUNET_MESSENGER_KIND_ID:
1364 handle_message_id (room, &session, message, hash);
1365 break;
1366 case GNUNET_MESSENGER_KIND_MISS:
1367 handle_message_miss (room, &session, message, hash);
1368 break;
1369 case GNUNET_MESSENGER_KIND_DELETE:
1370 handle_message_delete (room, &session, message, hash);
1371 break;
1372 case GNUNET_MESSENGER_KIND_CONNECTION:
1373 handle_message_connection (room, &session, message, hash);
1374 break;
1375 default:
1376 break;
1377 }
1378
1379 if (GNUNET_YES == start_handle)
1380 handle_room_messages (room);
1381}
1382
1383
1384static void
1385get_room_data_subdir (struct GNUNET_MESSENGER_SrvRoom *room,
1386 char **dir)
1387{
1388 GNUNET_assert ((room) && (dir));
1389
1390 GNUNET_asprintf (dir, "%s%s%c%s%c", room->service->dir, "rooms",
1391 DIR_SEPARATOR, GNUNET_h2s (get_srv_room_key (room)),
1392 DIR_SEPARATOR);
1393}
1394
1395
1396void
1397load_srv_room (struct GNUNET_MESSENGER_SrvRoom *room)
1398{
1399 GNUNET_assert (room);
1400
1401 char *room_dir;
1402 get_room_data_subdir (room, &room_dir);
1403
1404 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Load room from directory: %s\n",
1405 room_dir);
1406
1407 if (GNUNET_YES == GNUNET_DISK_directory_test (room_dir, GNUNET_YES))
1408 {
1409 char *peers_file;
1410 GNUNET_asprintf (&peers_file, "%s%s", room_dir, "peers.list");
1411
1412 load_peer_store (get_srv_room_peer_store (room), peers_file);
1413 GNUNET_free (peers_file);
1414
1415 load_member_store (get_srv_room_member_store (room), room_dir);
1416 load_message_store (get_srv_room_message_store (room), room_dir);
1417 load_operation_store (get_srv_room_operation_store (room), room_dir);
1418
1419 char *basement_file;
1420 GNUNET_asprintf (&basement_file, "%s%s", room_dir, "basement.list");
1421
1422 load_list_tunnels (&(room->basement), basement_file);
1423 GNUNET_free (basement_file);
1424
1425 load_message_state (&(room->state), room_dir);
1426 }
1427
1428 GNUNET_free (room_dir);
1429}
1430
1431
1432void
1433save_srv_room (struct GNUNET_MESSENGER_SrvRoom *room)
1434{
1435 GNUNET_assert (room);
1436
1437 char *room_dir;
1438 get_room_data_subdir (room, &room_dir);
1439
1440 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Save room to directory: %s\n",
1441 room_dir);
1442
1443 if ((GNUNET_YES == GNUNET_DISK_directory_test (room_dir, GNUNET_NO)) ||
1444 (GNUNET_OK == GNUNET_DISK_directory_create (room_dir)))
1445 {
1446 char *peers_file;
1447 GNUNET_asprintf (&peers_file, "%s%s", room_dir, "peers.list");
1448
1449 save_peer_store (get_srv_room_peer_store (room), peers_file);
1450 GNUNET_free (peers_file);
1451
1452 save_member_store (get_srv_room_member_store (room), room_dir);
1453 save_message_store (get_srv_room_message_store (room), room_dir);
1454 save_operation_store (get_srv_room_operation_store (room), room_dir);
1455
1456 char *basement_file;
1457 GNUNET_asprintf (&basement_file, "%s%s", room_dir, "basement.list");
1458
1459 save_list_tunnels (&(room->basement), basement_file);
1460 GNUNET_free (basement_file);
1461
1462 save_message_state (&(room->state), room_dir);
1463 }
1464
1465 GNUNET_free (room_dir);
1466}
1467
1468
1469void
1470remove_srv_room (struct GNUNET_MESSENGER_SrvRoom *room)
1471{
1472 GNUNET_assert (room);
1473
1474 char *room_dir;
1475 get_room_data_subdir (room, &room_dir);
1476
1477 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Remove room from directory: %s\n",
1478 room_dir);
1479
1480 if (GNUNET_YES == GNUNET_DISK_directory_test (room_dir, GNUNET_YES))
1481 GNUNET_DISK_directory_remove (room_dir);
1482
1483 GNUNET_free (room_dir);
1484}
1485
1486
1487static void
1488remove_room_member_session (struct GNUNET_MESSENGER_SrvRoom *room,
1489 struct GNUNET_MESSENGER_MemberSession *session)
1490{
1491 GNUNET_assert ((room) && (session));
1492
1493 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1494 "Remove member session from room: %s (%s)\n",
1495 GNUNET_sh2s (get_member_session_id (session)),
1496 GNUNET_h2s (get_srv_room_key (room)));
1497
1498 remove_member_session (session->member, session);
1499
1500 const struct GNUNET_CRYPTO_PublicKey *public_key =
1501 get_member_session_public_key (session);
1502
1503 struct GNUNET_HashCode hash;
1504 GNUNET_CRYPTO_hash (public_key, sizeof(*public_key), &hash);
1505
1506 char *room_dir;
1507 get_room_data_subdir (room, &room_dir);
1508
1509 char *session_dir;
1510 GNUNET_asprintf (
1511 &session_dir, "%s%s%c%s%c%s%c%s%c", room_dir,
1512 "members", DIR_SEPARATOR,
1513 GNUNET_sh2s (get_member_session_id (session)), DIR_SEPARATOR,
1514 "sessions", DIR_SEPARATOR,
1515 GNUNET_h2s (&hash), DIR_SEPARATOR
1516 );
1517
1518 GNUNET_free (room_dir);
1519
1520 GNUNET_DISK_directory_remove (session_dir);
1521 GNUNET_free (session_dir);
1522
1523 destroy_member_session (session);
1524}
diff --git a/src/service/messenger/gnunet-service-messenger_room.h b/src/service/messenger/gnunet-service-messenger_room.h
new file mode 100644
index 000000000..e9395cfc4
--- /dev/null
+++ b/src/service/messenger/gnunet-service-messenger_room.h
@@ -0,0 +1,404 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_room.h
23 * @brief GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_SERVICE_MESSENGER_ROOM_H
27#define GNUNET_SERVICE_MESSENGER_ROOM_H
28
29#include "gnunet_cadet_service.h"
30#include "gnunet_util_lib.h"
31
32#include "gnunet_messenger_service.h"
33#include "gnunet-service-messenger_handle.h"
34#include "gnunet-service-messenger_message_state.h"
35#include "gnunet-service-messenger_list_messages.h"
36#include "gnunet-service-messenger_member_store.h"
37#include "gnunet-service-messenger_message_store.h"
38#include "gnunet-service-messenger_operation_store.h"
39#include "gnunet-service-messenger_peer_store.h"
40
41#include "messenger_api_list_tunnels.h"
42#include "messenger_api_message.h"
43
44#define GNUNET_MESSENGER_IDLE_DELAY GNUNET_TIME_relative_multiply \
45 (GNUNET_TIME_relative_get_second_ (), 5)
46
47#define GNUNET_MESSENGER_REQUEST_DELAY GNUNET_TIME_relative_multiply \
48 (GNUNET_TIME_relative_get_minute_ (), 5)
49
50#define GNUNET_MESSENGER_MERGE_DELAY GNUNET_TIME_relative_multiply \
51 (GNUNET_TIME_relative_get_second_ (), 30)
52
53struct GNUNET_MESSENGER_SrvTunnel;
54struct GNUNET_MESSENGER_MemberSession;
55
56struct GNUNET_MESSENGER_SrvRoom
57{
58 struct GNUNET_MESSENGER_Service *service;
59 struct GNUNET_MESSENGER_SrvHandle *host;
60 struct GNUNET_CADET_Port *port;
61
62 struct GNUNET_HashCode key;
63
64 struct GNUNET_CONTAINER_MultiPeerMap *tunnels;
65
66 struct GNUNET_MESSENGER_PeerStore peer_store;
67 struct GNUNET_MESSENGER_MemberStore member_store;
68 struct GNUNET_MESSENGER_MessageStore message_store;
69 struct GNUNET_MESSENGER_OperationStore operation_store;
70
71 struct GNUNET_MESSENGER_ListTunnels basement;
72 struct GNUNET_MESSENGER_MessageState state;
73
74 struct GNUNET_HashCode *peer_message;
75
76 struct GNUNET_MESSENGER_ListMessages handling;
77 struct GNUNET_SCHEDULER_Task *idle;
78};
79
80/**
81 * Creates and allocates a new room for a <i>handle</i> with a given <i>key</i>.
82 *
83 * @param[in,out] handle Handle
84 * @param[in] key Key of room
85 * @return New room
86 */
87struct GNUNET_MESSENGER_SrvRoom*
88create_srv_room (struct GNUNET_MESSENGER_SrvHandle *handle,
89 const struct GNUNET_HashCode *key);
90
91/**
92 * Destroys a room and frees its memory fully.
93 *
94 * The <i>deletion</i> flag should only be set to #GNUNET_YES if the
95 * room gets dropped by the service, otherwise #GNUNET_NO.
96 *
97 * @param[in,out] room Room
98 * @param[in] deletion Flag to indicate context of destruction
99 */
100void
101destroy_srv_room (struct GNUNET_MESSENGER_SrvRoom *room,
102 enum GNUNET_GenericReturnValue deletion);
103
104/**
105 * Returns the used peer store of a given <i>room</i>.
106 *
107 * @param[in,out] room Room
108 * @return Peer store
109 */
110struct GNUNET_MESSENGER_PeerStore*
111get_srv_room_peer_store (struct GNUNET_MESSENGER_SrvRoom *room);
112
113/**
114 * Returns the used member store of a given <i>room</i>.
115 *
116 * @param[in,out] room Room
117 * @return Member store
118 */
119struct GNUNET_MESSENGER_MemberStore*
120get_srv_room_member_store (struct GNUNET_MESSENGER_SrvRoom *room);
121
122/**
123 * Returns the used message store of a given <i>room</i>.
124 *
125 * @param[in,out] room Room
126 * @return Message store
127 */
128struct GNUNET_MESSENGER_MessageStore*
129get_srv_room_message_store (struct GNUNET_MESSENGER_SrvRoom *room);
130
131/**
132 * Returns the used operation store of a given <i>room</i>.
133 *
134 * @param[in,out] room Room
135 * @return Operation store
136 */
137struct GNUNET_MESSENGER_OperationStore*
138get_srv_room_operation_store (struct GNUNET_MESSENGER_SrvRoom *room);
139
140/**
141 * Tries to open a <i>room</i> for a given <i>handle</i>. If the room has already been opened, the handle
142 * will locally join the room.
143 *
144 * Calling this method should result in joining a room and sending a peer message as well for this peer.
145 *
146 * If the function returns #GNUNET_YES the port for this room is guaranteed to be open for incoming connections.
147 *
148 * @param[in,out] room Room
149 * @param[in,out] handle Handle
150 * @return #GNUNET_YES on success, #GNUNET_NO on failure.
151 */
152enum GNUNET_GenericReturnValue
153open_srv_room (struct GNUNET_MESSENGER_SrvRoom *room,
154 struct GNUNET_MESSENGER_SrvHandle *handle);
155
156/**
157 * Connects a tunnel to a hosting peer of a <i>room</i> through a so called <i>door</i> which is represented by
158 * a peer identity of a hosting peer. During the connection the handle will join the room as a member, waiting for
159 * an info message from the selected host.
160 *
161 * @param[in,out] room Room
162 * @param[in,out] handle Handle
163 * @param[in] door Peer identity
164 * @return #GNUNET_YES on success, #GNUNET_NO on failure.
165 */
166enum GNUNET_GenericReturnValue
167enter_srv_room_at (struct GNUNET_MESSENGER_SrvRoom *room,
168 struct GNUNET_MESSENGER_SrvHandle *handle,
169 const struct GNUNET_PeerIdentity *door);
170
171/**
172 * Packs a <i>message</i> depending on the selected <i>mode</i> into a newly allocated envelope. It will set the
173 * timestamp of the message, the sender id and the previous messages hash automatically before packing. The message
174 * will be signed by the handles private key.
175 *
176 * If the optional <i>hash</i> parameter is a valid pointer, its value will be overridden by the signed messages hash.
177 *
178 * If <i>mode</i> is set to #GNUNET_MESSENGER_PACK_MODE_ENVELOPE, the function returns a valid envelope to send
179 * through a message queue, otherwise NULL.
180 *
181 * @param[in] room Room
182 * @param[in] handle Handle
183 * @param[in,out] message Message
184 * @param[out] hash Hash of message
185 * @param[in] mode Packing mode
186 * @return New envelope or NULL
187 */
188struct GNUNET_MQ_Envelope*
189pack_srv_room_message (const struct GNUNET_MESSENGER_SrvRoom *room,
190 const struct GNUNET_MESSENGER_SrvHandle *handle,
191 struct GNUNET_MESSENGER_Message *message,
192 struct GNUNET_HashCode *hash,
193 enum GNUNET_MESSENGER_PackMode mode);
194
195/**
196 * Sends a <i>message</i> from a given <i>handle</i> into a <i>room</i>. The <i>hash</i> parameter will be
197 * updated with the hash-value resulting from the sent message.
198 *
199 * The function handles packing the message automatically and will call linked message-events locally even if
200 * the message won't be sent to another peer.
201 *
202 * The function returns #GNUNET_YES on success, #GNUNET_NO if message is null and
203 * #GNUNET_SYSERR if the message was known already.
204 *
205 * @param[in,out] room Room
206 * @param[in,out] handle Handle
207 * @param[in,out] message Message
208 * @return #GNUNET_YES on success, #GNUNET_NO or #GNUNET_SYSERR otherwise.
209 */
210enum GNUNET_GenericReturnValue
211send_srv_room_message (struct GNUNET_MESSENGER_SrvRoom *room,
212 struct GNUNET_MESSENGER_SrvHandle *handle,
213 struct GNUNET_MESSENGER_Message *message);
214
215/**
216 * Forwards a <i>message</i> with a given <i>hash</i> to a specific <i>tunnel</i> inside of a <i>room</i>.
217 *
218 * @param[in,out] room Room
219 * @param[in,out] tunnel Tunnel
220 * @param[in,out] message Message
221 * @param[in] hash Hash of message
222 */
223void
224forward_srv_room_message (struct GNUNET_MESSENGER_SrvRoom *room,
225 struct GNUNET_MESSENGER_SrvTunnel *tunnel,
226 struct GNUNET_MESSENGER_Message *message,
227 const struct GNUNET_HashCode *hash);
228
229/**
230 * Checks the current state of opening a given <i>room</i> from this peer and re-publishes it
231 * if necessary to a selected <i>tunnel</i> or to all connected tunnels if necessary or if the
232 * selected tunnel is NULL.
233 *
234 * @param[in,out] room Room
235 * @param[in,out] tunnel Tunnel
236 */
237void
238check_srv_room_peer_status (struct GNUNET_MESSENGER_SrvRoom *room,
239 struct GNUNET_MESSENGER_SrvTunnel *tunnel);
240
241/**
242 * Reduces all current forks inside of the message history of a <i>room</i> to one remaining last message
243 * by merging them down. All merge messages will be sent from a given <i>handle</i>.
244 *
245 * @param[in,out] room Room
246 * @param[in,out] handle Handle
247 */
248void
249merge_srv_room_last_messages (struct GNUNET_MESSENGER_SrvRoom *room,
250 struct GNUNET_MESSENGER_SrvHandle *handle);
251
252/**
253 * Deletes a message from the <i>room</i> with a given <i>hash</i> in a specific <i>delay</i> if
254 * the provided member by its session is permitted to do so.
255 *
256 * @param[in,out] room Room
257 * @param[in,out] session Member session
258 * @param[in] hash Hash of message
259 * @param[in] delay Delay of deletion
260 * @return #GNUNET_YES on success, #GNUNET_NO if permission gets denied, #GNUNET_SYSERR on operation failure
261 */
262enum GNUNET_GenericReturnValue
263delete_srv_room_message (struct GNUNET_MESSENGER_SrvRoom *room,
264 struct GNUNET_MESSENGER_MemberSession *session,
265 const struct GNUNET_HashCode *hash,
266 const struct GNUNET_TIME_Relative delay);
267
268/**
269 * Returns the CADET handle from a rooms service.
270 *
271 * @param[in,out] room Room
272 * @return CADET handle
273 */
274struct GNUNET_CADET_Handle*
275get_srv_room_cadet (struct GNUNET_MESSENGER_SrvRoom *room);
276
277/**
278 * Returns the shared secret you need to access a <i>room</i>.
279 *
280 * @param[in] room Room
281 * @return Shared secret
282 */
283const struct GNUNET_HashCode*
284get_srv_room_key (const struct GNUNET_MESSENGER_SrvRoom *room);
285
286/**
287 * Returns a tunnel inside of a <i>room</i> leading towards a given <i>peer</i> if such a tunnel exists,
288 * otherwise NULL.
289 *
290 * @param[in] room Room
291 * @param[in] peer Peer identity
292 * @return Tunnel or NULL
293 */
294const struct GNUNET_MESSENGER_SrvTunnel*
295get_srv_room_tunnel (const struct GNUNET_MESSENGER_SrvRoom *room,
296 const struct GNUNET_PeerIdentity *peer);
297
298/**
299 * Method called whenever a <i>message</i> is found during a request in a <i>room</i>.
300 *
301 * @param[in,out] cls Closure from #request_room_message
302 * @param[in,out] room Room
303 * @param[in] message Message or NULL
304 * @param[in] hash Hash of message
305 */
306typedef void (GNUNET_MESSENGER_MessageRequestCallback) (
307 void *cls,
308 struct GNUNET_MESSENGER_SrvRoom *room,
309 const struct GNUNET_MESSENGER_Message *message,
310 const struct GNUNET_HashCode *hash
311 );
312
313/**
314 * Requests a message from a <i>room</i> identified by a given <i>hash</i>. If the message is found,
315 * the selected <i>callback</i> will be called with it and the provided closure. If no matching message
316 * is found but it wasn't deleted the selected callback will be called with #NULL as message instead.
317 * In case of deletion the next available previous message will be used to call the callback.
318 *
319 * It is also possible that the given callback will not be called if the requesting session is not
320 * permitted!
321 *
322 * @param[in,out] room Room
323 * @param[in] hash Hash of message
324 * @param[in] callback Callback to process result
325 * @param[in] cls Closure for the <i>callback</i>
326 * @return #GNUNET_YES if the request could be processed, otherwise #GNUNET_NO
327 */
328enum GNUNET_GenericReturnValue
329request_srv_room_message (struct GNUNET_MESSENGER_SrvRoom *room,
330 const struct GNUNET_HashCode *hash,
331 const struct GNUNET_MESSENGER_MemberSession *session,
332 GNUNET_MESSENGER_MessageRequestCallback callback,
333 void *cls);
334
335/**
336 * Checks for potential collisions with member ids and solves them changing active handles ids if they
337 * use an already used member id (comparing public key and timestamp).
338 *
339 * @param[in,out] room Room
340 * @param[in] public_key Public key
341 * @param[in] member_id Member ID
342 * @param[in] timestamp Timestamp
343 */
344void
345solve_srv_room_member_collisions (struct GNUNET_MESSENGER_SrvRoom *room,
346 const struct
347 GNUNET_CRYPTO_PublicKey *public_key,
348 const struct GNUNET_ShortHashCode *member_id,
349 struct GNUNET_TIME_Absolute timestamp);
350
351/**
352 * Rebuilds the decentralized structure for a <i>room</i> by ensuring all required connections are made
353 * depending on the amount of peers and this peers index in the list of them.
354 *
355 * @param[in,out] room Room
356 */
357void
358rebuild_srv_room_basement_structure (struct GNUNET_MESSENGER_SrvRoom *room);
359
360/**
361 * Returns the amount of active tunnels of a given <i>room</i>.
362 *
363 * @param[in] room Room
364 * @return Amount of tunnels
365 */
366uint32_t
367get_srv_room_amount_of_tunnels (const struct GNUNET_MESSENGER_SrvRoom *room);
368
369/**
370 * Returns connection flags about connection information of a given <i>room</i> and the service managing it.
371 *
372 * @param[in] room Room
373 * @return Connection flags
374 */
375uint32_t
376get_srv_room_connection_flags (const struct GNUNET_MESSENGER_SrvRoom *room);
377
378/**
379 * Loads the local configuration for a given <i>room</i> of a service which contains the last messages hash
380 * and the ruleset for general access of new members.
381 *
382 * @param[out] room Room
383 */
384void
385load_srv_room (struct GNUNET_MESSENGER_SrvRoom *room);
386
387/**
388 * Saves the configuration for a given <i>room</i> of a service which contains the last messages hash
389 * and the ruleset for general access of new members locally.
390 *
391 * @param[in] room Room
392 */
393void
394save_srv_room (struct GNUNET_MESSENGER_SrvRoom *room);
395
396/**
397 * Removes the configuration for a given <i>room</i> of a service.
398 *
399 * @param[in] room Room
400 */
401void
402remove_srv_room (struct GNUNET_MESSENGER_SrvRoom *room);
403
404#endif //GNUNET_SERVICE_MESSENGER_ROOM_H
diff --git a/src/service/messenger/gnunet-service-messenger_sender_session.h b/src/service/messenger/gnunet-service-messenger_sender_session.h
new file mode 100644
index 000000000..8da9044ce
--- /dev/null
+++ b/src/service/messenger/gnunet-service-messenger_sender_session.h
@@ -0,0 +1,42 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2023 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_sender_session.h
23 * @brief GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_SERVICE_MESSENGER_SENDER_SESSION_H
27#define GNUNET_SERVICE_MESSENGER_SENDER_SESSION_H
28
29#include "gnunet_util_lib.h"
30
31#include "gnunet-service-messenger_member_session.h"
32
33struct GNUNET_MESSENGER_SenderSession
34{
35 union
36 {
37 struct GNUNET_MESSENGER_MemberSession *member;
38 struct GNUNET_PeerIdentity *peer;
39 };
40};
41
42#endif /* GNUNET_SERVICE_MESSENGER_SENDER_SESSION_H */
diff --git a/src/service/messenger/gnunet-service-messenger_service.c b/src/service/messenger/gnunet-service-messenger_service.c
new file mode 100644
index 000000000..11656d6b7
--- /dev/null
+++ b/src/service/messenger/gnunet-service-messenger_service.c
@@ -0,0 +1,461 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_service.c
23 * @brief GNUnet MESSENGER service
24 */
25
26#include "gnunet-service-messenger_service.h"
27
28#include "gnunet-service-messenger_message_kind.h"
29#include "gnunet-service-messenger_room.h"
30
31#include "gnunet_common.h"
32#include "messenger_api_util.h"
33
34static void
35callback_shutdown_service (void *cls)
36{
37 struct GNUNET_MESSENGER_Service *service = cls;
38
39 if (service)
40 {
41 service->shutdown = NULL;
42
43 destroy_service (service);
44 }
45}
46
47
48struct GNUNET_MESSENGER_Service*
49create_service (const struct GNUNET_CONFIGURATION_Handle *config,
50 struct GNUNET_SERVICE_Handle *service_handle)
51{
52 GNUNET_assert ((config) && (service_handle));
53
54 struct GNUNET_MESSENGER_Service *service = GNUNET_new (struct
55 GNUNET_MESSENGER_Service);
56
57 service->config = config;
58 service->service = service_handle;
59
60 service->shutdown = GNUNET_SCHEDULER_add_shutdown (&callback_shutdown_service,
61 service);
62
63 service->peer = NULL;
64 service->dir = NULL;
65
66 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (service->config,
67 GNUNET_MESSENGER_SERVICE_NAME,
68 "MESSENGER_DIR",
69 &(service->dir)))
70 {
71 if (service->dir)
72 GNUNET_free (service->dir);
73
74 service->dir = NULL;
75 }
76 else
77 {
78 if ((GNUNET_YES != GNUNET_DISK_directory_test (service->dir, GNUNET_YES)) &&
79 (GNUNET_OK
80 !=
81 GNUNET_DISK_directory_create (service->dir)))
82 {
83 GNUNET_free (service->dir);
84
85 service->dir = NULL;
86 }
87 }
88
89 service->auto_connecting = GNUNET_CONFIGURATION_get_value_yesno (
90 service->config,
91 GNUNET_MESSENGER_SERVICE_NAME,
92 "MESSENGER_AUTO_CONNECTING");
93
94 service->auto_routing = GNUNET_CONFIGURATION_get_value_yesno (service->config,
95 GNUNET_MESSENGER_SERVICE_NAME,
96 "MESSENGER_AUTO_ROUTING");
97
98 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (service->config,
99 GNUNET_MESSENGER_SERVICE_NAME,
100 "MESSENGER_MIN_ROUTERS",
101 &(service->min_routers)))
102 service->min_routers = 0;
103
104 service->cadet = GNUNET_CADET_connect (service->config);
105
106 init_list_handles (&(service->handles));
107
108 service->rooms = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
109
110 init_contact_store (get_service_contact_store (service));
111
112 return service;
113}
114
115
116static enum GNUNET_GenericReturnValue
117iterate_destroy_rooms (void *cls,
118 const struct GNUNET_HashCode *key,
119 void *value)
120{
121 struct GNUNET_MESSENGER_SrvRoom *room = value;
122 destroy_srv_room (room, GNUNET_NO);
123 return GNUNET_YES;
124}
125
126
127void
128destroy_service (struct GNUNET_MESSENGER_Service *service)
129{
130 GNUNET_assert (service);
131
132 if (service->shutdown)
133 {
134 GNUNET_SCHEDULER_cancel (service->shutdown);
135
136 service->shutdown = NULL;
137 }
138
139 clear_list_handles (&(service->handles));
140
141 GNUNET_CONTAINER_multihashmap_iterate (service->rooms, iterate_destroy_rooms,
142 NULL);
143 GNUNET_CONTAINER_multihashmap_destroy (service->rooms);
144
145 clear_contact_store (get_service_contact_store (service));
146
147 if (service->cadet)
148 {
149 GNUNET_CADET_disconnect (service->cadet);
150
151 service->cadet = NULL;
152 }
153
154 if (service->dir)
155 {
156 GNUNET_free (service->dir);
157
158 service->dir = NULL;
159 }
160
161 if (service->peer)
162 {
163 GNUNET_free (service->peer);
164
165 service->peer = NULL;
166 }
167
168 GNUNET_SERVICE_shutdown (service->service);
169
170 GNUNET_free (service);
171}
172
173
174struct GNUNET_MESSENGER_ContactStore*
175get_service_contact_store (struct GNUNET_MESSENGER_Service *service)
176{
177 GNUNET_assert (service);
178
179 return &(service->contact_store);
180}
181
182
183struct GNUNET_MESSENGER_SrvHandle*
184add_service_handle (struct GNUNET_MESSENGER_Service *service,
185 struct GNUNET_MQ_Handle *mq)
186{
187 GNUNET_assert ((service) && (mq));
188
189 struct GNUNET_MESSENGER_SrvHandle *handle = create_srv_handle (service, mq);
190
191 if (handle)
192 {
193 add_list_handle (&(service->handles), handle);
194 }
195
196 return handle;
197}
198
199
200void
201remove_service_handle (struct GNUNET_MESSENGER_Service *service,
202 struct GNUNET_MESSENGER_SrvHandle *handle)
203{
204 GNUNET_assert ((service) && (handle));
205
206 if (! handle)
207 return;
208
209 if (GNUNET_YES == remove_list_handle (&(service->handles), handle))
210 destroy_srv_handle (handle);
211}
212
213
214enum GNUNET_GenericReturnValue
215get_service_peer_identity (struct GNUNET_MESSENGER_Service *service,
216 struct GNUNET_PeerIdentity *peer)
217{
218 GNUNET_assert ((service) && (peer));
219
220 if (service->peer)
221 {
222 GNUNET_memcpy (peer, service->peer, sizeof(struct GNUNET_PeerIdentity));
223 return GNUNET_OK;
224 }
225
226 enum GNUNET_GenericReturnValue result;
227 result = GNUNET_CRYPTO_get_peer_identity (service->config, peer);
228
229 if (GNUNET_OK != result)
230 return result;
231
232 if (! service->peer)
233 service->peer = GNUNET_new (struct GNUNET_PeerIdentity);
234
235 GNUNET_memcpy (service->peer, peer, sizeof(struct GNUNET_PeerIdentity));
236 return result;
237}
238
239
240struct GNUNET_MESSENGER_SrvRoom*
241get_service_room (const struct GNUNET_MESSENGER_Service *service,
242 const struct GNUNET_HashCode *key)
243{
244 GNUNET_assert ((service) && (key));
245
246 return GNUNET_CONTAINER_multihashmap_get (service->rooms, key);
247}
248
249
250struct HandleInitializationClosure
251{
252 struct GNUNET_MESSENGER_SrvHandle *handle;
253 struct GNUNET_MESSENGER_SrvRoom *room;
254 const struct GNUNET_CRYPTO_PublicKey *pubkey;
255};
256
257static enum GNUNET_GenericReturnValue
258find_member_session_in_room (void *cls,
259 const struct GNUNET_CRYPTO_PublicKey *public_key,
260 struct GNUNET_MESSENGER_MemberSession *session)
261{
262 struct HandleInitializationClosure *init = cls;
263
264 if (! public_key)
265 return GNUNET_YES;
266
267 const struct GNUNET_CRYPTO_PublicKey *pubkey = get_srv_handle_key (
268 init->handle);
269
270 if (0 != GNUNET_memcmp (pubkey, public_key))
271 return GNUNET_YES;
272
273 const struct GNUNET_ShortHashCode *id = get_member_session_id (session);
274
275 if (! id)
276 {
277 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Initialitation: Missing member id!");
278 return GNUNET_NO;
279 }
280
281 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
282 "Initialitation: Matching member found (%s)!\n",
283 GNUNET_sh2s (id));
284
285 change_srv_handle_member_id (init->handle, get_srv_room_key (init->room), id);
286 return GNUNET_NO;
287}
288
289
290static void
291initialize_service_handle (struct GNUNET_MESSENGER_SrvHandle *handle,
292 struct GNUNET_MESSENGER_SrvRoom *room)
293{
294 GNUNET_assert ((handle) && (room));
295
296 struct GNUNET_MESSENGER_MemberStore *store = get_srv_room_member_store (room);
297 if (! store)
298 return;
299
300 const struct GNUNET_CRYPTO_PublicKey *pubkey = get_srv_handle_key (handle);
301 if ((! pubkey) || (0 == GNUNET_memcmp (pubkey, get_anonymous_public_key ())))
302 return;
303
304 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
305 "Initialize member id of handle via matching member in room!\n");
306
307 struct HandleInitializationClosure init;
308 init.handle = handle;
309 init.room = room;
310 init.pubkey = pubkey;
311
312 iterate_store_members (store, find_member_session_in_room, &init);
313}
314
315
316enum GNUNET_GenericReturnValue
317open_service_room (struct GNUNET_MESSENGER_Service *service,
318 struct GNUNET_MESSENGER_SrvHandle *handle,
319 const struct GNUNET_HashCode *key)
320{
321 GNUNET_assert ((service) && (handle) && (key));
322
323 struct GNUNET_MESSENGER_SrvRoom *room = get_service_room (service, key);
324
325 if (room)
326 {
327 initialize_service_handle (handle, room);
328 return open_srv_room (room, handle);
329 }
330
331 room = create_srv_room (handle, key);
332 initialize_service_handle (handle, room);
333
334 if ((GNUNET_YES == open_srv_room (room, handle)) &&
335 (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (service->rooms,
336 key, room,
337 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)))
338 return GNUNET_YES;
339
340 destroy_srv_room (room, GNUNET_YES);
341 return GNUNET_NO;
342}
343
344
345enum GNUNET_GenericReturnValue
346entry_service_room (struct GNUNET_MESSENGER_Service *service,
347 struct GNUNET_MESSENGER_SrvHandle *handle,
348 const struct GNUNET_PeerIdentity *door,
349 const struct GNUNET_HashCode *key)
350{
351 GNUNET_assert ((service) && (handle) && (door) && (key));
352
353 struct GNUNET_MESSENGER_SrvRoom *room = get_service_room (service, key);
354
355 if (room)
356 {
357 initialize_service_handle (handle, room);
358
359 if (GNUNET_YES == enter_srv_room_at (room, handle, door))
360 return GNUNET_YES;
361 else
362 return GNUNET_NO;
363 }
364
365 room = create_srv_room (handle, key);
366 initialize_service_handle (handle, room);
367
368 if ((GNUNET_YES == enter_srv_room_at (room, handle, door)) &&
369 (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (service->rooms,
370 key, room,
371 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)))
372 {
373 return GNUNET_YES;
374 }
375 else
376 {
377 destroy_srv_room (room, GNUNET_YES);
378 return GNUNET_NO;
379 }
380
381}
382
383
384enum GNUNET_GenericReturnValue
385close_service_room (struct GNUNET_MESSENGER_Service *service,
386 struct GNUNET_MESSENGER_SrvHandle *handle,
387 const struct GNUNET_HashCode *key,
388 enum GNUNET_GenericReturnValue deletion)
389{
390 GNUNET_assert ((service) && (handle) && (key));
391
392 struct GNUNET_MESSENGER_SrvRoom *room = get_service_room (service, key);
393
394 if (! room)
395 return GNUNET_NO;
396
397 struct GNUNET_ShortHashCode *id = (struct GNUNET_ShortHashCode*) (
398 GNUNET_CONTAINER_multihashmap_get (handle->member_ids, key));
399
400 GNUNET_assert (id);
401
402 if (GNUNET_YES != GNUNET_CONTAINER_multihashmap_remove (handle->member_ids,
403 key, id))
404 return GNUNET_NO;
405
406 GNUNET_free (id);
407
408 struct GNUNET_MESSENGER_SrvHandle *member_handle = (struct
409 GNUNET_MESSENGER_SrvHandle
410 *)
411 find_list_handle_by_member (
412 &(service->handles), key);
413
414 if (! member_handle)
415 {
416 if (GNUNET_OK == GNUNET_CONTAINER_multihashmap_remove (service->rooms, key,
417 room))
418 {
419 destroy_srv_room (room, deletion);
420 return GNUNET_YES;
421 }
422 else
423 return GNUNET_NO;
424 }
425
426 if (room->host == handle)
427 {
428 room->host = member_handle;
429
430 if (room->peer_message)
431 send_srv_room_message (room, room->host, create_message_connection (
432 room));
433 }
434
435 return GNUNET_YES;
436}
437
438
439void
440handle_service_message (struct GNUNET_MESSENGER_Service *service,
441 struct GNUNET_MESSENGER_SrvRoom *room,
442 const struct GNUNET_MESSENGER_SenderSession *session,
443 const struct GNUNET_MESSENGER_Message *message,
444 const struct GNUNET_HashCode *hash)
445{
446 GNUNET_assert ((service) && (room) && (session) && (message) && (hash));
447
448 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
449 "Notify active clients about message: %s (%s)\n",
450 GNUNET_h2s (hash), GNUNET_MESSENGER_name_of_kind (
451 message->header.kind));
452
453 struct GNUNET_MESSENGER_ListHandle *element = service->handles.head;
454
455 while (element)
456 {
457 notify_srv_handle_message (element->handle, room, session, message, hash,
458 GNUNET_YES);
459 element = element->next;
460 }
461}
diff --git a/src/service/messenger/gnunet-service-messenger_service.h b/src/service/messenger/gnunet-service-messenger_service.h
new file mode 100644
index 000000000..7634dba8e
--- /dev/null
+++ b/src/service/messenger/gnunet-service-messenger_service.h
@@ -0,0 +1,205 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_service.h
23 * @brief GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_SERVICE_MESSENGER_SERVICE_H
27#define GNUNET_SERVICE_MESSENGER_SERVICE_H
28
29#include "gnunet_common.h"
30#include "gnunet_configuration_lib.h"
31#include "gnunet_util_lib.h"
32
33#include "gnunet-service-messenger_list_handles.h"
34#include "gnunet-service-messenger_sender_session.h"
35
36#include "messenger_api_contact_store.h"
37
38struct GNUNET_MESSENGER_SrvRoom;
39
40struct GNUNET_MESSENGER_Service
41{
42 const struct GNUNET_CONFIGURATION_Handle *config;
43 struct GNUNET_SERVICE_Handle *service;
44
45 struct GNUNET_SCHEDULER_Task *shutdown;
46
47 struct GNUNET_PeerIdentity *peer;
48 char *dir;
49
50 enum GNUNET_GenericReturnValue auto_connecting;
51 enum GNUNET_GenericReturnValue auto_routing;
52 unsigned long long min_routers;
53
54 struct GNUNET_CADET_Handle *cadet;
55
56 struct GNUNET_MESSENGER_ContactStore contact_store;
57
58 struct GNUNET_MESSENGER_ListHandles handles;
59
60 struct GNUNET_CONTAINER_MultiHashMap *rooms;
61};
62
63/**
64 * Creates and allocates a new service using a given <i>config</i> and a GNUnet service handle.
65 *
66 * @param[in] config Configuration
67 * @param[in,out] service_handle GNUnet service handle
68 * @return New service
69 */
70struct GNUNET_MESSENGER_Service*
71create_service (const struct GNUNET_CONFIGURATION_Handle *config,
72 struct GNUNET_SERVICE_Handle *service_handle);
73
74/**
75 * Destroys a <i>service</i> and frees its memory fully.
76 *
77 * @param[in,out] service Service
78 */
79void
80destroy_service (struct GNUNET_MESSENGER_Service *service);
81
82/**
83 * Returns the used contact store of a given <i>service</i>.
84 *
85 * @param[in,out] service Service
86 * @return Contact store
87 */
88struct GNUNET_MESSENGER_ContactStore*
89get_service_contact_store (struct GNUNET_MESSENGER_Service *service);
90
91/**
92 * Creates and adds a new handle to a <i>service</i> using a given message queue.
93 *
94 * @param[in,out] service Service
95 * @param[in,out] mq Message queue
96 * @return New handle
97 */
98struct GNUNET_MESSENGER_SrvHandle*
99add_service_handle (struct GNUNET_MESSENGER_Service *service,
100 struct GNUNET_MQ_Handle *mq);
101
102/**
103 * Removes a <i>handle</i> from a <i>service</i> and destroys it.
104 *
105 * @param[in,out] service Service
106 * @param[in,out] handle Handle
107 */
108void
109remove_service_handle (struct GNUNET_MESSENGER_Service *service,
110 struct GNUNET_MESSENGER_SrvHandle *handle);
111
112/**
113 * Tries to write the peer identity of the peer running a <i>service</i> on to the <i>peer</i>
114 * parameter. The functions returns #GNUNET_OK on success, otherwise #GNUNET_SYSERR.
115 *
116 * @param[in,out] service Service
117 * @param[out] peer Peer identity
118 * @return #GNUNET_OK on success, otherwise #GNUNET_SYSERR
119 */
120enum GNUNET_GenericReturnValue
121get_service_peer_identity (struct GNUNET_MESSENGER_Service *service,
122 struct GNUNET_PeerIdentity *peer);
123
124/**
125 * Returns the room identified by a given <i>key</i> for a <i>service</i>. If the service doesn't know any room
126 * using the given key, NULL gets returned.
127 *
128 * @param[in] service Service
129 * @param[in] key Key of room
130 * @return Room or NULL
131 */
132struct GNUNET_MESSENGER_SrvRoom*
133get_service_room (const struct GNUNET_MESSENGER_Service *service,
134 const struct GNUNET_HashCode *key);
135
136/**
137 * Tries to open a room using a given <i>key</i> for a <i>service</i> by a specific <i>handle</i>. The room will be
138 * created if necessary. If the function is successful, it returns #GNUNET_YES, otherwise #GNUNET_NO.
139 *
140 * @param[in,out] service Service
141 * @param[in,out] handle Handle
142 * @param[in] key Key of room
143 * @return #GNUNET_YES on success, otherwise #GNUNET_NO
144 */
145enum GNUNET_GenericReturnValue
146open_service_room (struct GNUNET_MESSENGER_Service *service,
147 struct GNUNET_MESSENGER_SrvHandle *handle,
148 const struct GNUNET_HashCode *key);
149
150/**
151 * Tries to enter a room using a given <i>key</i> for a <i>service</i> by a specific <i>handle</i>. The room will
152 * be created if necessary. If the function is successful, it returns #GNUNET_YES, otherwise #GNUNET_NO.
153 *
154 * The room will be entered through the peer identitied by the peer identity provided as <i>door</i> parameter and
155 * a new connection will be made.
156 *
157 * @param[in,out] service Service
158 * @param[in,out] handle Handle
159 * @param[in] door Peer identity
160 * @param[in] key Key of room
161 * @return #GNUNET_YES on success, otherwise #GNUNET_NO
162 */
163enum GNUNET_GenericReturnValue
164entry_service_room (struct GNUNET_MESSENGER_Service *service,
165 struct GNUNET_MESSENGER_SrvHandle *handle,
166 const struct GNUNET_PeerIdentity *door,
167 const struct GNUNET_HashCode *key);
168
169/**
170 * Tries to close a room using a given <i>key</i> for a <i>service</i> by a specific <i>handle</i>. The room will
171 * be created if necessary. If the function is successful, it returns #GNUNET_YES, otherwise #GNUNET_NO.
172 *
173 * If the specific handle is currently the host of the room for this service, a new handle which is a member will
174 * take its place. Otherwise the room will be destroyed for this service.
175 *
176 * @param[in,out] service Service
177 * @param[in,out] handle Handle
178 * @param[in] key Key of room
179 * @param[in] deletion Flag to indicate context of closing
180 * @return #GNUNET_YES on success, otherwise #GNUNET_NO
181 */
182enum GNUNET_GenericReturnValue
183close_service_room (struct GNUNET_MESSENGER_Service *service,
184 struct GNUNET_MESSENGER_SrvHandle *handle,
185 const struct GNUNET_HashCode *key,
186 enum GNUNET_GenericReturnValue deletion);
187
188/**
189 * Sends a received or sent <i>message</i> with a given <i>hash</i> to each handle of a <i>service</i> which
190 * is currently member of a specific <i>room</i> for handling it in the client API.
191 *
192 * @param[in,out] service Service
193 * @param[in,out] room Room
194 * @param[in] session Sender session
195 * @param[in] message Message
196 * @param[in] hash Hash of message
197 */
198void
199handle_service_message (struct GNUNET_MESSENGER_Service *service,
200 struct GNUNET_MESSENGER_SrvRoom *room,
201 const struct GNUNET_MESSENGER_SenderSession *session,
202 const struct GNUNET_MESSENGER_Message *message,
203 const struct GNUNET_HashCode *hash);
204
205#endif //GNUNET_SERVICE_MESSENGER_SERVICE_H
diff --git a/src/service/messenger/gnunet-service-messenger_tunnel.c b/src/service/messenger/gnunet-service-messenger_tunnel.c
new file mode 100644
index 000000000..98d0ab1ce
--- /dev/null
+++ b/src/service/messenger/gnunet-service-messenger_tunnel.c
@@ -0,0 +1,441 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_tunnel.c
23 * @brief GNUnet MESSENGER service
24 */
25
26#include "gnunet-service-messenger_tunnel.h"
27
28#include "gnunet-service-messenger_handle.h"
29#include "gnunet-service-messenger_message_recv.h"
30#include "gnunet-service-messenger_message_store.h"
31#include "gnunet-service-messenger_operation_store.h"
32#include "gnunet-service-messenger_operation.h"
33
34#include "messenger_api_util.h"
35
36struct GNUNET_MESSENGER_SrvTunnel*
37create_tunnel (struct GNUNET_MESSENGER_SrvRoom *room,
38 const struct GNUNET_PeerIdentity *door)
39{
40 GNUNET_assert ((room) && (door));
41
42 struct GNUNET_MESSENGER_SrvTunnel *tunnel = GNUNET_new (struct
43 GNUNET_MESSENGER_SrvTunnel);
44
45 tunnel->room = room;
46 tunnel->channel = NULL;
47
48 tunnel->peer = GNUNET_PEER_intern (door);
49
50 tunnel->messenger_version = 0;
51
52 tunnel->peer_message = NULL;
53
54 init_message_state (&(tunnel->state));
55
56 return tunnel;
57}
58
59
60void
61destroy_tunnel (struct GNUNET_MESSENGER_SrvTunnel *tunnel)
62{
63 GNUNET_assert (tunnel);
64
65 if (tunnel->channel)
66 GNUNET_CADET_channel_destroy (tunnel->channel);
67
68 GNUNET_PEER_change_rc (tunnel->peer, -1);
69
70 if (tunnel->peer_message)
71 GNUNET_free (tunnel->peer_message);
72
73 clear_message_state (&(tunnel->state));
74
75 GNUNET_free (tunnel);
76}
77
78
79void
80bind_tunnel (struct GNUNET_MESSENGER_SrvTunnel *tunnel,
81 struct GNUNET_CADET_Channel *channel)
82{
83 GNUNET_assert (tunnel);
84
85 if (tunnel->channel)
86 delayed_disconnect_channel (tunnel->channel);
87
88 tunnel->channel = channel;
89}
90
91
92extern void
93callback_room_disconnect (struct GNUNET_MESSENGER_SrvRoom *room,
94 void *cls);
95
96void
97callback_tunnel_disconnect (void *cls,
98 const struct GNUNET_CADET_Channel *channel)
99{
100 struct GNUNET_MESSENGER_SrvTunnel *tunnel = cls;
101
102 if (tunnel)
103 {
104 tunnel->channel = NULL;
105
106 callback_room_disconnect (tunnel->room, cls);
107 }
108}
109
110
111extern enum GNUNET_GenericReturnValue
112callback_verify_room_message (struct GNUNET_MESSENGER_SrvRoom *room,
113 void *cls,
114 struct GNUNET_MESSENGER_Message *message,
115 struct GNUNET_HashCode *hash);
116
117enum GNUNET_GenericReturnValue
118check_tunnel_message (void *cls,
119 const struct GNUNET_MessageHeader *header)
120{
121 struct GNUNET_MESSENGER_SrvTunnel *tunnel = cls;
122
123 if (! tunnel)
124 return GNUNET_SYSERR;
125
126 const uint16_t length = ntohs (header->size) - sizeof(*header);
127 const char *buffer = (const char*) &header[1];
128
129 struct GNUNET_MESSENGER_Message message;
130
131 if (length < get_message_kind_size (GNUNET_MESSENGER_KIND_UNKNOWN,
132 GNUNET_YES))
133 {
134 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
135 "Tunnel error: Message too short! (%d)\n", length);
136 return GNUNET_SYSERR;
137 }
138
139 uint16_t padding = 0;
140
141 if (GNUNET_YES != decode_message (&message, length, buffer, GNUNET_YES,
142 &padding))
143 {
144 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Tunnel error: Decoding failed!\n");
145 return GNUNET_SYSERR;
146 }
147
148 struct GNUNET_HashCode hash;
149 hash_message (&message, length - padding, buffer, &hash);
150
151 return callback_verify_room_message (tunnel->room, cls, &message, &hash);
152}
153
154
155extern enum GNUNET_GenericReturnValue
156update_room_message (struct GNUNET_MESSENGER_SrvRoom *room,
157 struct GNUNET_MESSENGER_Message *message,
158 const struct GNUNET_HashCode *hash);
159
160extern void
161callback_room_handle_message (struct GNUNET_MESSENGER_SrvRoom *room,
162 const struct GNUNET_MESSENGER_Message *message,
163 const struct GNUNET_HashCode *hash);
164
165static void
166update_tunnel_last_message (struct GNUNET_MESSENGER_SrvTunnel *tunnel,
167 const struct GNUNET_HashCode *hash)
168{
169 struct GNUNET_MESSENGER_OperationStore *operation_store =
170 get_srv_room_operation_store (tunnel->room);
171
172 enum GNUNET_GenericReturnValue requested;
173 requested = (GNUNET_MESSENGER_OP_REQUEST ==
174 get_store_operation_type (operation_store, hash)?
175 GNUNET_YES : GNUNET_NO);
176
177 struct GNUNET_MESSENGER_MessageStore *message_store =
178 get_srv_room_message_store (tunnel->room);
179
180 const struct GNUNET_MESSENGER_Message *message = get_store_message (
181 message_store, hash);
182
183 if (message)
184 update_message_state (&(tunnel->state), requested, message, hash);
185}
186
187
188void
189handle_tunnel_message (void *cls, const struct GNUNET_MessageHeader *header)
190{
191 struct GNUNET_MESSENGER_SrvTunnel *tunnel = cls;
192
193 if (! tunnel)
194 return;
195
196 const uint16_t length = ntohs (header->size) - sizeof(*header);
197 const char *buffer = (const char*) &header[1];
198
199 struct GNUNET_MESSENGER_Message message;
200 struct GNUNET_HashCode hash;
201
202 uint16_t padding = 0;
203
204 decode_message (&message, length, buffer, GNUNET_YES, &padding);
205 hash_message (&message, length - padding, buffer, &hash);
206
207 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got message of kind: %s!\n",
208 GNUNET_MESSENGER_name_of_kind (message.header.kind));
209
210 enum GNUNET_GenericReturnValue new_message;
211 new_message = update_room_message (tunnel->room,
212 copy_message (&message),
213 &hash);
214
215 if (GNUNET_YES != new_message)
216 goto receive_done;
217
218 update_tunnel_last_message (tunnel, &hash);
219
220 enum GNUNET_GenericReturnValue forward_message = GNUNET_YES;
221
222 switch (message.header.kind)
223 {
224 case GNUNET_MESSENGER_KIND_INFO:
225 forward_message = recv_message_info (tunnel->room, tunnel, &message, &hash);
226 break;
227 case GNUNET_MESSENGER_KIND_PEER:
228 forward_message = recv_message_peer (tunnel->room, tunnel, &message, &hash);
229 break;
230 case GNUNET_MESSENGER_KIND_MISS:
231 forward_message = recv_message_miss (tunnel->room, tunnel, &message, &hash);
232 break;
233 case GNUNET_MESSENGER_KIND_REQUEST:
234 forward_message = recv_message_request (tunnel->room, tunnel, &message,
235 &hash);
236 break;
237 default:
238 break;
239 }
240
241 if (GNUNET_YES == forward_message)
242 {
243 forward_srv_room_message (tunnel->room, tunnel, &message, &hash);
244 callback_room_handle_message (tunnel->room, &message, &hash);
245 }
246
247receive_done:
248 cleanup_message (&message);
249
250 GNUNET_CADET_receive_done (tunnel->channel);
251}
252
253
254enum GNUNET_GenericReturnValue
255connect_tunnel (struct GNUNET_MESSENGER_SrvTunnel *tunnel)
256{
257 GNUNET_assert (tunnel);
258
259 if (tunnel->channel)
260 return GNUNET_NO;
261
262 const struct GNUNET_PeerIdentity *door = GNUNET_PEER_resolve2 (tunnel->peer);
263
264 struct GNUNET_CADET_Handle *cadet = get_srv_room_cadet (tunnel->room);
265 const struct GNUNET_HashCode *key = get_srv_room_key (tunnel->room);
266
267 struct GNUNET_MQ_MessageHandler handlers[] = { GNUNET_MQ_hd_var_size (
268 tunnel_message,
269 GNUNET_MESSAGE_TYPE_CADET_CLI,
270 struct
271 GNUNET_MessageHeader, NULL),
272 GNUNET_MQ_handler_end () };
273
274 struct GNUNET_HashCode port;
275 convert_messenger_key_to_port (key, &port);
276 tunnel->channel = GNUNET_CADET_channel_create (cadet, tunnel, door, &port,
277 NULL,
278 callback_tunnel_disconnect,
279 handlers);
280
281 return GNUNET_YES;
282}
283
284
285void
286disconnect_tunnel (struct GNUNET_MESSENGER_SrvTunnel *tunnel)
287{
288 GNUNET_assert (tunnel);
289
290 if (tunnel->channel)
291 {
292 delayed_disconnect_channel (tunnel->channel);
293
294 tunnel->channel = NULL;
295 }
296}
297
298
299enum GNUNET_GenericReturnValue
300is_tunnel_connected (const struct GNUNET_MESSENGER_SrvTunnel *tunnel)
301{
302 GNUNET_assert (tunnel);
303
304 return (tunnel->channel ? GNUNET_YES : GNUNET_NO);
305}
306
307
308struct GNUNET_MESSENGER_MessageSent
309{
310 struct GNUNET_MESSENGER_SrvTunnel *tunnel;
311 struct GNUNET_HashCode hash;
312};
313
314static void
315callback_tunnel_sent (void *cls)
316{
317 struct GNUNET_MESSENGER_MessageSent *sent = cls;
318
319 if (sent->tunnel)
320 update_tunnel_last_message (sent->tunnel, &(sent->hash));
321
322 GNUNET_free (sent);
323}
324
325
326void
327send_tunnel_envelope (struct GNUNET_MESSENGER_SrvTunnel *tunnel,
328 struct GNUNET_MQ_Envelope *env,
329 const struct GNUNET_HashCode *hash)
330{
331 GNUNET_assert ((tunnel) && (env) && (hash));
332
333 struct GNUNET_MQ_Handle *mq = GNUNET_CADET_get_mq (tunnel->channel);
334
335 struct GNUNET_MESSENGER_MessageSent *sent = GNUNET_new (struct
336 GNUNET_MESSENGER_MessageSent);
337
338 GNUNET_memcpy (&(sent->hash), hash, sizeof(struct GNUNET_HashCode));
339
340 sent->tunnel = tunnel;
341
342 GNUNET_MQ_notify_sent (env, callback_tunnel_sent, sent);
343 GNUNET_MQ_send (mq, env);
344}
345
346
347enum GNUNET_GenericReturnValue
348send_tunnel_message (struct GNUNET_MESSENGER_SrvTunnel *tunnel,
349 void *handle,
350 struct GNUNET_MESSENGER_Message *message)
351{
352 GNUNET_assert ((tunnel) && (handle));
353
354 if (! message)
355 return GNUNET_NO;
356
357 struct GNUNET_HashCode hash;
358 struct GNUNET_MQ_Envelope *env = pack_srv_room_message (
359 tunnel->room, (struct GNUNET_MESSENGER_SrvHandle*) handle,
360 message, &hash, GNUNET_MESSENGER_PACK_MODE_ENVELOPE
361 );
362
363 destroy_message (message);
364
365 if (! env)
366 return GNUNET_NO;
367
368 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending tunnel message: %s\n",
369 GNUNET_h2s (&hash));
370
371 send_tunnel_envelope (tunnel, env, &hash);
372 return GNUNET_YES;
373}
374
375
376void
377forward_tunnel_message (struct GNUNET_MESSENGER_SrvTunnel *tunnel,
378 const struct GNUNET_MESSENGER_Message *message,
379 const struct GNUNET_HashCode *hash)
380{
381 GNUNET_assert ((tunnel) && (message) && (hash));
382
383 struct GNUNET_MESSENGER_Message *copy = copy_message (message);
384 struct GNUNET_MQ_Envelope *env = pack_message (copy, NULL, NULL,
385 GNUNET_MESSENGER_PACK_MODE_ENVELOPE,
386 NULL);
387
388 destroy_message (copy);
389
390 if (! env)
391 return;
392
393 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Forwarding tunnel message: %s\n",
394 GNUNET_h2s (hash));
395
396 send_tunnel_envelope (tunnel, env, hash);
397}
398
399
400const struct GNUNET_HashCode*
401get_tunnel_peer_message (const struct GNUNET_MESSENGER_SrvTunnel *tunnel)
402{
403 GNUNET_assert (tunnel);
404
405 return tunnel->peer_message;
406}
407
408
409void
410get_tunnel_peer_identity (const struct GNUNET_MESSENGER_SrvTunnel *tunnel,
411 struct GNUNET_PeerIdentity *peer)
412{
413 GNUNET_assert (tunnel);
414
415 GNUNET_PEER_resolve (tunnel->peer, peer);
416}
417
418
419uint32_t
420get_tunnel_messenger_version (const struct GNUNET_MESSENGER_SrvTunnel *tunnel)
421{
422 GNUNET_assert (tunnel);
423
424 return tunnel->messenger_version;
425}
426
427
428enum GNUNET_GenericReturnValue
429update_tunnel_messenger_version (struct GNUNET_MESSENGER_SrvTunnel *tunnel,
430 uint32_t version)
431{
432 GNUNET_assert (tunnel);
433
434 if (version != GNUNET_MESSENGER_VERSION)
435 return GNUNET_SYSERR;
436
437 if (version > tunnel->messenger_version)
438 tunnel->messenger_version = version;
439
440 return GNUNET_OK;
441}
diff --git a/src/service/messenger/gnunet-service-messenger_tunnel.h b/src/service/messenger/gnunet-service-messenger_tunnel.h
new file mode 100644
index 000000000..6a8452f61
--- /dev/null
+++ b/src/service/messenger/gnunet-service-messenger_tunnel.h
@@ -0,0 +1,193 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2023 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_tunnel.h
23 * @brief GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_SERVICE_MESSENGER_TUNNEL_H
27#define GNUNET_SERVICE_MESSENGER_TUNNEL_H
28
29#include "gnunet_cadet_service.h"
30#include "gnunet_util_lib.h"
31
32#include "gnunet-service-messenger_room.h"
33#include "gnunet-service-messenger_message_state.h"
34
35struct GNUNET_MESSENGER_SrvTunnel
36{
37 struct GNUNET_MESSENGER_SrvRoom *room;
38 struct GNUNET_CADET_Channel *channel;
39
40 GNUNET_PEER_Id peer;
41
42 uint32_t messenger_version;
43
44 struct GNUNET_HashCode *peer_message;
45 struct GNUNET_MESSENGER_MessageState state;
46};
47
48/**
49 * Creates and allocates a tunnel of a <i>room</i> to a specific peer identity (called <i>door</i>).
50 *
51 * @param[in,out] room Room
52 * @param[in] door Peer identity
53 * @return New tunnel
54 */
55struct GNUNET_MESSENGER_SrvTunnel*
56create_tunnel (struct GNUNET_MESSENGER_SrvRoom *room,
57 const struct GNUNET_PeerIdentity *door);
58
59/**
60 * Destroys a <i>tunnel</i> and frees its memory fully.
61 *
62 * @param[in,out] tunnel
63 */
64void
65destroy_tunnel (struct GNUNET_MESSENGER_SrvTunnel *tunnel);
66
67/**
68 * Binds a CADET <i>channel</i> to a <i>tunnel</i> and replaces its channel
69 * the tunnel is currently bound to if necessary.
70 *
71 * @param[in,out] tunnel Tunnel
72 * @param[in,out] channel CADET channel
73 */
74void
75bind_tunnel (struct GNUNET_MESSENGER_SrvTunnel *tunnel,
76 struct GNUNET_CADET_Channel *channel);
77
78/**
79 * Tries to connect a <i>tunnel</i> by creating a new CADET channel and binding it.
80 * The function returns #GNUNET_YES on success, otherwise #GNUNET_NO.
81 *
82 * @param[in,out] tunnel Tunnel
83 * @return #GNUNET_YES on success, otherwise #GNUNET_NO
84 */
85enum GNUNET_GenericReturnValue
86connect_tunnel (struct GNUNET_MESSENGER_SrvTunnel *tunnel);
87
88/**
89 * Disconnects and unbinds a channel from a <i>tunnel</i>. The actual disconnection
90 * will be asynchronous.
91 *
92 * @param[in,out] tunnel Tunnel
93 */
94void
95disconnect_tunnel (struct GNUNET_MESSENGER_SrvTunnel *tunnel);
96
97/**
98 * Returns the status of a currently bound channel of a <i>tunnel</i>.
99 *
100 * @param[in] tunnel Tunnel
101 * @return #GNUNET_YES or #GNUNET_NO
102 */
103enum GNUNET_GenericReturnValue
104is_tunnel_connected (const struct GNUNET_MESSENGER_SrvTunnel *tunnel);
105
106/**
107 * Sends an envelope containing a <i>message</i> with a given <i>hash</i> through
108 * a <i>tunnel</i>.
109 *
110 * @param[in,out] tunnel Tunnel
111 * @param[in,out] env Envelope
112 * @param[in] hash Hash of message
113 */
114void
115send_tunnel_envelope (struct GNUNET_MESSENGER_SrvTunnel *tunnel,
116 struct GNUNET_MQ_Envelope *env,
117 const struct GNUNET_HashCode *hash);
118
119/**
120 * Sends a <i>message</i> by packing it automatically into an envelope and passing it
121 * through the <i>tunnel</i>. The used <i>handle</i> will sign the message and
122 * the <i>hash</i> will be calculated and stored.
123 *
124 * @param[in,out] tunnel Tunnel
125 * @param[in,out] handle Handle
126 * @param[in,out] message Message
127 * @return #GNUNET_YES on success, GNUNET_NO otherwise
128 */
129enum GNUNET_GenericReturnValue
130send_tunnel_message (struct GNUNET_MESSENGER_SrvTunnel *tunnel,
131 void *handle,
132 struct GNUNET_MESSENGER_Message *message);
133
134/**
135 * Forwards a given <i>message</i> with a known <i>hash</i> through a <i>tunnel</i>.
136 *
137 * @param[in,out] tunnel Tunnel
138 * @param[in] message Message
139 * @param[in] hash Hash of message
140 */
141void
142forward_tunnel_message (struct GNUNET_MESSENGER_SrvTunnel *tunnel,
143 const struct GNUNET_MESSENGER_Message *message,
144 const struct GNUNET_HashCode *hash);
145
146/**
147 * Returns the hash of the latest peer message published through a given <i>tunnel</i>
148 * and matching the tunnels peer identity. If no peer message has been linked to the tunnel
149 * yet, NULL gets returned.
150 *
151 * @param[in] tunnel Tunnel
152 * @return Hash of peer message or NULL
153 */
154const struct GNUNET_HashCode*
155get_tunnel_peer_message (const struct GNUNET_MESSENGER_SrvTunnel *tunnel);
156
157/**
158 * Writes the peer identity of the peer connected via <i>tunnel</i> to this peer into
159 * the <i>peer</i> parameter.
160 *
161 * @param[in] tunnel Tunnel
162 * @param[out] peer Peer identity
163 */
164void
165get_tunnel_peer_identity (const struct GNUNET_MESSENGER_SrvTunnel *tunnel,
166 struct GNUNET_PeerIdentity *peer);
167
168/**
169 * Returns the current messenger version the peer connected via a given <i>tunnel</i>
170 * has reported to be using if it was compatible during updating.
171 *
172 * @see update_tunnel_messenger_version
173 *
174 * @param[in] tunnel Tunnel
175 * @return Version of messenger
176 */
177uint32_t
178get_tunnel_messenger_version (const struct GNUNET_MESSENGER_SrvTunnel *tunnel);
179
180/**
181 * Updates the messenger version of the <i>tunnel</i> to a given <i>version</i> if
182 * it is compatible to the running peer of the service. Depending on success it
183 * returns #GNUNET_OK or #GNUNET_SYSERR on failure.
184 *
185 * @param[in,out] tunnel Tunnel
186 * @param[in] version Version of messenger
187 * @result #GNUNET_OK on success, otherwise #GNUNET_SYSERR
188 */
189enum GNUNET_GenericReturnValue
190update_tunnel_messenger_version (struct GNUNET_MESSENGER_SrvTunnel *tunnel,
191 uint32_t version);
192
193#endif //GNUNET_SERVICE_MESSENGER_TUNNEL_H
diff --git a/src/service/messenger/meson.build b/src/service/messenger/meson.build
new file mode 100644
index 000000000..4a472b6b5
--- /dev/null
+++ b/src/service/messenger/meson.build
@@ -0,0 +1,70 @@
1libgnunetmessenger_src = ['messenger_api.c',
2 'messenger_api_contact.c',
3 'messenger_api_contact_store.c',
4 'messenger_api_message.c',
5 'messenger_api_message_control.c',
6 'messenger_api_message_kind.c',
7 'messenger_api_list_tunnels.c',
8 'messenger_api_queue_messages.c',
9 'messenger_api_util.c',
10 'messenger_api_handle.c',
11 'messenger_api_room.c']
12
13gnunetservicemessenger_src = ['gnunet-service-messenger.c',
14 'gnunet-service-messenger_service.c',
15 'gnunet-service-messenger_list_handles.c',
16 'gnunet-service-messenger_list_messages.c',
17 'gnunet-service-messenger_member_session.c',
18 'gnunet-service-messenger_member.c',
19 'gnunet-service-messenger_member_store.c',
20 'gnunet-service-messenger_message_handle.c',
21 'gnunet-service-messenger_message_kind.c',
22 'gnunet-service-messenger_message_recv.c',
23 'gnunet-service-messenger_message_send.c',
24 'gnunet-service-messenger_message_state.c',
25 'gnunet-service-messenger_message_store.c',
26 'gnunet-service-messenger_operation_store.c',
27 'gnunet-service-messenger_operation.c',
28 'gnunet-service-messenger_peer_store.c',
29 'gnunet-service-messenger_basement.c',
30 'gnunet-service-messenger_handle.c',
31 'gnunet-service-messenger_room.c',
32 'gnunet-service-messenger_tunnel.c']
33
34configure_file(input : 'messenger.conf.in',
35 output : 'messenger.conf',
36 configuration : cdata,
37 install: true,
38 install_dir: pkgcfgdir)
39
40
41if get_option('monolith')
42 foreach p : libgnunetmessenger_src + gnunetservicemessenger_src
43 gnunet_src += 'messenger/' + p
44 endforeach
45endif
46
47libgnunetmessenger = library('gnunetmessenger',
48 libgnunetmessenger_src,
49 soversion: '0',
50 version: '0.0.0',
51 dependencies: [libgnunetutil_dep,
52 libgnunetcadet_dep,
53 libgnunetidentity_dep],
54 include_directories: [incdir, configuration_inc],
55 install: true,
56 install_dir: get_option('libdir'))
57libgnunetmessenger_dep = declare_dependency(link_with : libgnunetmessenger)
58pkg.generate(libgnunetmessenger, url: 'https://www.gnunet.org',
59 description : 'Provides API to access the GNUnet Messenger subsystem')
60
61executable ('gnunet-service-messenger',
62 gnunetservicemessenger_src,
63 dependencies: [libgnunetmessenger_dep,
64 libgnunetutil_dep,
65 libgnunetidentity_dep,
66 libgnunetcadet_dep],
67 include_directories: [incdir, configuration_inc],
68 install: true,
69 install_dir: get_option('libdir') / 'gnunet' / 'libexec')
70
diff --git a/src/service/messenger/messenger-testing-cmds.h b/src/service/messenger/messenger-testing-cmds.h
new file mode 100644
index 000000000..222633355
--- /dev/null
+++ b/src/service/messenger/messenger-testing-cmds.h
@@ -0,0 +1,103 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2023 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file messenger-testing-cmds.h
23 * @brief testing lib for messenger service
24 * @author Tobias Frisch
25 */
26#ifndef MESSENGER_TESTING_CMDS_H
27#define MESSENGER_TESTING_CMDS_H
28
29#include "gnunet_testing_ng_lib.h"
30#include "gnunet_testing_plugin.h"
31
32#include "messenger-testing.h"
33
34struct GNUNET_TESTING_Command
35GNUNET_MESSENGER_cmd_start_service (const char *label,
36 const char *peer_label,
37 const char *system_label,
38 struct GNUNET_MESSENGER_TestStageTopology *
39 topology,
40 unsigned int peer_index);
41
42
43struct GNUNET_TESTING_Command
44GNUNET_MESSENGER_cmd_stop_service (const char *label,
45 const char *service_label);
46
47struct GNUNET_TESTING_Command
48GNUNET_MESSENGER_cmd_join_room (const char *label,
49 const char *service_label,
50 const char *room_key);
51
52/**
53 * Create headers for a trait with name @a name for
54 * statically allocated data of type @a type.
55 */
56#define GNUNET_MESSENGER_MAKE_DECL_SIMPLE_TRAIT(name,type) \
57 enum GNUNET_GenericReturnValue \
58 GNUNET_MESSENGER_get_trait_ ## name ( \
59 const struct GNUNET_TESTING_Command *cmd, \
60 type **ret); \
61 struct GNUNET_TESTING_Trait \
62 GNUNET_MESSENGER_make_trait_ ## name ( \
63 type * value);
64
65
66/**
67 * Create C implementation for a trait with name @a name for statically
68 * allocated data of type @a type.
69 */
70#define GNUNET_MESSENGER_MAKE_IMPL_SIMPLE_TRAIT(name,type) \
71 enum GNUNET_GenericReturnValue \
72 GNUNET_MESSENGER_get_trait_ ## name ( \
73 const struct GNUNET_TESTING_Command *cmd, \
74 type * *ret) \
75 { \
76 if (NULL == cmd->traits) return GNUNET_SYSERR; \
77 return cmd->traits (cmd->cls, \
78 (const void **) ret, \
79 GNUNET_S (name), \
80 0); \
81 } \
82 struct GNUNET_TESTING_Trait \
83 GNUNET_MESSENGER_make_trait_ ## name ( \
84 type * value) \
85 { \
86 struct GNUNET_TESTING_Trait ret = { \
87 .trait_name = GNUNET_S (name), \
88 .ptr = (const void *) value \
89 }; \
90 return ret; \
91 }
92
93
94/**
95 * Call #op on all simple traits.
96 */
97#define GNUNET_MESSENGER_SIMPLE_TRAITS(op) \
98 op (state, struct GNUNET_MESSENGER_StartServiceState)
99
100GNUNET_MESSENGER_SIMPLE_TRAITS (GNUNET_MESSENGER_MAKE_DECL_SIMPLE_TRAIT)
101
102#endif
103/* end of messenger-testing-cmds.h */
diff --git a/src/service/messenger/messenger-testing.c b/src/service/messenger/messenger-testing.c
new file mode 100644
index 000000000..b3f7e3137
--- /dev/null
+++ b/src/service/messenger/messenger-testing.c
@@ -0,0 +1,114 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2023 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file messenger-testing.c
23 * @brief testing lib for messenger service
24 * @author Tobias Frisch
25 */
26
27#include "messenger-testing.h"
28
29#include "gnunet_util_lib.h"
30
31struct GNUNET_MESSENGER_TestStage
32GNUNET_MESSENGER_create_stage_skip ()
33{
34 struct GNUNET_MESSENGER_TestStage stage;
35 stage.door_id = 0;
36 stage.join = GNUNET_MESSENGER_STAGE_JOIN_NONE;
37 return stage;
38}
39
40
41struct GNUNET_MESSENGER_TestStage
42GNUNET_MESSENGER_create_stage_open_room ()
43{
44 struct GNUNET_MESSENGER_TestStage stage;
45 stage.door_id = 0;
46 stage.join = GNUNET_MESSENGER_STAGE_JOIN_OPEN_ROOM;
47 return stage;
48}
49
50
51struct GNUNET_MESSENGER_TestStage
52GNUNET_MESSENGER_create_stage_enter_room (uint32_t door_id)
53{
54 struct GNUNET_MESSENGER_TestStage stage;
55 stage.door_id = door_id;
56 stage.join = GNUNET_MESSENGER_STAGE_JOIN_ENTER_ROOM;
57 return stage;
58}
59
60
61struct GNUNET_MESSENGER_TestStageTopology *
62GNUNET_MESSENGER_create_topo (unsigned int peer_amount,
63 unsigned int stage_amount,
64 const struct GNUNET_MESSENGER_TestStage
65 peer_stages[static peer_amount * stage_amount])
66{
67 GNUNET_assert ((peer_amount) && (stage_amount) && (peer_stages));
68
69 struct GNUNET_MESSENGER_TestStageTopology *tp;
70 tp = GNUNET_new (struct GNUNET_MESSENGER_TestStageTopology);
71 tp->peer_amount = peer_amount;
72 tp->stage_amount = stage_amount;
73
74 const unsigned int size = tp->peer_amount * tp->stage_amount;
75 tp->peer_stages = GNUNET_new_array (size, struct GNUNET_MESSENGER_TestStage);
76
77 for (unsigned int i = 0; i < size; i++)
78 tp->peer_stages[i] = peer_stages[i];
79
80 return tp;
81}
82
83
84void
85GNUNET_MESSENGER_destroy_topo (struct
86 GNUNET_MESSENGER_TestStageTopology *topology)
87{
88 GNUNET_assert ((topology) && (topology->peer_stages));
89 GNUNET_free (topology->peer_stages);
90 GNUNET_free (topology);
91}
92
93
94struct GNUNET_MESSENGER_RoomState *
95GNUNET_MESSENGER_create_room_state (struct
96 GNUNET_MESSENGER_TestStageTopology *topology)
97{
98 struct GNUNET_MESSENGER_RoomState *rs;
99 rs = GNUNET_new (struct GNUNET_MESSENGER_RoomState);
100 rs->doors = GNUNET_CONTAINER_multipeermap_create (topology->peer_amount,
101 GNUNET_NO);
102 rs->required_doors = 0;
103 return rs;
104}
105
106
107void
108GNUNET_MESSENGER_destroy_room_state (struct
109 GNUNET_MESSENGER_RoomState *room_state)
110{
111 GNUNET_assert ((room_state) && (room_state->doors));
112 GNUNET_CONTAINER_multipeermap_destroy (room_state->doors);
113 GNUNET_free (room_state);
114}
diff --git a/src/service/messenger/messenger-testing.h b/src/service/messenger/messenger-testing.h
new file mode 100644
index 000000000..850c37243
--- /dev/null
+++ b/src/service/messenger/messenger-testing.h
@@ -0,0 +1,102 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2023 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file messenger-testing.h
23 * @brief testing lib for messenger service
24 * @author Tobias Frisch
25 */
26
27#ifndef MESSENGER_TESTING_H
28#define MESSENGER_TESTING_H
29
30enum GNUNET_MESSENGER_TestStageJoin
31{
32 GNUNET_MESSENGER_STAGE_JOIN_NONE = 0x0,
33 GNUNET_MESSENGER_STAGE_JOIN_OPEN_ROOM = 0x1,
34 GNUNET_MESSENGER_STAGE_JOIN_ENTER_ROOM = 0x2,
35};
36
37struct GNUNET_MESSENGER_TestStage
38{
39 unsigned int door_id;
40 enum GNUNET_MESSENGER_TestStageJoin join;
41};
42
43struct GNUNET_MESSENGER_TestStage
44GNUNET_MESSENGER_create_stage_skip ();
45
46struct GNUNET_MESSENGER_TestStage
47GNUNET_MESSENGER_create_stage_open_room ();
48
49struct GNUNET_MESSENGER_TestStage
50GNUNET_MESSENGER_create_stage_enter_room (unsigned int door_id);
51
52struct GNUNET_MESSENGER_TestStageTopology
53{
54 unsigned int peer_amount;
55 unsigned int stage_amount;
56
57 struct GNUNET_MESSENGER_TestStage *peer_stages;
58};
59
60struct GNUNET_MESSENGER_TestStageTopology *
61GNUNET_MESSENGER_create_topo (unsigned int peer_amount,
62 unsigned int stage_amount,
63 const struct GNUNET_MESSENGER_TestStage
64 peer_stages[static peer_amount * stage_amount]);
65
66void
67GNUNET_MESSENGER_destroy_topo (struct
68 GNUNET_MESSENGER_TestStageTopology *topology);
69
70struct GNUNET_MESSENGER_RoomState
71{
72 struct GNUNET_CONTAINER_MultiPeerMap *doors;
73
74 unsigned int required_doors;
75};
76
77struct GNUNET_MESSENGER_RoomState *
78GNUNET_MESSENGER_create_room_state (struct
79 GNUNET_MESSENGER_TestStageTopology *topology);
80
81void
82GNUNET_MESSENGER_destroy_room_state (struct
83 GNUNET_MESSENGER_RoomState *room_state);
84
85struct GNUNET_MESSENGER_StartServiceState
86{
87 char *peer_label;
88 char *system_label;
89
90 struct GNUNET_MESSENGER_TestStageTopology *topology;
91
92 struct GNUNET_TESTING_Interpreter *is;
93 const struct GNUNET_TESTING_System *tl_system;
94 struct GNUNET_MESSENGER_Handle *msg;
95 struct GNUNET_CONTAINER_MultiHashMap *rooms;
96
97 unsigned int peer_index;
98 unsigned int stage_index;
99};
100
101#endif
102/* end of messenger-testing.h */
diff --git a/src/service/messenger/messenger.conf.in b/src/service/messenger/messenger.conf.in
new file mode 100644
index 000000000..6e29dea44
--- /dev/null
+++ b/src/service/messenger/messenger.conf.in
@@ -0,0 +1,17 @@
1[messenger]
2START_ON_DEMAND = @START_ON_DEMAND@
3RUN_PER_USER = YES
4@JAVAPORT@PORT = 2125
5HOSTNAME = localhost
6BINARY = gnunet-service-messenger
7ACCEPT_FROM = 127.0.0.1;
8ACCEPT_FROM6 = ::1;
9UNIXPATH = $GNUNET_USER_RUNTIME_DIR/gnunet-service-messenger.sock
10UNIX_MATCH_UID = NO
11UNIX_MATCH_GID = YES
12
13# Directory to store messages and contacts
14MESSENGER_DIR = $GNUNET_DATA_HOME/messenger/
15MESSENGER_AUTO_CONNECTING = YES
16MESSENGER_AUTO_ROUTING = YES
17MESSENGER_MIN_ROUTERS = 3 \ No newline at end of file
diff --git a/src/service/messenger/messenger_api.c b/src/service/messenger/messenger_api.c
new file mode 100644
index 000000000..12a326202
--- /dev/null
+++ b/src/service/messenger/messenger_api.c
@@ -0,0 +1,1263 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/messenger_api.c
23 * @brief messenger api: client implementation of GNUnet MESSENGER service
24 */
25
26#include "gnunet_common.h"
27#include "gnunet_messenger_service.h"
28
29#include "gnunet-service-messenger.h"
30
31#include "gnunet_reclaim_service.h"
32#include "gnunet_time_lib.h"
33#include "messenger_api_contact.h"
34#include "messenger_api_contact_store.h"
35#include "messenger_api_handle.h"
36#include "messenger_api_message.h"
37#include "messenger_api_message_control.h"
38#include "messenger_api_message_kind.h"
39#include "messenger_api_room.h"
40#include "messenger_api_util.h"
41
42const char*
43GNUNET_MESSENGER_name_of_kind (enum GNUNET_MESSENGER_MessageKind kind)
44{
45 switch (kind)
46 {
47 case GNUNET_MESSENGER_KIND_INFO:
48 return "INFO";
49 case GNUNET_MESSENGER_KIND_JOIN:
50 return "JOIN";
51 case GNUNET_MESSENGER_KIND_LEAVE:
52 return "LEAVE";
53 case GNUNET_MESSENGER_KIND_NAME:
54 return "NAME";
55 case GNUNET_MESSENGER_KIND_KEY:
56 return "KEY";
57 case GNUNET_MESSENGER_KIND_PEER:
58 return "PEER";
59 case GNUNET_MESSENGER_KIND_ID:
60 return "ID";
61 case GNUNET_MESSENGER_KIND_MISS:
62 return "MISS";
63 case GNUNET_MESSENGER_KIND_MERGE:
64 return "MERGE";
65 case GNUNET_MESSENGER_KIND_REQUEST:
66 return "REQUEST";
67 case GNUNET_MESSENGER_KIND_INVITE:
68 return "INVITE";
69 case GNUNET_MESSENGER_KIND_TEXT:
70 return "TEXT";
71 case GNUNET_MESSENGER_KIND_FILE:
72 return "FILE";
73 case GNUNET_MESSENGER_KIND_PRIVATE:
74 return "PRIVATE";
75 case GNUNET_MESSENGER_KIND_DELETE:
76 return "DELETE";
77 case GNUNET_MESSENGER_KIND_CONNECTION:
78 return "CONNECTION";
79 case GNUNET_MESSENGER_KIND_TICKET:
80 return "TICKET";
81 case GNUNET_MESSENGER_KIND_TRANSCRIPT:
82 return "TRANSCRIPT";
83 case GNUNET_MESSENGER_KIND_TAG:
84 return "TAG";
85 default:
86 return "UNKNOWN";
87 }
88}
89
90
91static enum GNUNET_GenericReturnValue
92dequeue_messages_from_room (struct GNUNET_MESSENGER_Room *room);
93
94static void
95handle_room_open (void *cls,
96 const struct GNUNET_MESSENGER_RoomMessage *msg)
97{
98 struct GNUNET_MESSENGER_Handle *handle = cls;
99
100 const struct GNUNET_HashCode *key = &(msg->key);
101 const struct GNUNET_HashCode *prev = &(msg->previous);
102
103 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Opened room: %s\n", GNUNET_h2s (key));
104
105 open_handle_room (handle, key);
106
107 struct GNUNET_MESSENGER_Room *room = get_handle_room (handle, key);
108
109 if (! room)
110 return;
111
112 update_room_last_message (room, prev);
113
114 dequeue_messages_from_room (room);
115}
116
117
118static void
119handle_room_entry (void *cls,
120 const struct GNUNET_MESSENGER_RoomMessage *msg)
121{
122 struct GNUNET_MESSENGER_Handle *handle = cls;
123
124 const struct GNUNET_PeerIdentity *door = &(msg->door);
125 const struct GNUNET_HashCode *key = &(msg->key);
126 const struct GNUNET_HashCode *prev = &(msg->previous);
127
128 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Entered room: %s\n", GNUNET_h2s (key));
129
130 entry_handle_room_at (handle, door, key);
131
132 struct GNUNET_MESSENGER_Room *room = get_handle_room (handle, key);
133
134 if (! room)
135 return;
136
137 update_room_last_message (room, prev);
138
139 dequeue_messages_from_room (room);
140}
141
142
143static void
144handle_room_close (void *cls,
145 const struct GNUNET_MESSENGER_RoomMessage *msg)
146{
147 struct GNUNET_MESSENGER_Handle *handle = cls;
148
149 const struct GNUNET_HashCode *key = &(msg->key);
150 const struct GNUNET_HashCode *prev = &(msg->previous);
151
152 struct GNUNET_MESSENGER_Room *room = get_handle_room (handle, key);
153
154 if (room)
155 update_room_last_message (room, prev);
156
157 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Closed room: %s\n", GNUNET_h2s (key));
158
159 close_handle_room (handle, key);
160}
161
162
163static void
164handle_room_sync (void *cls,
165 const struct GNUNET_MESSENGER_RoomMessage *msg)
166{
167 struct GNUNET_MESSENGER_Handle *handle = cls;
168
169 const struct GNUNET_HashCode *key = &(msg->key);
170 const struct GNUNET_HashCode *prev = &(msg->previous);
171
172 struct GNUNET_MESSENGER_Room *room = get_handle_room (handle, key);
173
174 if (! room)
175 return;
176
177 update_room_last_message (room, prev);
178
179 room->wait_for_sync = GNUNET_NO;
180
181 dequeue_messages_from_room (room);
182}
183
184
185static void
186enqueue_message_to_room (struct GNUNET_MESSENGER_Room *room,
187 struct GNUNET_MESSENGER_Message *message,
188 struct GNUNET_MESSENGER_Message *transcript);
189
190static void
191handle_member_id (void *cls,
192 const struct GNUNET_MESSENGER_MemberMessage *msg)
193{
194 struct GNUNET_MESSENGER_Handle *handle = cls;
195
196 const struct GNUNET_HashCode *key = &(msg->key);
197 const struct GNUNET_ShortHashCode *id = &(msg->id);
198 const uint32_t reset = msg->reset;
199
200 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Changed member id in room: %s\n",
201 GNUNET_h2s (key));
202
203 struct GNUNET_MESSENGER_Room *room = get_handle_room (handle, key);
204
205 if (! room)
206 {
207 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Room is unknown to handle: %s\n",
208 GNUNET_h2s (key));
209 return;
210 }
211
212 struct GNUNET_MESSENGER_Message *message;
213 if ((! get_room_sender_id (room)) || (GNUNET_YES == reset))
214 {
215 set_room_sender_id (room, id);
216 message = create_message_join (get_handle_key (handle));
217 }
218 else
219 message = create_message_id (id);
220
221 if (! message)
222 return;
223
224 enqueue_message_to_room (room, message, NULL);
225}
226
227
228static enum GNUNET_GenericReturnValue
229check_recv_message (void *cls,
230 const struct GNUNET_MESSENGER_RecvMessage *msg)
231{
232 const uint16_t full_length = ntohs (msg->header.size);
233
234 if (full_length < sizeof(*msg))
235 {
236 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
237 "Receiving failed: Message invalid!\n");
238 return GNUNET_NO;
239 }
240
241 const uint16_t length = full_length - sizeof(*msg);
242 const char *buffer = ((const char*) msg) + sizeof(*msg);
243
244 struct GNUNET_MESSENGER_Message message;
245
246 if (length < get_message_kind_size (GNUNET_MESSENGER_KIND_UNKNOWN,
247 GNUNET_YES))
248 {
249 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
250 "Receiving failed: Message too short!\n");
251 return GNUNET_NO;
252 }
253
254 if (GNUNET_YES != decode_message (&message, length, buffer, GNUNET_YES, NULL))
255 {
256 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
257 "Receiving failed: Message decoding failed!\n");
258 return GNUNET_NO;
259 }
260
261 cleanup_message (&message);
262 return GNUNET_OK;
263}
264
265
266static void
267handle_recv_message (void *cls,
268 const struct GNUNET_MESSENGER_RecvMessage *msg)
269{
270 struct GNUNET_MESSENGER_Handle *handle = cls;
271
272 const struct GNUNET_HashCode *key = &(msg->key);
273 const struct GNUNET_HashCode *sender = &(msg->sender);
274 const struct GNUNET_HashCode *context = &(msg->context);
275 const struct GNUNET_HashCode *hash = &(msg->hash);
276
277 enum GNUNET_MESSENGER_MessageFlags flags = (
278 (enum GNUNET_MESSENGER_MessageFlags) (msg->flags));
279
280 const uint16_t length = ntohs (msg->header.size) - sizeof(*msg);
281 const char *buffer = ((const char*) msg) + sizeof(*msg);
282
283 struct GNUNET_MESSENGER_Message message;
284 decode_message (&message, length, buffer, GNUNET_YES, NULL);
285
286 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receiving message: %s\n",
287 GNUNET_MESSENGER_name_of_kind (message.header.kind));
288
289 struct GNUNET_MESSENGER_Room *room = get_handle_room (handle, key);
290
291 if (! room)
292 {
293 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Unknown room for this client: %s\n",
294 GNUNET_h2s (key));
295
296 goto skip_message;
297 }
298
299 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
300 "Raw contact from sender and context: (%s : %s)\n",
301 GNUNET_h2s (sender), GNUNET_h2s_full (context));
302
303 process_message_control (room->control,
304 sender,
305 context,
306 hash,
307 &message,
308 flags);
309
310skip_message:
311 cleanup_message (&message);
312}
313
314
315static void
316handle_miss_message (void *cls,
317 const struct GNUNET_MESSENGER_GetMessage *msg)
318{
319 struct GNUNET_MESSENGER_Handle *handle = cls;
320
321 const struct GNUNET_HashCode *key = &(msg->key);
322 const struct GNUNET_HashCode *hash = &(msg->hash);
323
324 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Missing message in room: %s\n",
325 GNUNET_h2s (hash));
326
327 struct GNUNET_MESSENGER_Room *room = get_handle_room (handle, key);
328
329 if (! room)
330 {
331 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
332 "Miss in unknown room for this client: %s\n", GNUNET_h2s (key));
333 return;
334 }
335
336 if (! get_room_sender_id (room))
337 return;
338
339 struct GNUNET_MESSENGER_Message *message = create_message_request (hash);
340 if (! message)
341 return;
342
343 enqueue_message_to_room (room, message, NULL);
344}
345
346
347static void
348reconnect (struct GNUNET_MESSENGER_Handle *handle);
349
350static void
351send_open_room (struct GNUNET_MESSENGER_Handle *handle,
352 struct GNUNET_MESSENGER_Room *room)
353{
354 const struct GNUNET_CRYPTO_PublicKey *key = get_handle_pubkey (handle);
355
356 struct GNUNET_MESSENGER_RoomMessage *msg;
357 struct GNUNET_MQ_Envelope *env;
358
359 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
360 "Open room (%s) by member using key: %s\n",
361 GNUNET_h2s (&(room->key)),
362 GNUNET_CRYPTO_public_key_to_string (key));
363
364 const ssize_t len = GNUNET_CRYPTO_public_key_get_length (key);
365
366 env = GNUNET_MQ_msg_extra (msg, len > 0 ? len : 0,
367 GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_OPEN);
368 GNUNET_memcpy (&(msg->key), &(room->key), sizeof(msg->key));
369 GNUNET_memcpy (&(msg->previous), &(room->last_message),
370 sizeof(msg->previous));
371
372 char *msg_buffer = ((char*) msg) + sizeof(*msg);
373
374 if (len > 0)
375 GNUNET_CRYPTO_write_public_key_to_buffer (key, msg_buffer, len);
376
377 GNUNET_MQ_send (handle->mq, env);
378}
379
380
381static void
382send_enter_room (struct GNUNET_MESSENGER_Handle *handle,
383 struct GNUNET_MESSENGER_Room *room,
384 const struct GNUNET_PeerIdentity *door)
385{
386 const struct GNUNET_CRYPTO_PublicKey *key = get_handle_pubkey (handle);
387
388 struct GNUNET_MESSENGER_RoomMessage *msg;
389 struct GNUNET_MQ_Envelope *env;
390
391 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Enter room (%s) via door: %s (%s)\n",
392 GNUNET_h2s (&(room->key)),
393 GNUNET_i2s (door),
394 GNUNET_CRYPTO_public_key_to_string (key));
395
396 const ssize_t len = GNUNET_CRYPTO_public_key_get_length (key);
397
398 env = GNUNET_MQ_msg_extra (msg, len > 0 ? len : 0,
399 GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_ENTRY);
400 GNUNET_memcpy (&(msg->door), door, sizeof(*door));
401 GNUNET_memcpy (&(msg->key), &(room->key), sizeof(msg->key));
402 GNUNET_memcpy (&(msg->previous), &(room->last_message),
403 sizeof(msg->previous));
404
405 char *msg_buffer = ((char*) msg) + sizeof(*msg);
406
407 if (len > 0)
408 GNUNET_CRYPTO_write_public_key_to_buffer (key, msg_buffer, len);
409
410 GNUNET_MQ_send (handle->mq, env);
411}
412
413
414static void
415send_close_room (struct GNUNET_MESSENGER_Handle *handle,
416 struct GNUNET_MESSENGER_Room *room)
417{
418 struct GNUNET_MESSENGER_RoomMessage *msg;
419 struct GNUNET_MQ_Envelope *env;
420
421 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Close room (%s)!\n",
422 GNUNET_h2s (&(room->key)));
423
424 env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_CLOSE);
425
426 GNUNET_memcpy (&(msg->key), &(room->key), sizeof(msg->key));
427 GNUNET_memcpy (&(msg->previous), &(room->last_message),
428 sizeof(msg->previous));
429
430 GNUNET_MQ_send (handle->mq, env);
431}
432
433
434static void
435send_sync_room (struct GNUNET_MESSENGER_Handle *handle,
436 struct GNUNET_MESSENGER_Room *room)
437{
438 struct GNUNET_MESSENGER_RoomMessage *msg;
439 struct GNUNET_MQ_Envelope *env;
440
441 room->wait_for_sync = GNUNET_YES;
442
443 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sync room (%s)!\n",
444 GNUNET_h2s (&(room->key)));
445
446 env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_SYNC);
447
448 GNUNET_memcpy (&(msg->key), &(room->key), sizeof(msg->key));
449 GNUNET_memcpy (&(msg->previous), &(room->last_message),
450 sizeof(msg->previous));
451
452 GNUNET_MQ_send (handle->mq, env);
453}
454
455
456static enum GNUNET_GenericReturnValue
457iterate_reset_room (void *cls,
458 const struct GNUNET_HashCode *key,
459 void *value)
460{
461 struct GNUNET_MESSENGER_Handle *handle = cls;
462 struct GNUNET_MESSENGER_Room *room = value;
463
464 if (GNUNET_YES == room->opened)
465 send_open_room (handle, room);
466
467 struct GNUNET_MESSENGER_ListTunnel *entry = room->entries.head;
468
469 struct GNUNET_PeerIdentity door;
470
471 while (entry)
472 {
473 GNUNET_PEER_resolve (entry->peer, &door);
474
475 send_enter_room (handle, room, &door);
476
477 entry = entry->next;
478 }
479
480 return GNUNET_YES;
481}
482
483
484static void
485callback_reconnect (void *cls)
486{
487 struct GNUNET_MESSENGER_Handle *handle = cls;
488
489 handle->reconnect_task = NULL;
490 handle->reconnect_time = GNUNET_TIME_STD_BACKOFF (handle->reconnect_time);
491
492 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Reconnect messenger!\n");
493
494 reconnect (handle);
495
496 GNUNET_CONTAINER_multihashmap_iterate (handle->rooms, iterate_reset_room,
497 handle);
498}
499
500
501static enum GNUNET_GenericReturnValue
502iterate_close_room (void *cls,
503 const struct GNUNET_HashCode *key,
504 void *value)
505{
506 struct GNUNET_MESSENGER_Handle *handle = cls;
507 struct GNUNET_MESSENGER_Room *room = value;
508
509 send_close_room (handle, room);
510
511 return GNUNET_YES;
512}
513
514
515static void
516callback_mq_error (void *cls,
517 enum GNUNET_MQ_Error error)
518{
519 struct GNUNET_MESSENGER_Handle *handle = cls;
520
521 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MQ_Error: %u\n", error);
522
523 GNUNET_CONTAINER_multihashmap_iterate (handle->rooms, iterate_close_room,
524 handle);
525
526 if (handle->mq)
527 {
528 GNUNET_MQ_destroy (handle->mq);
529 handle->mq = NULL;
530 }
531
532 handle->reconnect_task = GNUNET_SCHEDULER_add_delayed (handle->reconnect_time,
533 &callback_reconnect,
534 handle);
535}
536
537
538static void
539reconnect (struct GNUNET_MESSENGER_Handle *handle)
540{
541 const struct GNUNET_MQ_MessageHandler handlers[] = {
542 GNUNET_MQ_hd_fixed_size (
543 member_id,
544 GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_MEMBER_ID,
545 struct GNUNET_MESSENGER_MemberMessage, handle
546 ),
547 GNUNET_MQ_hd_fixed_size (
548 room_open,
549 GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_OPEN,
550 struct GNUNET_MESSENGER_RoomMessage, handle
551 ),
552 GNUNET_MQ_hd_fixed_size (
553 room_entry,
554 GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_ENTRY,
555 struct GNUNET_MESSENGER_RoomMessage, handle
556 ),
557 GNUNET_MQ_hd_fixed_size (
558 room_close,
559 GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_CLOSE,
560 struct GNUNET_MESSENGER_RoomMessage, handle
561 ),
562 GNUNET_MQ_hd_var_size (
563 recv_message,
564 GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_RECV_MESSAGE,
565 struct GNUNET_MESSENGER_RecvMessage, handle
566 ),
567 GNUNET_MQ_hd_fixed_size (
568 miss_message,
569 GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_GET_MESSAGE,
570 struct GNUNET_MESSENGER_GetMessage, handle
571 ),
572 GNUNET_MQ_hd_fixed_size (
573 room_sync,
574 GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_SYNC,
575 struct GNUNET_MESSENGER_RoomMessage, handle
576 ),
577 GNUNET_MQ_handler_end ()
578 };
579
580 handle->mq = GNUNET_CLIENT_connect (handle->cfg,
581 GNUNET_MESSENGER_SERVICE_NAME, handlers,
582 &callback_mq_error, handle);
583}
584
585
586struct GNUNET_MESSENGER_Handle*
587GNUNET_MESSENGER_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
588 const char *name,
589 const struct GNUNET_CRYPTO_PrivateKey *key,
590 GNUNET_MESSENGER_MessageCallback msg_callback,
591 void *msg_cls)
592{
593 struct GNUNET_MESSENGER_Handle *handle = create_handle (cfg, msg_callback,
594 msg_cls);
595
596 reconnect (handle);
597
598 if (handle->mq)
599 {
600 set_handle_name (handle, name);
601
602 if ((! key) || (0 < GNUNET_CRYPTO_private_key_get_length (key)))
603 set_handle_key (handle, key);
604
605 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connect handle!\n");
606
607 struct GNUNET_MESSENGER_CreateMessage *msg;
608 struct GNUNET_MQ_Envelope *env;
609
610 env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_CREATE);
611 GNUNET_MQ_send (handle->mq, env);
612 return handle;
613 }
614 else
615 {
616 destroy_handle (handle);
617 return NULL;
618 }
619}
620
621
622void
623GNUNET_MESSENGER_disconnect (struct GNUNET_MESSENGER_Handle *handle)
624{
625 if (! handle)
626 return;
627
628 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnect handle!\n");
629
630 struct GNUNET_MESSENGER_DestroyMessage *msg;
631 struct GNUNET_MQ_Envelope *env;
632
633 env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_DESTROY);
634 GNUNET_MQ_send (handle->mq, env);
635
636 destroy_handle (handle);
637}
638
639
640static void
641callback_leave_message_sent (void *cls)
642{
643 struct GNUNET_MESSENGER_Room *room = cls;
644
645 room->opened = GNUNET_NO;
646 clear_list_tunnels (&(room->entries));
647
648 send_close_room (room->handle, room);
649}
650
651
652static void
653send_message_to_room (struct GNUNET_MESSENGER_Room *room,
654 struct GNUNET_MESSENGER_Message *message,
655 const struct GNUNET_CRYPTO_PrivateKey *key,
656 struct GNUNET_HashCode *hash)
657{
658 const struct GNUNET_ShortHashCode *sender_id = get_room_sender_id (room);
659
660 message->header.timestamp = GNUNET_TIME_absolute_hton (
661 GNUNET_TIME_absolute_get ());
662
663 GNUNET_memcpy (&(message->header.sender_id), sender_id,
664 sizeof(message->header.sender_id));
665 GNUNET_memcpy (&(message->header.previous), &(room->last_message),
666 sizeof(message->header.previous));
667
668 message->header.signature.type = key->type;
669
670 const uint16_t msg_length = get_message_size (message, GNUNET_YES);
671
672 struct GNUNET_MESSENGER_SendMessage *msg;
673 struct GNUNET_MQ_Envelope *env;
674
675 env = GNUNET_MQ_msg_extra (
676 msg, msg_length,
677 GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_SEND_MESSAGE
678 );
679
680 GNUNET_memcpy (&(msg->key), &(room->key), sizeof(msg->key));
681
682 char *msg_buffer = ((char*) msg) + sizeof(*msg);
683 encode_message (message, msg_length, msg_buffer, GNUNET_YES);
684
685 hash_message (message, msg_length, msg_buffer, hash);
686 sign_message (message, msg_length, msg_buffer, hash, key);
687
688 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Send message (%s)!\n",
689 GNUNET_h2s (hash));
690
691 update_room_last_message (room, hash);
692
693 if (GNUNET_MESSENGER_KIND_LEAVE == message->header.kind)
694 GNUNET_MQ_notify_sent (env, callback_leave_message_sent, room);
695
696 GNUNET_MQ_send (room->handle->mq, env);
697}
698
699
700static void
701enqueue_message_to_room (struct GNUNET_MESSENGER_Room *room,
702 struct GNUNET_MESSENGER_Message *message,
703 struct GNUNET_MESSENGER_Message *transcript)
704{
705 GNUNET_assert ((room) && (message));
706
707 const struct GNUNET_CRYPTO_PrivateKey *key = get_handle_key (room->handle);
708 enum GNUNET_GenericReturnValue priority;
709
710 switch (message->header.kind)
711 {
712 case GNUNET_MESSENGER_KIND_JOIN:
713 priority = GNUNET_YES;
714 break;
715 default:
716 priority = GNUNET_NO;
717 break;
718 }
719
720 enqueue_to_messages (&(room->queue), key, message, transcript, priority);
721
722 if (GNUNET_YES != is_room_available (room))
723 return;
724
725 if (GNUNET_YES == is_message_session_bound (message))
726 send_sync_room (room->handle, room);
727 else if (GNUNET_YES != room->wait_for_sync)
728 dequeue_messages_from_room (room);
729}
730
731
732static enum GNUNET_GenericReturnValue
733dequeue_messages_from_room (struct GNUNET_MESSENGER_Room *room)
734{
735 if (GNUNET_YES != is_room_available (room))
736 return room->queue.head ? GNUNET_NO : GNUNET_YES;
737
738 struct GNUNET_MESSENGER_Message *message = NULL;
739 struct GNUNET_MESSENGER_Message *transcript = NULL;
740 struct GNUNET_CRYPTO_PublicKey pubkey;
741 struct GNUNET_CRYPTO_PrivateKey key;
742 struct GNUNET_HashCode hash, other;
743
744 do {
745 if (message)
746 destroy_message (message);
747
748 memset (&key, 0, sizeof(key));
749 message = dequeue_from_messages (&(room->queue), &key, &transcript);
750
751 if (! message)
752 {
753 message = transcript;
754 transcript = NULL;
755 continue;
756 }
757
758 send_message_to_room (room, message, &key, &hash);
759
760 if (! transcript)
761 {
762 GNUNET_CRYPTO_private_key_clear (&key);
763 continue;
764 }
765
766 GNUNET_memcpy (&(transcript->body.transcript.hash), &hash, sizeof(hash));
767
768 memset (&pubkey, 0, sizeof(pubkey));
769 GNUNET_CRYPTO_key_get_public (&key, &pubkey);
770
771 if (GNUNET_YES == encrypt_message (transcript, &pubkey))
772 {
773 send_message_to_room (room, transcript, &key, &other);
774 GNUNET_CRYPTO_private_key_clear (&key);
775
776 link_room_message (room, &hash, &other);
777 link_room_message (room, &other, &hash);
778 }
779 else
780 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
781 "Sending transcript aborted: Encryption failed!\n");
782
783 destroy_message (transcript);
784 transcript = NULL;
785 } while (message);
786
787 return GNUNET_YES;
788}
789
790
791const char*
792GNUNET_MESSENGER_get_name (const struct GNUNET_MESSENGER_Handle *handle)
793{
794 if (! handle)
795 return NULL;
796
797 return get_handle_name (handle);
798}
799
800
801static enum GNUNET_GenericReturnValue
802iterate_send_name_to_room (void *cls,
803 struct GNUNET_MESSENGER_Room *room,
804 const struct GNUNET_MESSENGER_Contact *contact)
805{
806 const struct GNUNET_MESSENGER_Handle *handle = cls;
807
808 if (GNUNET_YES != room->use_handle_name)
809 return GNUNET_YES;
810
811 const char *name = get_handle_name (handle);
812
813 if (! name)
814 return GNUNET_YES;
815
816 struct GNUNET_MESSENGER_Message *message = create_message_name (name);
817
818 if (! message)
819 return GNUNET_NO;
820
821 enqueue_message_to_room (room, message, NULL);
822 return GNUNET_YES;
823}
824
825
826enum GNUNET_GenericReturnValue
827GNUNET_MESSENGER_set_name (struct GNUNET_MESSENGER_Handle *handle,
828 const char *name)
829{
830 if (! handle)
831 return GNUNET_SYSERR;
832
833 set_handle_name (handle, strlen (name) > 0 ? name : NULL);
834 GNUNET_MESSENGER_find_rooms (handle, NULL, iterate_send_name_to_room, handle);
835 return GNUNET_YES;
836}
837
838
839static const struct GNUNET_CRYPTO_PublicKey*
840get_non_anonymous_key (const struct GNUNET_CRYPTO_PublicKey *public_key)
841{
842 if (0 == GNUNET_memcmp (public_key, get_anonymous_public_key ()))
843 return NULL;
844
845 return public_key;
846}
847
848
849const struct GNUNET_CRYPTO_PublicKey*
850GNUNET_MESSENGER_get_key (const struct GNUNET_MESSENGER_Handle *handle)
851{
852 if (! handle)
853 return NULL;
854
855 return get_non_anonymous_key (get_handle_pubkey (handle));
856}
857
858
859static enum GNUNET_GenericReturnValue
860iterate_send_key_to_room (void *cls,
861 struct GNUNET_MESSENGER_Room *room,
862 const struct GNUNET_MESSENGER_Contact *contact)
863{
864 const struct GNUNET_CRYPTO_PrivateKey *key = cls;
865
866 struct GNUNET_MESSENGER_Message *message = create_message_key (key);
867
868 if (! message)
869 return GNUNET_NO;
870
871 enqueue_message_to_room (room, message, NULL);
872 return GNUNET_YES;
873}
874
875
876enum GNUNET_GenericReturnValue
877GNUNET_MESSENGER_set_key (struct GNUNET_MESSENGER_Handle *handle,
878 const struct GNUNET_CRYPTO_PrivateKey *key)
879{
880 if (! handle)
881 return GNUNET_SYSERR;
882
883 if (! key)
884 {
885 GNUNET_MESSENGER_find_rooms (handle, NULL, iterate_send_key_to_room, NULL);
886 set_handle_key (handle, NULL);
887 return GNUNET_YES;
888 }
889
890 if (0 >= GNUNET_CRYPTO_private_key_get_length (key))
891 return GNUNET_SYSERR;
892
893 struct GNUNET_CRYPTO_PrivateKey priv;
894 GNUNET_memcpy (&priv, key, sizeof (priv));
895
896 GNUNET_MESSENGER_find_rooms (handle, NULL, iterate_send_key_to_room, &priv);
897 GNUNET_CRYPTO_private_key_clear (&priv);
898
899 set_handle_key (handle, key);
900 return GNUNET_YES;
901}
902
903
904struct GNUNET_MESSENGER_Room*
905GNUNET_MESSENGER_open_room (struct GNUNET_MESSENGER_Handle *handle,
906 const struct GNUNET_HashCode *key)
907{
908 if ((! handle) || (! key))
909 return NULL;
910
911 struct GNUNET_MESSENGER_Room *room = GNUNET_CONTAINER_multihashmap_get (
912 handle->rooms, key);
913
914 if (! room)
915 {
916 room = create_room (handle, key);
917
918 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (handle->rooms, key,
919 room,
920 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
921 {
922 destroy_room (room);
923 return NULL;
924 }
925 }
926
927 send_open_room (handle, room);
928 return room;
929}
930
931
932struct GNUNET_MESSENGER_Room*
933GNUNET_MESSENGER_enter_room (struct GNUNET_MESSENGER_Handle *handle,
934 const struct GNUNET_PeerIdentity *door,
935 const struct GNUNET_HashCode *key)
936{
937 if ((! handle) || (! door) || (! key))
938 return NULL;
939
940 struct GNUNET_MESSENGER_Room *room = GNUNET_CONTAINER_multihashmap_get (
941 handle->rooms, key);
942
943 if (! room)
944 {
945 room = create_room (handle, key);
946
947 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (handle->rooms, key,
948 room,
949 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
950 {
951 destroy_room (room);
952 return NULL;
953 }
954 }
955
956 send_enter_room (handle, room, door);
957 return room;
958}
959
960
961void
962GNUNET_MESSENGER_close_room (struct GNUNET_MESSENGER_Room *room)
963{
964 if (! room)
965 return;
966
967 struct GNUNET_MESSENGER_Message *message = create_message_leave ();
968
969 if (! message)
970 return;
971
972 enqueue_message_to_room (room, message, NULL);
973}
974
975
976struct GNUNET_MESSENGER_RoomFind
977{
978 const struct GNUNET_MESSENGER_Contact *contact;
979 GNUNET_MESSENGER_MemberCallback callback;
980 size_t counter;
981 void *cls;
982};
983
984static enum GNUNET_GenericReturnValue
985iterate_find_room (void *cls,
986 const struct GNUNET_HashCode *key,
987 void *value)
988{
989 struct GNUNET_MESSENGER_RoomFind *find = cls;
990 struct GNUNET_MESSENGER_Room *room = value;
991
992 if ((find->counter > 0) && ((! find->contact) || (GNUNET_YES ==
993 find_room_member (room,
994 find->
995 contact)))
996 )
997 {
998 find->counter--;
999
1000 if (! find->callback)
1001 return GNUNET_YES;
1002
1003 return find->callback (find->cls, room, find->contact);
1004 }
1005 else
1006 return GNUNET_NO;
1007}
1008
1009
1010int
1011GNUNET_MESSENGER_find_rooms (const struct GNUNET_MESSENGER_Handle *handle,
1012 const struct GNUNET_MESSENGER_Contact *contact,
1013 GNUNET_MESSENGER_MemberCallback callback,
1014 void *cls)
1015{
1016 if (! handle)
1017 return GNUNET_SYSERR;
1018
1019 struct GNUNET_MESSENGER_RoomFind find;
1020
1021 find.contact = contact;
1022 find.callback = callback;
1023 find.counter = (contact? contact->rc : SIZE_MAX);
1024 find.cls = cls;
1025
1026 return GNUNET_CONTAINER_multihashmap_iterate (handle->rooms,
1027 iterate_find_room, &find);
1028}
1029
1030
1031const struct GNUNET_HashCode*
1032GNUNET_MESSENGER_room_get_key (const struct GNUNET_MESSENGER_Room *room)
1033{
1034 if (! room)
1035 return NULL;
1036
1037 return &(room->key);
1038}
1039
1040
1041const struct GNUNET_MESSENGER_Contact*
1042GNUNET_MESSENGER_get_sender (const struct GNUNET_MESSENGER_Room *room,
1043 const struct GNUNET_HashCode *hash)
1044{
1045 if ((! room) || (! hash))
1046 return NULL;
1047
1048 return get_room_sender (room, hash);
1049}
1050
1051
1052const struct GNUNET_MESSENGER_Contact*
1053GNUNET_MESSENGER_get_recipient (const struct GNUNET_MESSENGER_Room *room,
1054 const struct GNUNET_HashCode *hash)
1055{
1056 if ((! room) || (! hash))
1057 return NULL;
1058
1059 return get_room_recipient (room, hash);
1060}
1061
1062
1063const char*
1064GNUNET_MESSENGER_contact_get_name (const struct
1065 GNUNET_MESSENGER_Contact *contact)
1066{
1067 if (! contact)
1068 return NULL;
1069
1070 return get_contact_name (contact);
1071}
1072
1073
1074const struct GNUNET_CRYPTO_PublicKey*
1075GNUNET_MESSENGER_contact_get_key (const struct
1076 GNUNET_MESSENGER_Contact *contact)
1077{
1078 if (! contact)
1079 return NULL;
1080
1081 return get_non_anonymous_key (get_contact_key (contact));
1082}
1083
1084
1085size_t
1086GNUNET_MESSENGER_contact_get_id (const struct
1087 GNUNET_MESSENGER_Contact *contact)
1088{
1089 if (! contact)
1090 return 0;
1091
1092 return get_contact_id (contact);
1093}
1094
1095
1096static void
1097send_message_to_room_with_key (struct GNUNET_MESSENGER_Room *room,
1098 struct GNUNET_MESSENGER_Message *message,
1099 const struct GNUNET_CRYPTO_PublicKey *public_key)
1100{
1101 struct GNUNET_MESSENGER_Message *transcript = NULL;
1102 const struct GNUNET_CRYPTO_PublicKey *pubkey;
1103
1104 char *original_name;
1105
1106 if (GNUNET_MESSENGER_KIND_NAME != message->header.kind)
1107 goto skip_naming;
1108
1109 original_name = message->body.name.name;
1110 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1111 "Apply rule for using handle name in room: %s\n", GNUNET_h2s (
1112 &(room->key)));
1113
1114 const char *handle_name = get_handle_name (room->handle);
1115
1116 if ((handle_name) && (GNUNET_YES == room->use_handle_name) &&
1117 ((! original_name) || (0 == strlen (original_name))))
1118 {
1119 if (original_name)
1120 GNUNET_free (original_name);
1121
1122 message->body.name.name = GNUNET_strdup (handle_name);
1123 }
1124
1125skip_naming:
1126 if (! public_key)
1127 goto skip_encryption;
1128
1129 pubkey = get_handle_pubkey (room->handle);
1130
1131 if (0 != GNUNET_memcmp (pubkey, public_key))
1132 transcript = transcribe_message (message, public_key);
1133
1134 if (GNUNET_YES != encrypt_message (message, public_key))
1135 {
1136 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1137 "Sending message aborted: Encryption failed!\n");
1138
1139 if (transcript)
1140 destroy_message (transcript);
1141
1142 destroy_message (message);
1143 return;
1144 }
1145
1146skip_encryption:
1147 enqueue_message_to_room (room, message, transcript);
1148}
1149
1150
1151void
1152GNUNET_MESSENGER_send_message (struct GNUNET_MESSENGER_Room *room,
1153 const struct GNUNET_MESSENGER_Message *message,
1154 const struct GNUNET_MESSENGER_Contact *contact)
1155{
1156 if ((! room) || (! message))
1157 return;
1158
1159 switch (filter_message_sending (message))
1160 {
1161 case GNUNET_SYSERR:
1162 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1163 "Sending message aborted: This kind of message is reserved for the service!\n");
1164 return;
1165 case GNUNET_NO:
1166 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1167 "Sending message aborted: This kind of message could cause issues!\n");
1168 return;
1169 default:
1170 break;
1171 }
1172
1173 const struct GNUNET_CRYPTO_PublicKey *public_key;
1174
1175 if (contact)
1176 {
1177 public_key = get_non_anonymous_key (
1178 get_contact_key (contact)
1179 );
1180
1181 if (! public_key)
1182 {
1183 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1184 "Sending message aborted: Invalid key!\n");
1185 return;
1186 }
1187 }
1188 else
1189 public_key = NULL;
1190
1191 send_message_to_room_with_key (room, copy_message (message), public_key);
1192}
1193
1194
1195void
1196delete_message_in_room (struct GNUNET_MESSENGER_Room *room,
1197 const struct GNUNET_HashCode *hash,
1198 const struct GNUNET_TIME_Relative delay)
1199{
1200 struct GNUNET_MESSENGER_Message *message = create_message_delete (hash,
1201 delay);
1202
1203 if (! message)
1204 {
1205 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1206 "Sending deletion aborted: Message creation failed!\n");
1207 return;
1208 }
1209
1210 send_message_to_room_with_key (room, message, NULL);
1211}
1212
1213
1214void
1215GNUNET_MESSENGER_delete_message (struct GNUNET_MESSENGER_Room *room,
1216 const struct GNUNET_HashCode *hash,
1217 const struct GNUNET_TIME_Relative delay)
1218{
1219 if ((! room) || (! hash))
1220 return;
1221
1222 delete_message_in_room (room, hash, delay);
1223}
1224
1225
1226const struct GNUNET_MESSENGER_Message*
1227GNUNET_MESSENGER_get_message (const struct GNUNET_MESSENGER_Room *room,
1228 const struct GNUNET_HashCode *hash)
1229{
1230 if ((! room) || (! hash))
1231 return NULL;
1232
1233 const struct GNUNET_MESSENGER_Message *message = get_room_message (room,
1234 hash);
1235
1236 if (! message)
1237 {
1238 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Request message (%s)!\n",
1239 GNUNET_h2s (hash));
1240
1241 struct GNUNET_MESSENGER_GetMessage *msg;
1242 struct GNUNET_MQ_Envelope *env;
1243
1244 env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_GET_MESSAGE);
1245 GNUNET_memcpy (&(msg->key), &(room->key), sizeof(msg->key));
1246 GNUNET_memcpy (&(msg->hash), hash, sizeof(*hash));
1247 GNUNET_MQ_send (room->handle->mq, env);
1248 }
1249
1250 return message;
1251}
1252
1253
1254int
1255GNUNET_MESSENGER_iterate_members (struct GNUNET_MESSENGER_Room *room,
1256 GNUNET_MESSENGER_MemberCallback callback,
1257 void *cls)
1258{
1259 if (! room)
1260 return GNUNET_SYSERR;
1261
1262 return iterate_room_members (room, callback, cls);
1263}
diff --git a/src/service/messenger/messenger_api_cmd_join_room.c b/src/service/messenger/messenger_api_cmd_join_room.c
new file mode 100644
index 000000000..dc0e9a882
--- /dev/null
+++ b/src/service/messenger/messenger_api_cmd_join_room.c
@@ -0,0 +1,181 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2023 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file messenger_api_cmd_join_room.c
23 * @brief cmd to join a room in a messenger service.
24 * @author Tobias Frisch
25 */
26
27#include "gnunet_util_lib.h"
28#include "gnunet_core_testing_lib.h"
29#include "gnunet_transport_testing_ng_lib.h"
30#include "gnunet_messenger_service.h"
31#include "messenger-testing-cmds.h"
32
33struct GNUNET_MESSENGER_JoinRoomState
34{
35 char *service_label;
36 char *room_key;
37
38 struct GNUNET_MESSENGER_Room *room;
39};
40
41static void
42join_room_run (void *cls,
43 struct GNUNET_TESTING_Interpreter *is)
44{
45 struct GNUNET_MESSENGER_JoinRoomState *jrs = cls;
46 struct GNUNET_HashCode key;
47
48 if (jrs->room_key)
49 GNUNET_CRYPTO_hash (jrs->room_key, strlen (jrs->room_key), &key);
50 else
51 memset (&key, 0, sizeof(key));
52
53 const struct GNUNET_TESTING_Command *service_cmd;
54 service_cmd = GNUNET_TESTING_interpreter_lookup_command (is,
55 jrs->service_label);
56
57 struct GNUNET_MESSENGER_StartServiceState *sss;
58 GNUNET_MESSENGER_get_trait_state (service_cmd, &sss);
59
60 unsigned int peer_index;
61 unsigned int stage_index;
62 struct GNUNET_MESSENGER_RoomState *rs;
63
64 rs = GNUNET_CONTAINER_multihashmap_get (sss->rooms, &key);
65 if (rs)
66 goto skip_room_state;
67
68 rs = GNUNET_MESSENGER_create_room_state (sss->topology);
69 if ((! rs) && (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (sss->rooms,
70 &key,
71 rs,
72 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)))
73 {
74 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
75 "Testing library failed to create a room state with key '%s'\n",
76 jrs->room_key);
77 GNUNET_TESTING_interpreter_fail (is);
78 return;
79 }
80
81skip_room_state:
82 peer_index = sss->peer_index;
83 stage_index = sss->stage_index;
84
85 const unsigned int index = stage_index * sss->topology->peer_amount
86 + peer_index;
87 const struct GNUNET_MESSENGER_TestStage *stage =
88 &(sss->topology->peer_stages[index]);
89
90 unsigned int door_index = stage->door_id;
91
92 if (door_index == 0)
93 door_index = (peer_index + GNUNET_CRYPTO_random_u32 (
94 GNUNET_CRYPTO_QUALITY_WEAK,
95 sss->topology->peer_amount - 1
96 ) + 1) % sss->topology->peer_amount;
97 else
98 door_index = (door_index - 1) % sss->topology->peer_amount;
99
100 struct GNUNET_PeerIdentity *door;
101 door = GNUNET_TESTING_get_peer (door_index, sss->tl_system);
102 if (! door)
103 {
104 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
105 "Testing library failed to get peer identity of index '%u'\n",
106 door_index);
107 GNUNET_TESTING_interpreter_fail (is);
108 return;
109 }
110
111 struct GNUNET_MESSENGER_Room *room;
112 switch (stage->join)
113 {
114 case GNUNET_MESSENGER_STAGE_JOIN_OPEN_ROOM:
115 room = GNUNET_MESSENGER_open_room (sss->msg, &key);
116
117 if (! room)
118 {
119 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
120 "Testing library failed to open room with key '%s'\n",
121 jrs->room_key);
122 GNUNET_free (door);
123 GNUNET_TESTING_interpreter_fail (is);
124 return;
125 }
126
127 break;
128 case GNUNET_MESSENGER_STAGE_JOIN_ENTER_ROOM:
129 room = GNUNET_MESSENGER_enter_room (sss->msg, door, &key);
130
131 if (! room)
132 {
133 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
134 "Testing library failed to enter room with key '%s'\n",
135 jrs->room_key);
136 GNUNET_free (door);
137 GNUNET_TESTING_interpreter_fail (is);
138 return;
139 }
140
141 break;
142 default:
143 room = NULL;
144 break;
145 }
146
147 jrs->room = room;
148TODO: sss->stage_index++;
149
150 GNUNET_free (door);
151}
152
153
154static void
155join_room_cleanup (void *cls)
156{
157 struct GNUNET_MESSENGER_JoinRoomState *jrs = cls;
158
159 GNUNET_free (jrs->room_key);
160 GNUNET_free (jrs->service_label);
161 GNUNET_free (jrs);
162}
163
164
165struct GNUNET_TESTING_Command
166GNUNET_MESSENGER_cmd_join_room (const char *label,
167 const char *service_label,
168 const char *room_key)
169{
170 struct GNUNET_MESSENGER_JoinRoomState *jrs;
171
172 jrs = GNUNET_new (struct GNUNET_MESSENGER_JoinRoomState);
173 jrs->service_label = GNUNET_strdup (service_label);
174 jrs->room_key = GNUNET_strdup (room_key);
175
176 return GNUNET_TESTING_command_new (jrs,
177 label,
178 &join_room_run,
179 &join_room_cleanup,
180 NULL);
181}
diff --git a/src/service/messenger/messenger_api_cmd_start_service.c b/src/service/messenger/messenger_api_cmd_start_service.c
new file mode 100644
index 000000000..f764d31c2
--- /dev/null
+++ b/src/service/messenger/messenger_api_cmd_start_service.c
@@ -0,0 +1,172 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2023--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file messenger_api_cmd_start_service.c
23 * @brief cmd to start a messenger service.
24 * @author Tobias Frisch
25 */
26
27#include "gnunet_util_lib.h"
28#include "gnunet_testing_ng_lib.h"
29#include "gnunet_testing_netjail_lib.h"
30#include "gnunet_transport_testing_ng_lib.h"
31#include "gnunet_messenger_service.h"
32#include "messenger-testing-cmds.h"
33
34static void
35on_message_cb (void *cls,
36 struct GNUNET_MESSENGER_Room *room,
37 const struct GNUNET_MESSENGER_Contact *sender,
38 const struct GNUNET_MESSENGER_Contact *recipient,
39 const struct GNUNET_MESSENGER_Message *message,
40 const struct GNUNET_HashCode *hash,
41 enum GNUNET_MESSENGER_MessageFlags flags)
42{
43 struct GNUNET_MESSENGER_StartServiceState *sss = cls;
44
45 const struct GNUNET_HashCode *key = GNUNET_MESSENGER_room_get_key (room);
46 struct GNUNET_MESSENGER_RoomState *rs;
47
48 rs = GNUNET_CONTAINER_multihashmap_get (sss->rooms, key);
49 if (! rs)
50 {
51 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
52 "Testing library failed to find room state\n");
53 GNUNET_TESTING_interpreter_fail (sss->is);
54 return;
55 }
56
57 if (GNUNET_MESSENGER_KIND_PEER != message->header.kind)
58 return;
59
60 if (GNUNET_OK != GNUNET_CONTAINER_multipeermap_put (rs->doors,
61 &(message->body.peer.peer)
62 ,
63 NULL,
64 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE))
65 {
66 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
67 "Testing library failed to register peer identity as found door\n");
68 GNUNET_TESTING_interpreter_fail (sss->is);
69 return;
70 }
71}
72
73
74static void
75start_service_run (void *cls,
76 struct GNUNET_TESTING_Interpreter *is)
77{
78 struct GNUNET_MESSENGER_StartServiceState *sss = cls;
79
80 sss->is = is;
81
82 const struct GNUNET_TESTING_Command *peer_cmd;
83 peer_cmd = GNUNET_TESTING_interpreter_lookup_command (is,
84 sss->peer_label);
85
86 const struct GNUNET_TESTING_StartPeerState *sps;
87 GNUNET_TRANSPORT_TESTING_get_trait_state (peer_cmd, &sps);
88
89 const struct GNUNET_TESTING_Command *system_cmd;
90 system_cmd = GNUNET_TESTING_interpreter_lookup_command (is,
91 sss->system_label);
92
93 const struct GNUNET_TESTING_System *tl_system;
94 GNUNET_TESTING_get_trait_test_system (system_cmd,
95 &tl_system);
96
97 sss->tl_system = tl_system;
98
99 sss->msg = GNUNET_MESSENGER_connect (sps->cfg, NULL, NULL, on_message_cb,
100 sss);
101 if (! sss->msg)
102 {
103 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
104 "Testing library failed to connect to messenger service\n");
105 GNUNET_TESTING_interpreter_fail (is);
106 return;
107 }
108
109 sss->rooms = GNUNET_CONTAINER_multihashmap_create (
110 sss->topology->stage_amount, GNUNET_NO);
111}
112
113
114static void
115start_service_cleanup (void *cls)
116{
117 struct GNUNET_MESSENGER_StartServiceState *sss = cls;
118
119 GNUNET_free (sss->system_label);
120 GNUNET_free (sss->peer_label);
121 GNUNET_free (sss);
122}
123
124
125static enum GNUNET_GenericReturnValue
126start_service_traits (void *cls,
127 const void **ret,
128 const char *trait,
129 unsigned int index)
130{
131 struct GNUNET_MESSENGER_StartServiceState *sss = cls;
132
133 struct GNUNET_TESTING_Trait traits[] = {
134 GNUNET_MESSENGER_make_trait_state ((void *) sss),
135 GNUNET_TESTING_trait_end ()
136 };
137
138 return GNUNET_TESTING_get_trait (traits,
139 ret,
140 trait,
141 index);
142}
143
144
145struct GNUNET_TESTING_Command
146GNUNET_MESSENGER_cmd_start_service (const char *label,
147 const char *peer_label,
148 const char *system_label,
149 struct GNUNET_MESSENGER_TestStageTopology *
150 topology,
151 unsigned int peer_index)
152{
153 struct GNUNET_MESSENGER_StartServiceState *sss;
154
155 sss = GNUNET_new (struct GNUNET_MESSENGER_StartServiceState);
156 sss->peer_label = GNUNET_strdup (peer_label);
157 sss->system_label = GNUNET_strdup (system_label);
158 sss->topology = topology;
159
160 sss->is = NULL;
161 sss->tl_system = NULL;
162 sss->msg = NULL;
163 sss->rooms = NULL;
164 sss->peer_index = peer_index;
165 sss->stage_index = 0;
166
167 return GNUNET_TESTING_command_new (sss,
168 label,
169 &start_service_run,
170 &start_service_cleanup,
171 &start_service_traits);
172}
diff --git a/src/service/messenger/messenger_api_cmd_stop_service.c b/src/service/messenger/messenger_api_cmd_stop_service.c
new file mode 100644
index 000000000..b10de7661
--- /dev/null
+++ b/src/service/messenger/messenger_api_cmd_stop_service.c
@@ -0,0 +1,95 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2023 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file messenger_api_cmd_stop_service.c
23 * @brief cmd to stop a messenger service.
24 * @author Tobias Frisch
25 */
26
27#include "gnunet_util_lib.h"
28#include "gnunet_testing_ng_lib.h"
29#include "gnunet_messenger_service.h"
30#include "messenger-testing-cmds.h"
31
32struct GNUNET_MESSENGER_StopServiceState
33{
34 char *service_label;
35};
36
37static enum GNUNET_GenericReturnValue
38cleanup_rooms_cb (void *cls,
39 const struct GNUNET_HashCode *key,
40 void *value)
41{
42 struct GNUNET_MESSENGER_RoomState *rs = cls;
43 GNUNET_MESSENGER_destroy_room_state (rs);
44 return GNUNET_YES;
45}
46
47
48static void
49stop_service_run (void *cls,
50 struct GNUNET_TESTING_Interpreter *is)
51{
52 struct GNUNET_MESSENGER_StopServiceState *stop_ss = cls;
53
54 const struct GNUNET_TESTING_Command *service_cmd;
55 service_cmd = GNUNET_TESTING_interpreter_lookup_command (is,
56 stop_ss->
57 service_label);
58
59 struct GNUNET_MESSENGER_StartServiceState *sss;
60 GNUNET_MESSENGER_get_trait_state (service_cmd, &sss);
61
62 GNUNET_MESSENGER_disconnect (sss->msg);
63 sss->msg = NULL;
64
65 GNUNET_CONTAINER_multihashmap_iterate (sss->rooms, cleanup_rooms_cb, NULL);
66 GNUNET_CONTAINER_multihashmap_destroy (sss->rooms);
67 sss->rooms = NULL;
68}
69
70
71static void
72stop_service_cleanup (void *cls)
73{
74 struct GNUNET_MESSENGER_StopServiceState *sss = cls;
75
76 GNUNET_free (sss->service_label);
77 GNUNET_free (sss);
78}
79
80
81struct GNUNET_TESTING_Command
82GNUNET_MESSENGER_cmd_stop_service (const char *label,
83 const char *service_label)
84{
85 struct GNUNET_MESSENGER_StopServiceState *sss;
86
87 sss = GNUNET_new (struct GNUNET_MESSENGER_StopServiceState);
88 sss->service_label = GNUNET_strdup (service_label);
89
90 return GNUNET_TESTING_command_new (sss,
91 label,
92 &stop_service_run,
93 &stop_service_cleanup,
94 NULL);
95}
diff --git a/src/service/messenger/messenger_api_contact.c b/src/service/messenger/messenger_api_contact.c
new file mode 100644
index 000000000..841f72a10
--- /dev/null
+++ b/src/service/messenger/messenger_api_contact.c
@@ -0,0 +1,129 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2023 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/messenger_api_contact.c
23 * @brief messenger api: client implementation of GNUnet MESSENGER service
24 */
25
26#include "messenger_api_contact.h"
27
28struct GNUNET_MESSENGER_Contact*
29create_contact (const struct GNUNET_CRYPTO_PublicKey *key,
30 size_t unique_id)
31{
32 GNUNET_assert (key);
33
34 struct GNUNET_MESSENGER_Contact *contact = GNUNET_new (struct
35 GNUNET_MESSENGER_Contact);
36
37 contact->name = NULL;
38 contact->rc = 0;
39 contact->id = unique_id;
40
41 GNUNET_memcpy (&(contact->public_key), key, sizeof(contact->public_key));
42
43 return contact;
44}
45
46
47void
48destroy_contact (struct GNUNET_MESSENGER_Contact *contact)
49{
50 GNUNET_assert (contact);
51
52 if (contact->name)
53 GNUNET_free (contact->name);
54
55 GNUNET_free (contact);
56}
57
58
59const char*
60get_contact_name (const struct GNUNET_MESSENGER_Contact *contact)
61{
62 GNUNET_assert (contact);
63
64 return contact->name;
65}
66
67
68void
69set_contact_name (struct GNUNET_MESSENGER_Contact *contact,
70 const char *name)
71{
72 GNUNET_assert (contact);
73
74 if (contact->name)
75 GNUNET_free (contact->name);
76
77 contact->name = name ? GNUNET_strdup (name) : NULL;
78}
79
80
81const struct GNUNET_CRYPTO_PublicKey*
82get_contact_key (const struct GNUNET_MESSENGER_Contact *contact)
83{
84 GNUNET_assert (contact);
85
86 return &(contact->public_key);
87}
88
89
90void
91increase_contact_rc (struct GNUNET_MESSENGER_Contact *contact)
92{
93 GNUNET_assert (contact);
94
95 contact->rc++;
96}
97
98
99enum GNUNET_GenericReturnValue
100decrease_contact_rc (struct GNUNET_MESSENGER_Contact *contact)
101{
102 GNUNET_assert (contact);
103
104 if (contact->rc > 0)
105 contact->rc--;
106
107 return contact->rc ? GNUNET_NO : GNUNET_YES;
108}
109
110
111size_t
112get_contact_id (const struct GNUNET_MESSENGER_Contact *contact)
113{
114 GNUNET_assert (contact);
115
116 return contact->id;
117}
118
119
120void
121get_context_from_member (const struct GNUNET_HashCode *key,
122 const struct GNUNET_ShortHashCode *id,
123 struct GNUNET_HashCode *context)
124{
125 GNUNET_assert ((key) && (id) && (context));
126
127 GNUNET_CRYPTO_hash (id, sizeof(*id), context);
128 GNUNET_CRYPTO_hash_xor (key, context, context);
129}
diff --git a/src/service/messenger/messenger_api_contact.h b/src/service/messenger/messenger_api_contact.h
new file mode 100644
index 000000000..d3bb38e96
--- /dev/null
+++ b/src/service/messenger/messenger_api_contact.h
@@ -0,0 +1,126 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/messenger_api_contact.h
23 * @brief messenger api: client implementation of GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_MESSENGER_API_CONTACT_H
27#define GNUNET_MESSENGER_API_CONTACT_H
28
29#include "gnunet_util_lib.h"
30
31struct GNUNET_MESSENGER_Contact
32{
33 char *name;
34 size_t rc;
35 size_t id;
36
37 struct GNUNET_CRYPTO_PublicKey public_key;
38};
39
40/**
41 * Creates and allocates a new contact with a given public <i>key</i>.
42 *
43 * @param[in] key Public key
44 * @param[in] unique_id Locally unique identifier
45 * @return New contact
46 */
47struct GNUNET_MESSENGER_Contact*
48create_contact (const struct GNUNET_CRYPTO_PublicKey *key,
49 size_t unique_id);
50
51/**
52 * Destroys a contact and frees its memory fully.
53 *
54 * @param[in,out] contact Contact
55 */
56void
57destroy_contact (struct GNUNET_MESSENGER_Contact *contact);
58
59/**
60 * Returns the current name of a given <i>contact</i> or NULL if no valid name was assigned yet.
61 *
62 * @param[in] contact Contact
63 * @return Name of the contact or NULL
64 */
65const char*
66get_contact_name (const struct GNUNET_MESSENGER_Contact *contact);
67
68/**
69 * Changes the current name of a given <i>contact</i> by copying it from the parameter <i>name</i>.
70 *
71 * @param[in,out] contact Contact
72 * @param[in] name Name
73 */
74void
75set_contact_name (struct GNUNET_MESSENGER_Contact *contact,
76 const char *name);
77
78/**
79 * Returns the public key of a given <i>contact</i>.
80 *
81 * @param[in] contact Contact
82 * @return Public key of the contact
83 */
84const struct GNUNET_CRYPTO_PublicKey*
85get_contact_key (const struct GNUNET_MESSENGER_Contact *contact);
86
87/**
88 * Increases the reference counter of a given <i>contact</i> which is zero as default.
89 *
90 * @param[in,out] contact Contact
91 */
92void
93increase_contact_rc (struct GNUNET_MESSENGER_Contact *contact);
94
95/**
96 * Decreases the reference counter if possible (can not underflow!) of a given <i>contact</i>
97 * and returns #GNUNET_YES if the counter is equal to zero, otherwise #GNUNET_NO.
98 *
99 * @param[in,out] contact Contact
100 * @return #GNUNET_YES or #GNUNET_NO depending on the reference counter
101 */
102enum GNUNET_GenericReturnValue
103decrease_contact_rc (struct GNUNET_MESSENGER_Contact *contact);
104
105/**
106 * Returns the locally unique identifier of a given <i>contact</i>.
107 *
108 * @param[in] contact contact Contact
109 * @return Locally unique identifier of contact
110 */
111size_t
112get_contact_id (const struct GNUNET_MESSENGER_Contact *contact);
113
114/**
115 * Calculates the context <i>hash</i> of a member in a room and returns it.
116 *
117 * @param[in] key Key of room
118 * @param[in] id Member id
119 * @param[out] context Member context
120 */
121void
122get_context_from_member (const struct GNUNET_HashCode *key,
123 const struct GNUNET_ShortHashCode *id,
124 struct GNUNET_HashCode *context);
125
126#endif //GNUNET_MESSENGER_API_CONTACT_H
diff --git a/src/service/messenger/messenger_api_contact_store.c b/src/service/messenger/messenger_api_contact_store.c
new file mode 100644
index 000000000..081a8c6e9
--- /dev/null
+++ b/src/service/messenger/messenger_api_contact_store.c
@@ -0,0 +1,218 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2023 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/messenger_api_contact_store.c
23 * @brief messenger api: client implementation of GNUnet MESSENGER service
24 */
25
26#include "messenger_api_contact_store.h"
27
28#include "gnunet_common.h"
29#include "messenger_api_contact.h"
30#include "messenger_api_util.h"
31
32void
33init_contact_store (struct GNUNET_MESSENGER_ContactStore *store)
34{
35 GNUNET_assert (store);
36
37 store->anonymous = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
38 store->contacts = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
39
40 store->counter = 0;
41}
42
43
44static enum GNUNET_GenericReturnValue
45iterate_destroy_contacts (void *cls,
46 const struct GNUNET_HashCode *key,
47 void *value)
48{
49 struct GNUNET_MESSENGER_Contact *contact = value;
50 destroy_contact (contact);
51 return GNUNET_YES;
52}
53
54
55void
56clear_contact_store (struct GNUNET_MESSENGER_ContactStore *store)
57{
58 GNUNET_assert ((store) && (store->contacts));
59
60 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Clear contact store\n");
61
62 GNUNET_CONTAINER_multihashmap_iterate (store->anonymous,
63 iterate_destroy_contacts, NULL);
64 GNUNET_CONTAINER_multihashmap_iterate (store->contacts,
65 iterate_destroy_contacts, NULL);
66
67 GNUNET_CONTAINER_multihashmap_destroy (store->anonymous);
68 GNUNET_CONTAINER_multihashmap_destroy (store->contacts);
69}
70
71
72static struct GNUNET_CONTAINER_MultiHashMap*
73select_store_contact_map (struct GNUNET_MESSENGER_ContactStore *store,
74 const struct GNUNET_HashCode *context,
75 struct GNUNET_HashCode *hash)
76{
77 const struct GNUNET_CRYPTO_PublicKey *anonymous =
78 get_anonymous_public_key ();
79
80 struct GNUNET_HashCode anonHash;
81 GNUNET_CRYPTO_hash (anonymous, sizeof(*anonymous), &anonHash);
82
83 if ((context) && (0 == GNUNET_CRYPTO_hash_cmp (hash, &anonHash)))
84 {
85 GNUNET_memcpy (hash, context, sizeof(*context));
86 return store->anonymous;
87 }
88 else
89 return store->contacts;
90}
91
92
93struct GNUNET_MESSENGER_Contact*
94get_store_contact_raw (struct GNUNET_MESSENGER_ContactStore *store,
95 const struct GNUNET_HashCode *context,
96 const struct GNUNET_HashCode *key_hash)
97{
98 GNUNET_assert ((store) && (store->contacts) && (context) && (key_hash));
99
100 struct GNUNET_HashCode hash;
101 GNUNET_memcpy (&hash, key_hash, sizeof(*key_hash));
102
103 struct GNUNET_CONTAINER_MultiHashMap *map = select_store_contact_map (
104 store, context, &hash
105 );
106
107 return GNUNET_CONTAINER_multihashmap_get (map, &hash);
108}
109
110
111struct GNUNET_MESSENGER_Contact*
112get_store_contact (struct GNUNET_MESSENGER_ContactStore *store,
113 const struct GNUNET_HashCode *context,
114 const struct GNUNET_CRYPTO_PublicKey *pubkey)
115{
116 GNUNET_assert ((store) && (store->contacts) && (pubkey));
117
118 struct GNUNET_HashCode hash;
119 GNUNET_CRYPTO_hash (pubkey, sizeof(*pubkey), &hash);
120
121 struct GNUNET_CONTAINER_MultiHashMap *map = select_store_contact_map (
122 store, context, &hash);
123
124 struct GNUNET_MESSENGER_Contact *contact = GNUNET_CONTAINER_multihashmap_get (
125 map, &hash);
126
127 if (contact)
128 {
129 if (0 != GNUNET_memcmp (pubkey, get_contact_key (contact)))
130 {
131 char *str = GNUNET_CRYPTO_public_key_to_string (get_contact_key (
132 contact));
133 GNUNET_log (GNUNET_ERROR_TYPE_INVALID,
134 "Contact in store uses wrong key: %s\n", str);
135 GNUNET_free (str);
136 return NULL;
137 }
138
139 return contact;
140 }
141
142 contact = create_contact (pubkey, ++(store->counter));
143
144 if (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (map, &hash, contact,
145 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
146
147 return contact;
148
149 destroy_contact (contact);
150 return NULL;
151}
152
153
154void
155update_store_contact (struct GNUNET_MESSENGER_ContactStore *store,
156 struct GNUNET_MESSENGER_Contact *contact,
157 const struct GNUNET_HashCode *context,
158 const struct GNUNET_HashCode *next_context,
159 const struct GNUNET_CRYPTO_PublicKey *pubkey)
160{
161 GNUNET_assert ((store) && (store->contacts) && (contact) && (pubkey));
162
163 const struct GNUNET_CRYPTO_PublicKey *oldkey = get_contact_key (contact);
164
165 struct GNUNET_HashCode hash;
166 GNUNET_CRYPTO_hash (oldkey, sizeof(*oldkey), &hash);
167
168 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Update contact store entry: %s\n",
169 GNUNET_h2s (&hash));
170
171 struct GNUNET_CONTAINER_MultiHashMap *map = select_store_contact_map (
172 store, context, &hash
173 );
174
175 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (map, &hash, contact))
176 {
177 GNUNET_memcpy (&(contact->public_key), pubkey, sizeof(*pubkey));
178
179 GNUNET_CRYPTO_hash (pubkey, sizeof(*pubkey), &hash);
180
181 map = select_store_contact_map (
182 store, next_context, &hash
183 );
184
185 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (map, &hash, contact,
186 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
187
188 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Updating a contact failed: %s\n",
189 GNUNET_h2s (&hash));
190 }
191}
192
193
194void
195remove_store_contact (struct GNUNET_MESSENGER_ContactStore *store,
196 struct GNUNET_MESSENGER_Contact *contact,
197 const struct GNUNET_HashCode *context)
198{
199 GNUNET_assert ((store) && (store->contacts) && (contact));
200
201 const struct GNUNET_CRYPTO_PublicKey *pubkey = get_contact_key (contact);
202
203 struct GNUNET_HashCode hash;
204 GNUNET_CRYPTO_hash (pubkey, sizeof(*pubkey), &hash);
205
206 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Remove contact store entry: %s\n",
207 GNUNET_h2s (&hash));
208
209 struct GNUNET_CONTAINER_MultiHashMap *map = select_store_contact_map (
210 store, context, &hash
211 );
212
213 if (GNUNET_YES != GNUNET_CONTAINER_multihashmap_remove (map, &hash, contact))
214 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Removing a contact failed: %s\n",
215 GNUNET_h2s (&hash));
216
217 destroy_contact (contact);
218}
diff --git a/src/service/messenger/messenger_api_contact_store.h b/src/service/messenger/messenger_api_contact_store.h
new file mode 100644
index 000000000..6b61f3e4f
--- /dev/null
+++ b/src/service/messenger/messenger_api_contact_store.h
@@ -0,0 +1,126 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/messenger_api_contact_store.h
23 * @brief messenger api: client implementation of GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_MESSENGER_API_CONTACT_STORE_H
27#define GNUNET_MESSENGER_API_CONTACT_STORE_H
28
29#include "gnunet_util_lib.h"
30
31struct GNUNET_MESSENGER_Contact;
32
33struct GNUNET_MESSENGER_ContactStore
34{
35 struct GNUNET_CONTAINER_MultiHashMap *anonymous;
36 struct GNUNET_CONTAINER_MultiHashMap *contacts;
37
38 size_t counter;
39};
40
41/**
42 * Initializes a contact store as fully empty.
43 *
44 * @param[out] store Contact store
45 */
46void
47init_contact_store (struct GNUNET_MESSENGER_ContactStore *store);
48
49/**
50 * Clears a contact store, wipes its content and deallocates its memory.
51 *
52 * @param[in,out] store Contact store
53 */
54void
55clear_contact_store (struct GNUNET_MESSENGER_ContactStore *store);
56
57/**
58 * Returns a contact using the hash of a specific public key. In case the anonymous
59 * key gets used by the requested contact, it will use its provided member
60 * <i>context</i> to select the matching contact from the <i>store</i>.
61 *
62 * In case there is no contact stored which uses the given key or context,
63 * NULL gets returned.
64 *
65 * @param[in,out] store Contact store
66 * @param[in] context Member context
67 * @param[in] key_hash Hash of public key
68 */
69struct GNUNET_MESSENGER_Contact*
70get_store_contact_raw (struct GNUNET_MESSENGER_ContactStore *store,
71 const struct GNUNET_HashCode *context,
72 const struct GNUNET_HashCode *key_hash);
73
74/**
75 * Returns a contact using a specific public key. In case the anonymous
76 * key gets used by the requested contact, it will use its provided member
77 * <i>context</i> to select the matching contact from the <i>store</i>.
78 *
79 * In case there is no contact stored which uses the given key or context,
80 * a new contact will be created automatically.
81 *
82 * The function returns NULL if an error occurs during allocation
83 * or validation of the contacts key.
84 *
85 * @param[in,out] store Contact store
86 * @param[in] context Member context
87 * @param[in] pubkey Public key
88 */
89struct GNUNET_MESSENGER_Contact*
90get_store_contact (struct GNUNET_MESSENGER_ContactStore *store,
91 const struct GNUNET_HashCode *context,
92 const struct GNUNET_CRYPTO_PublicKey *pubkey);
93
94/**
95 * Moves a <i>contact</i> from the <i>store</i> to another location
96 * matching a given public key and member <i>context</i>.
97 *
98 * This function allows changes of keys or changes of member contexts!
99 *
100 * @param[in,out] store Contact store
101 * @param[in,out] contact Contact
102 * @param[in] context Member context
103 * @param[in] next_context Member context
104 * @param[in] pubkey Public key
105 */
106void
107update_store_contact (struct GNUNET_MESSENGER_ContactStore *store,
108 struct GNUNET_MESSENGER_Contact *contact,
109 const struct GNUNET_HashCode *context,
110 const struct GNUNET_HashCode *next_context,
111 const struct GNUNET_CRYPTO_PublicKey *pubkey);
112
113/**
114 * Removes a <i>contact</i> from the <i>store</i> which uses
115 * a given member <i>context</i>.
116 *
117 * @param[in,out] store Contact store
118 * @param[in,out] contact Contact
119 * @param[in] context Member context
120 */
121void
122remove_store_contact (struct GNUNET_MESSENGER_ContactStore *store,
123 struct GNUNET_MESSENGER_Contact *contact,
124 const struct GNUNET_HashCode *context);
125
126#endif //GNUNET_MESSENGER_API_CONTACT_STORE_H
diff --git a/src/service/messenger/messenger_api_handle.c b/src/service/messenger/messenger_api_handle.c
new file mode 100644
index 000000000..1cf2bccf0
--- /dev/null
+++ b/src/service/messenger/messenger_api_handle.c
@@ -0,0 +1,270 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2023 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/messenger_api_handle.c
23 * @brief messenger api: client implementation of GNUnet MESSENGER service
24 */
25
26#include "messenger_api_handle.h"
27
28#include "messenger_api_room.h"
29#include "messenger_api_util.h"
30
31struct GNUNET_MESSENGER_Handle*
32create_handle (const struct GNUNET_CONFIGURATION_Handle *cfg,
33 GNUNET_MESSENGER_MessageCallback msg_callback,
34 void *msg_cls)
35{
36 GNUNET_assert (cfg);
37
38 struct GNUNET_MESSENGER_Handle *handle = GNUNET_new (struct
39 GNUNET_MESSENGER_Handle);
40
41 handle->cfg = cfg;
42 handle->mq = NULL;
43
44 handle->msg_callback = msg_callback;
45 handle->msg_cls = msg_cls;
46
47 handle->name = NULL;
48 handle->key = NULL;
49 handle->pubkey = NULL;
50
51 handle->reconnect_time = GNUNET_TIME_relative_get_zero_ ();
52 handle->reconnect_task = NULL;
53
54 handle->rooms = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
55
56 init_contact_store (get_handle_contact_store (handle));
57
58 return handle;
59}
60
61
62static enum GNUNET_GenericReturnValue
63iterate_destroy_room (void *cls,
64 const struct GNUNET_HashCode *key,
65 void *value)
66{
67 struct GNUNET_MESSENGER_Room *room = value;
68
69 destroy_room (room);
70
71 return GNUNET_YES;
72}
73
74
75void
76destroy_handle (struct GNUNET_MESSENGER_Handle *handle)
77{
78 GNUNET_assert (handle);
79
80 clear_contact_store (get_handle_contact_store (handle));
81
82 if (handle->rooms)
83 {
84 GNUNET_CONTAINER_multihashmap_iterate (handle->rooms, iterate_destroy_room,
85 NULL);
86
87 GNUNET_CONTAINER_multihashmap_destroy (handle->rooms);
88 }
89
90 if (handle->reconnect_task)
91 GNUNET_SCHEDULER_cancel (handle->reconnect_task);
92
93 if (handle->mq)
94 GNUNET_MQ_destroy (handle->mq);
95
96 if (handle->name)
97 GNUNET_free (handle->name);
98
99 if (handle->key)
100 GNUNET_free (handle->key);
101
102 if (handle->pubkey)
103 GNUNET_free (handle->pubkey);
104
105 GNUNET_free (handle);
106}
107
108
109void
110set_handle_name (struct GNUNET_MESSENGER_Handle *handle,
111 const char *name)
112{
113 GNUNET_assert (handle);
114
115 if (handle->name)
116 GNUNET_free (handle->name);
117
118 handle->name = name ? GNUNET_strdup (name) : NULL;
119}
120
121
122const char*
123get_handle_name (const struct GNUNET_MESSENGER_Handle *handle)
124{
125 GNUNET_assert (handle);
126
127 return handle->name;
128}
129
130
131void
132set_handle_key (struct GNUNET_MESSENGER_Handle *handle,
133 const struct GNUNET_CRYPTO_PrivateKey *key)
134{
135 GNUNET_assert (handle);
136
137 if (! key)
138 {
139 if (handle->key)
140 GNUNET_free (handle->key);
141
142 if (handle->pubkey)
143 GNUNET_free (handle->pubkey);
144
145 handle->key = NULL;
146 handle->pubkey = NULL;
147 return;
148 }
149
150 if (! handle->key)
151 handle->key = GNUNET_new (struct GNUNET_CRYPTO_PrivateKey);
152
153 if (! handle->pubkey)
154 handle->pubkey = GNUNET_new (struct GNUNET_CRYPTO_PublicKey);
155
156 GNUNET_memcpy (handle->key, key, sizeof(*key));
157 GNUNET_CRYPTO_key_get_public (key, handle->pubkey);
158}
159
160
161const struct GNUNET_CRYPTO_PrivateKey*
162get_handle_key (const struct GNUNET_MESSENGER_Handle *handle)
163{
164 GNUNET_assert (handle);
165
166 if (handle->key)
167 return handle->key;
168
169 return get_anonymous_private_key ();
170}
171
172
173const struct GNUNET_CRYPTO_PublicKey*
174get_handle_pubkey (const struct GNUNET_MESSENGER_Handle *handle)
175{
176 GNUNET_assert (handle);
177
178 if (handle->pubkey)
179 return handle->pubkey;
180
181 return get_anonymous_public_key ();
182}
183
184
185struct GNUNET_MESSENGER_ContactStore*
186get_handle_contact_store (struct GNUNET_MESSENGER_Handle *handle)
187{
188 GNUNET_assert (handle);
189
190 return &(handle->contact_store);
191}
192
193
194struct GNUNET_MESSENGER_Contact*
195get_handle_contact (struct GNUNET_MESSENGER_Handle *handle,
196 const struct GNUNET_HashCode *key)
197{
198 GNUNET_assert ((handle) && (key));
199
200 struct GNUNET_MESSENGER_Room *room = GNUNET_CONTAINER_multihashmap_get (
201 handle->rooms, key);
202
203 if (! room)
204 return NULL;
205
206 const struct GNUNET_ShortHashCode *contact_id = get_room_sender_id (room);
207
208 if (! contact_id)
209 return NULL;
210
211 struct GNUNET_HashCode context;
212 get_context_from_member (key, contact_id, &context);
213
214 return get_store_contact (get_handle_contact_store (handle), &context,
215 get_handle_pubkey (handle));
216}
217
218
219void
220open_handle_room (struct GNUNET_MESSENGER_Handle *handle,
221 const struct GNUNET_HashCode *key)
222{
223 GNUNET_assert ((handle) && (key));
224
225 struct GNUNET_MESSENGER_Room *room = GNUNET_CONTAINER_multihashmap_get (
226 handle->rooms, key);
227
228 if (room)
229 room->opened = GNUNET_YES;
230}
231
232
233void
234entry_handle_room_at (struct GNUNET_MESSENGER_Handle *handle,
235 const struct GNUNET_PeerIdentity *door,
236 const struct GNUNET_HashCode *key)
237{
238 GNUNET_assert ((handle) && (door) && (key));
239
240 struct GNUNET_MESSENGER_Room *room = GNUNET_CONTAINER_multihashmap_get (
241 handle->rooms, key);
242
243 if (room)
244 add_to_list_tunnels (&(room->entries), door, NULL);
245}
246
247
248void
249close_handle_room (struct GNUNET_MESSENGER_Handle *handle,
250 const struct GNUNET_HashCode *key)
251{
252 GNUNET_assert ((handle) && (key));
253
254 struct GNUNET_MESSENGER_Room *room = GNUNET_CONTAINER_multihashmap_get (
255 handle->rooms, key);
256
257 if ((room) && (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (
258 handle->rooms, key, room)))
259 destroy_room (room);
260}
261
262
263struct GNUNET_MESSENGER_Room*
264get_handle_room (struct GNUNET_MESSENGER_Handle *handle,
265 const struct GNUNET_HashCode *key)
266{
267 GNUNET_assert ((handle) && (key));
268
269 return GNUNET_CONTAINER_multihashmap_get (handle->rooms, key);
270}
diff --git a/src/service/messenger/messenger_api_handle.h b/src/service/messenger/messenger_api_handle.h
new file mode 100644
index 000000000..1a2763020
--- /dev/null
+++ b/src/service/messenger/messenger_api_handle.h
@@ -0,0 +1,190 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/messenger_api_handle.h
23 * @brief messenger api: client implementation of GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_MESSENGER_API_HANDLE_H
27#define GNUNET_MESSENGER_API_HANDLE_H
28
29#include "gnunet_util_lib.h"
30
31#include "gnunet_messenger_service.h"
32
33#include "messenger_api_contact_store.h"
34
35struct GNUNET_MESSENGER_Handle
36{
37 const struct GNUNET_CONFIGURATION_Handle *cfg;
38
39 struct GNUNET_MQ_Handle *mq;
40
41 GNUNET_MESSENGER_MessageCallback msg_callback;
42 void *msg_cls;
43
44 char *name;
45 struct GNUNET_CRYPTO_PrivateKey *key;
46 struct GNUNET_CRYPTO_PublicKey *pubkey;
47
48 struct GNUNET_TIME_Relative reconnect_time;
49 struct GNUNET_SCHEDULER_Task *reconnect_task;
50
51 struct GNUNET_MESSENGER_ContactStore contact_store;
52
53 struct GNUNET_CONTAINER_MultiHashMap *rooms;
54};
55
56/**
57 * Creates and allocates a new handle using a given configuration and a custom message callback
58 * with a given closure for the client API.
59 *
60 * @param[in] cfg Configuration
61 * @param[in] msg_callback Message callback
62 * @param[in,out] msg_cls Closure
63 * @return New handle
64 */
65struct GNUNET_MESSENGER_Handle*
66create_handle (const struct GNUNET_CONFIGURATION_Handle *cfg,
67 GNUNET_MESSENGER_MessageCallback msg_callback,
68 void *msg_cls);
69
70/**
71 * Destroys a <i>handle</i> and frees its memory fully from the client API.
72 *
73 * @param[in,out] handle Handle
74 */
75void
76destroy_handle (struct GNUNET_MESSENGER_Handle *handle);
77
78/**
79 * Sets the name of a <i>handle</i> to a specific <i>name</i>.
80 *
81 * @param[in,out] handle Handle
82 * @param[in] name New name
83 */
84void
85set_handle_name (struct GNUNET_MESSENGER_Handle *handle,
86 const char *name);
87
88/**
89 * Returns the current name of a given <i>handle</i> or NULL if no valid name was assigned yet.
90 *
91 * @param[in] handle Handle
92 * @return Name of the handle or NULL
93 */
94const char*
95get_handle_name (const struct GNUNET_MESSENGER_Handle *handle);
96
97/**
98 * Sets the keypair of a given <i>handle</i> to the keypair of a specific private <i>key</i>.
99 *
100 * @param[in,out] handle Handle
101 * @param[in] key Private key or NULL
102 */
103void
104set_handle_key (struct GNUNET_MESSENGER_Handle *handle,
105 const struct GNUNET_CRYPTO_PrivateKey *key);
106
107/**
108 * Returns the private key of a given <i>handle</i>.
109 *
110 * @param[in] handle Handle
111 * @return Private key of the handle
112 */
113const struct GNUNET_CRYPTO_PrivateKey*
114get_handle_key (const struct GNUNET_MESSENGER_Handle *handle);
115
116/**
117 * Returns the public key of a given <i>handle</i>.
118 *
119 * @param[in] handle Handle
120 * @return Public key of the handle
121 */
122const struct GNUNET_CRYPTO_PublicKey*
123get_handle_pubkey (const struct GNUNET_MESSENGER_Handle *handle);
124
125/**
126 * Returns the used contact store of a given <i>handle</i>.
127 *
128 * @param[in,out] handle Handle
129 * @return Contact store
130 */
131struct GNUNET_MESSENGER_ContactStore*
132get_handle_contact_store (struct GNUNET_MESSENGER_Handle *handle);
133
134/**
135 * Returns the contact of a given <i>handle</i> in a room identified by a
136 * given <i>key</i>.
137 *
138 * @param[in,out] handle Handle
139 * @param[in] key Key of room
140 * @return Contact
141 */
142struct GNUNET_MESSENGER_Contact*
143get_handle_contact (struct GNUNET_MESSENGER_Handle *handle,
144 const struct GNUNET_HashCode *key);
145
146/**
147 * Marks a room known to a <i>handle</i> identified by a given <i>key</i> as open.
148 *
149 * @param[in,out] handle Handle
150 * @param[in] key Key of room
151 */
152void
153open_handle_room (struct GNUNET_MESSENGER_Handle *handle,
154 const struct GNUNET_HashCode *key);
155
156/**
157 * Adds a tunnel for a room known to a <i>handle</i> identified by a given <i>key</i> to a
158 * list of opened connections.
159 *
160 * @param[in,out] handle Handle
161 * @param[in] door Peer identity
162 * @param[in] key Key of room
163 */
164void
165entry_handle_room_at (struct GNUNET_MESSENGER_Handle *handle,
166 const struct GNUNET_PeerIdentity *door,
167 const struct GNUNET_HashCode *key);
168
169/**
170 * Destroys and so implicitly closes a room known to a <i>handle</i> identified by a given <i>key</i>.
171 *
172 * @param[in,out] handle Handle
173 * @param[in] key Key of room
174 */
175void
176close_handle_room (struct GNUNET_MESSENGER_Handle *handle,
177 const struct GNUNET_HashCode *key);
178
179/**
180 * Returns the room known to a <i>handle</i> identified by a given <i>key</i>.
181 *
182 * @param[in,out] handle handle Handle
183 * @param[in] key Key of room
184 * @return Room or NULL
185 */
186struct GNUNET_MESSENGER_Room*
187get_handle_room (struct GNUNET_MESSENGER_Handle *handle,
188 const struct GNUNET_HashCode *key);
189
190#endif //GNUNET_MESSENGER_API_HANDLE_H
diff --git a/src/service/messenger/messenger_api_list_tunnels.c b/src/service/messenger/messenger_api_list_tunnels.c
new file mode 100644
index 000000000..bb500233b
--- /dev/null
+++ b/src/service/messenger/messenger_api_list_tunnels.c
@@ -0,0 +1,298 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/messenger_api_list_tunnels.c
23 * @brief messenger api: client and service implementation of GNUnet MESSENGER service
24 */
25
26#include "messenger_api_list_tunnels.h"
27
28void
29init_list_tunnels (struct GNUNET_MESSENGER_ListTunnels *tunnels)
30{
31 GNUNET_assert (tunnels);
32
33 tunnels->head = NULL;
34 tunnels->tail = NULL;
35}
36
37
38void
39clear_list_tunnels (struct GNUNET_MESSENGER_ListTunnels *tunnels)
40{
41 GNUNET_assert (tunnels);
42
43 struct GNUNET_MESSENGER_ListTunnel *element;
44 for (element = tunnels->head; element;
45 element = remove_from_list_tunnels (tunnels, element))
46
47 tunnels->head = NULL;
48 tunnels->tail = NULL;
49}
50
51
52static int
53compare_list_tunnels (void *cls,
54 struct GNUNET_MESSENGER_ListTunnel *element0,
55 struct GNUNET_MESSENGER_ListTunnel *element1)
56{
57 struct GNUNET_PeerIdentity peer0, peer1;
58
59 GNUNET_PEER_resolve (element0->peer, &peer0);
60 GNUNET_PEER_resolve (element1->peer, &peer1);
61
62 return GNUNET_memcmp (&peer0, &peer1);
63}
64
65
66void
67add_to_list_tunnels (struct GNUNET_MESSENGER_ListTunnels *tunnels,
68 const struct GNUNET_PeerIdentity *peer,
69 const struct GNUNET_HashCode *hash)
70{
71 GNUNET_assert ((tunnels) && (peer));
72
73 struct GNUNET_MESSENGER_ListTunnel *element = GNUNET_new (struct
74 GNUNET_MESSENGER_ListTunnel);
75
76 element->peer = GNUNET_PEER_intern (peer);
77 element->hash = hash ? GNUNET_memdup (hash, sizeof (struct GNUNET_HashCode)) :
78 NULL;
79
80 memset (&(element->connection), 0, sizeof (element->connection));
81
82 GNUNET_CONTAINER_DLL_insert_sorted (struct GNUNET_MESSENGER_ListTunnel,
83 compare_list_tunnels, NULL, tunnels->head,
84 tunnels->tail, element);
85}
86
87
88struct GNUNET_MESSENGER_ListTunnel*
89find_list_tunnels (struct GNUNET_MESSENGER_ListTunnels *tunnels,
90 const struct GNUNET_PeerIdentity *peer,
91 size_t *index)
92{
93 GNUNET_assert ((tunnels) && (peer));
94
95 struct GNUNET_MESSENGER_ListTunnel *element;
96 struct GNUNET_PeerIdentity pid;
97
98 if (index)
99 *index = 0;
100
101 for (element = tunnels->head; element; element = element->next)
102 {
103 GNUNET_PEER_resolve (element->peer, &pid);
104
105 if (0 == GNUNET_memcmp (&pid, peer))
106 return element;
107
108 if (index)
109 (*index) = (*index) + 1;
110 }
111
112 return NULL;
113}
114
115
116struct GNUNET_MESSENGER_ListTunnel*
117find_list_tunnels_alternate (struct GNUNET_MESSENGER_ListTunnels *tunnels,
118 const struct GNUNET_PeerIdentity *peer)
119{
120 GNUNET_assert ((tunnels) && (peer));
121
122 struct GNUNET_MESSENGER_ListTunnel *element;
123 struct GNUNET_PeerIdentity pid;
124
125 for (element = tunnels->head; element; element = element->next)
126 {
127 GNUNET_PEER_resolve (element->peer, &pid);
128
129 if (0 != GNUNET_memcmp (&pid, peer))
130 return element;
131 }
132
133 return NULL;
134}
135
136
137enum GNUNET_GenericReturnValue
138verify_list_tunnels_flag_token (const struct
139 GNUNET_MESSENGER_ListTunnels *tunnels,
140 const struct GNUNET_PeerIdentity *peer,
141 enum GNUNET_MESSENGER_ConnectionFlags flag)
142{
143 GNUNET_assert ((tunnels) && (peer) && (flag));
144
145 struct GNUNET_MESSENGER_ListTunnel *element;
146 struct GNUNET_PeerIdentity pid;
147
148 for (element = tunnels->head; element; element = element->next)
149 {
150 if ((element->connection.flags & flag) != flag)
151 continue;
152
153 GNUNET_PEER_resolve (element->peer, &pid);
154
155 if (0 == GNUNET_memcmp (&pid, peer))
156 return GNUNET_OK;
157 }
158
159 return GNUNET_SYSERR;
160}
161
162
163void
164update_to_list_tunnels (struct GNUNET_MESSENGER_ListTunnels *tunnels,
165 const struct GNUNET_PeerIdentity *peer,
166 const struct GNUNET_HashCode *hash)
167{
168 GNUNET_assert ((tunnels) && (peer));
169
170 struct GNUNET_MESSENGER_ListTunnel *element = find_list_tunnels (tunnels,
171 peer,
172 NULL);
173 if (! element)
174 return;
175
176 if (element->hash)
177 {
178 if (hash)
179 GNUNET_memcpy (element->hash, hash, sizeof(struct GNUNET_HashCode));
180 else
181 {
182 GNUNET_free (element->hash);
183 element->hash = NULL;
184 }
185 }
186 else if (hash)
187 element->hash = GNUNET_memdup (hash, sizeof(struct GNUNET_HashCode));
188}
189
190
191enum GNUNET_GenericReturnValue
192contains_list_tunnels (struct GNUNET_MESSENGER_ListTunnels *tunnels,
193 const struct GNUNET_PeerIdentity *peer)
194{
195 GNUNET_assert ((tunnels) && (peer));
196
197 return find_list_tunnels (tunnels, peer, NULL) != NULL ? GNUNET_YES :
198 GNUNET_NO;
199}
200
201
202struct GNUNET_MESSENGER_ListTunnel*
203remove_from_list_tunnels (struct GNUNET_MESSENGER_ListTunnels *tunnels,
204 struct GNUNET_MESSENGER_ListTunnel *element)
205{
206 GNUNET_assert ((tunnels) && (element));
207
208 struct GNUNET_MESSENGER_ListTunnel *next = element->next;
209
210 if ((tunnels->head) && (tunnels->tail))
211 GNUNET_CONTAINER_DLL_remove (tunnels->head, tunnels->tail, element);
212
213 if (element->hash)
214 GNUNET_free (element->hash);
215
216 GNUNET_PEER_change_rc (element->peer, -1);
217 GNUNET_free (element);
218
219 return next;
220}
221
222
223void
224load_list_tunnels (struct GNUNET_MESSENGER_ListTunnels *tunnels,
225 const char *path)
226{
227 GNUNET_assert ((tunnels) && (path));
228
229 if (GNUNET_YES != GNUNET_DISK_file_test (path))
230 return;
231
232 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Load list of tunnels from path: %s\n",
233 path);
234
235 enum GNUNET_DISK_AccessPermissions permission = (GNUNET_DISK_PERM_USER_READ
236 | GNUNET_DISK_PERM_USER_WRITE
237 );
238
239 struct GNUNET_DISK_FileHandle *handle = GNUNET_DISK_file_open (
240 path, GNUNET_DISK_OPEN_READ, permission
241 );
242
243 if (! handle)
244 return;
245
246 GNUNET_DISK_file_seek (handle, 0, GNUNET_DISK_SEEK_SET);
247
248 struct GNUNET_PeerIdentity peer;
249 ssize_t len;
250
251 do {
252 len = GNUNET_DISK_file_read (handle, &peer, sizeof(peer));
253
254 if (len != sizeof(peer))
255 break;
256
257 add_to_list_tunnels (tunnels, &peer, NULL);
258 } while (len == sizeof(peer));
259
260 GNUNET_DISK_file_close (handle);
261}
262
263
264void
265save_list_tunnels (struct GNUNET_MESSENGER_ListTunnels *tunnels,
266 const char *path)
267{
268 GNUNET_assert ((tunnels) && (path));
269
270 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Save list of tunnels to path: %s\n",
271 path);
272
273 enum GNUNET_DISK_AccessPermissions permission = (GNUNET_DISK_PERM_USER_READ
274 | GNUNET_DISK_PERM_USER_WRITE
275 );
276
277 struct GNUNET_DISK_FileHandle *handle = GNUNET_DISK_file_open (
278 path, GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_WRITE, permission
279 );
280
281 if (! handle)
282 return;
283
284 GNUNET_DISK_file_seek (handle, 0, GNUNET_DISK_SEEK_SET);
285
286 struct GNUNET_MESSENGER_ListTunnel *element;
287 struct GNUNET_PeerIdentity pid;
288
289 for (element = tunnels->head; element; element = element->next)
290 {
291 GNUNET_PEER_resolve (element->peer, &pid);
292
293 GNUNET_DISK_file_write (handle, &pid, sizeof(pid));
294 }
295
296 GNUNET_DISK_file_sync (handle);
297 GNUNET_DISK_file_close (handle);
298}
diff --git a/src/service/messenger/messenger_api_list_tunnels.h b/src/service/messenger/messenger_api_list_tunnels.h
new file mode 100644
index 000000000..e4b709c3b
--- /dev/null
+++ b/src/service/messenger/messenger_api_list_tunnels.h
@@ -0,0 +1,187 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2023 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/messenger_api_list_tunnels.h
23 * @brief messenger api: client and service implementation of GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_MESSENGER_API_LIST_TUNNELS_H
27#define GNUNET_MESSENGER_API_LIST_TUNNELS_H
28
29#include "gnunet_messenger_service.h"
30#include "gnunet_util_lib.h"
31
32struct GNUNET_MESSENGER_ListTunnel
33{
34 struct GNUNET_MESSENGER_ListTunnel *prev;
35 struct GNUNET_MESSENGER_ListTunnel *next;
36
37 GNUNET_PEER_Id peer;
38 struct GNUNET_HashCode *hash;
39
40 struct GNUNET_MESSENGER_MessageConnection connection;
41};
42
43struct GNUNET_MESSENGER_ListTunnels
44{
45 struct GNUNET_MESSENGER_ListTunnel *head;
46 struct GNUNET_MESSENGER_ListTunnel *tail;
47};
48
49/**
50 * Initializes list of tunnels peer identities as empty list.
51 *
52 * @param[out] tunnels List of tunnels
53 */
54void
55init_list_tunnels (struct GNUNET_MESSENGER_ListTunnels *tunnels);
56
57/**
58 * Clears the list of tunnels peer identities.
59 *
60 * @param[in,out] tunnels List of tunnels
61 */
62void
63clear_list_tunnels (struct GNUNET_MESSENGER_ListTunnels *tunnels);
64
65/**
66 * Adds a specific <i>peer</i> from a tunnel to the end of the list.
67 *
68 * Optionally adds the <i>hash</i> of the peer message from the specific <i>peer</i>.
69 *
70 * @param[in,out] tunnels List of tunnels
71 * @param[in] peer Peer identity of tunnel
72 * @param[in] hash Hash of peer message or NULL
73 */
74void
75add_to_list_tunnels (struct GNUNET_MESSENGER_ListTunnels *tunnels,
76 const struct GNUNET_PeerIdentity *peer,
77 const struct GNUNET_HashCode *hash);
78
79/**
80 * Searches linearly through the list of tunnels peer identities for matching a
81 * specific <i>peer</i> identity and returns the matching element of the list.
82 *
83 * If no matching element is found, NULL gets returned.
84 *
85 * If <i>index</i> is not NULL, <i>index</i> will be overridden with the numeric index of
86 * the found element in the list. If no matching element is found, <i>index</i> will
87 * contain the total amount of elements in the list.
88 *
89 * @param[in,out] tunnels List of tunnels
90 * @param[in] peer Peer identity of tunnel
91 * @param[out] index Index of found element (optional)
92 * @return Element in the list with matching peer identity
93 */
94struct GNUNET_MESSENGER_ListTunnel*
95find_list_tunnels (struct GNUNET_MESSENGER_ListTunnels *tunnels,
96 const struct GNUNET_PeerIdentity *peer,
97 size_t *index);
98
99/**
100 * Searches linearly through the list of tunnels peer identities for matching
101 * against a specific <i>peer</i> identity and returns an element of the list
102 * which does not match it.
103 *
104 * @param[in,out] tunnels List of tunnels
105 * @param[in] peer Peer identity of tunnel
106 * @return Element in the list with unmatching peer identity
107 */
108struct GNUNET_MESSENGER_ListTunnel*
109find_list_tunnels_alternate (struct GNUNET_MESSENGER_ListTunnels *tunnels,
110 const struct GNUNET_PeerIdentity *peer);
111
112/**
113 * Verifies that a specific tunnel selected by its <i>peer</i> identity in a
114 * list of <i>tunnels</i> is the first in order with a given connection <i>flag</i>.
115 *
116 * @param[in] tunnels List of tunnels
117 * @param[in] peer Peer identity of tunnel
118 * @param[in] flag Connection flag mask
119 * @return #GNUNET_OK on success, otherwise #GNUNET_SYSERR
120 */
121enum GNUNET_GenericReturnValue
122verify_list_tunnels_flag_token (const struct
123 GNUNET_MESSENGER_ListTunnels *tunnels,
124 const struct GNUNET_PeerIdentity *peer,
125 enum GNUNET_MESSENGER_ConnectionFlags flag);
126
127/**
128 * Updates a specific <i>peer</i> from a tunnel in the list.
129 *
130 * This function exists to add the <i>hash</i> of a newer peer message
131 * from the specific <i>peer</i> to the list element. It can also remove
132 * the hash when NULL is provided as new <i>hash</i> value.
133 *
134 * @param[in,out] tunnels List of tunnels
135 * @param[in] peer Peer identity of tunnel
136 * @param[in] hash Hash of peer message or NULL
137 */
138void
139update_to_list_tunnels (struct GNUNET_MESSENGER_ListTunnels *tunnels,
140 const struct GNUNET_PeerIdentity *peer,
141 const struct GNUNET_HashCode *hash);
142
143/**
144 * Tests linearly if the list of tunnels peer identities contains a specific
145 * <i>peer</i> identity and returns #GNUNET_YES on success, otherwise #GNUNET_NO.
146 *
147 * @param[in,out] tunnels List of tunnels
148 * @param[in] peer Peer identity of tunnel
149 * @return #GNUNET_YES on success, otherwise #GNUNET_NO
150 */
151enum GNUNET_GenericReturnValue
152contains_list_tunnels (struct GNUNET_MESSENGER_ListTunnels *tunnels,
153 const struct GNUNET_PeerIdentity *peer);
154
155/**
156 * Removes a specific <i>element</i> from the list of tunnels peer identities and returns
157 * the next element in the list.
158 *
159 * @param[in,out] tunnels List of tunnels
160 * @param[in,out] element Element of the list
161 * @return Next element in the list
162 */
163struct GNUNET_MESSENGER_ListTunnel*
164remove_from_list_tunnels (struct GNUNET_MESSENGER_ListTunnels *tunnels,
165 struct GNUNET_MESSENGER_ListTunnel *element);
166
167/**
168 * Loads the list of tunnels peer identities from a file under a given <i>path</i>.
169 *
170 * @param[out] tunnels List of tunnels
171 * @param[in] path Path of file
172 */
173void
174load_list_tunnels (struct GNUNET_MESSENGER_ListTunnels *tunnels,
175 const char *path);
176
177/**
178 * Saves the list of tunnels peer identities to a file under a given <i>path</i>.
179 *
180 * @param[in] tunnels List of tunnels
181 * @param[in] path Path of file
182 */
183void
184save_list_tunnels (struct GNUNET_MESSENGER_ListTunnels *tunnels,
185 const char *path);
186
187#endif //GNUNET_MESSENGER_API_LIST_TUNNELS_H
diff --git a/src/service/messenger/messenger_api_message.c b/src/service/messenger/messenger_api_message.c
new file mode 100644
index 000000000..fa281cb37
--- /dev/null
+++ b/src/service/messenger/messenger_api_message.c
@@ -0,0 +1,1380 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/messenger_api_message.c
23 * @brief messenger api: client and service implementation of GNUnet MESSENGER service
24 */
25
26#include "messenger_api_message.h"
27
28#include "gnunet_common.h"
29#include "gnunet_messenger_service.h"
30#include "gnunet_signatures.h"
31
32struct GNUNET_MESSENGER_MessageSignature
33{
34 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
35 struct GNUNET_HashCode hash GNUNET_PACKED;
36};
37
38struct GNUNET_MESSENGER_ShortMessage
39{
40 enum GNUNET_MESSENGER_MessageKind kind;
41 struct GNUNET_MESSENGER_MessageBody body;
42};
43
44struct GNUNET_MESSENGER_Message*
45create_message (enum GNUNET_MESSENGER_MessageKind kind)
46{
47 struct GNUNET_MESSENGER_Message *message = GNUNET_new (struct
48 GNUNET_MESSENGER_Message);
49
50 message->header.kind = kind;
51
52 switch (message->header.kind)
53 {
54 case GNUNET_MESSENGER_KIND_NAME:
55 message->body.name.name = NULL;
56 break;
57 case GNUNET_MESSENGER_KIND_TEXT:
58 message->body.text.text = NULL;
59 break;
60 case GNUNET_MESSENGER_KIND_FILE:
61 message->body.file.uri = NULL;
62 break;
63 case GNUNET_MESSENGER_KIND_PRIVATE:
64 message->body.privacy.length = 0;
65 message->body.privacy.data = NULL;
66 break;
67 case GNUNET_MESSENGER_KIND_TICKET:
68 message->body.ticket.identifier = NULL;
69 break;
70 case GNUNET_MESSENGER_KIND_TRANSCRIPT:
71 message->body.transcript.length = 0;
72 message->body.transcript.data = NULL;
73 break;
74 case GNUNET_MESSENGER_KIND_TAG:
75 message->body.tag.tag = NULL;
76 break;
77 default:
78 break;
79 }
80
81 return message;
82}
83
84
85struct GNUNET_MESSENGER_Message*
86copy_message (const struct GNUNET_MESSENGER_Message *message)
87{
88 GNUNET_assert (message);
89
90 struct GNUNET_MESSENGER_Message *copy = GNUNET_new (struct
91 GNUNET_MESSENGER_Message);
92
93 GNUNET_memcpy (copy, message, sizeof(struct GNUNET_MESSENGER_Message));
94
95 switch (message->header.kind)
96 {
97 case GNUNET_MESSENGER_KIND_NAME:
98 copy->body.name.name = message->body.name.name? GNUNET_strdup (
99 message->body.name.name) : NULL;
100 break;
101 case GNUNET_MESSENGER_KIND_TEXT:
102 copy->body.text.text = message->body.text.text? GNUNET_strdup (
103 message->body.text.text) : NULL;
104 break;
105 case GNUNET_MESSENGER_KIND_FILE:
106 copy->body.file.uri = message->body.file.uri? GNUNET_strdup (
107 message->body.file.uri) : NULL;
108 break;
109 case GNUNET_MESSENGER_KIND_PRIVATE:
110 copy->body.privacy.data = copy->body.privacy.length ? GNUNET_malloc (
111 copy->body.privacy.length) : NULL;
112
113 if (copy->body.privacy.data)
114 GNUNET_memcpy (copy->body.privacy.data, message->body.privacy.data,
115 copy->body.privacy.length);
116
117 break;
118 case GNUNET_MESSENGER_KIND_TICKET:
119 copy->body.ticket.identifier = message->body.ticket.identifier?
120 GNUNET_strdup (
121 message->body.ticket.identifier) : NULL;
122 break;
123 case GNUNET_MESSENGER_KIND_TRANSCRIPT:
124 copy->body.transcript.data = copy->body.transcript.length ? GNUNET_malloc (
125 copy->body.transcript.length) : NULL;
126
127 if (copy->body.transcript.data)
128 GNUNET_memcpy (copy->body.transcript.data, message->body.transcript.data,
129 copy->body.transcript.length);
130
131 break;
132 case GNUNET_MESSENGER_KIND_TAG:
133 copy->body.tag.tag = message->body.tag.tag? GNUNET_strdup (
134 message->body.tag.tag) : NULL;
135 break;
136 default:
137 break;
138 }
139
140 return copy;
141}
142
143
144void
145copy_message_header (struct GNUNET_MESSENGER_Message *message,
146 const struct GNUNET_MESSENGER_MessageHeader *header)
147{
148 GNUNET_assert ((message) && (header));
149
150 enum GNUNET_MESSENGER_MessageKind kind = message->header.kind;
151
152 GNUNET_memcpy (&(message->header), header,
153 sizeof(struct GNUNET_MESSENGER_MessageHeader));
154
155 message->header.kind = kind;
156}
157
158
159static void
160destroy_message_body (enum GNUNET_MESSENGER_MessageKind kind,
161 struct GNUNET_MESSENGER_MessageBody *body)
162{
163 switch (kind)
164 {
165 case GNUNET_MESSENGER_KIND_NAME:
166 if (body->name.name)
167 GNUNET_free (body->name.name);
168 break;
169 case GNUNET_MESSENGER_KIND_TEXT:
170 if (body->text.text)
171 GNUNET_free (body->text.text);
172 break;
173 case GNUNET_MESSENGER_KIND_FILE:
174 if (body->file.uri)
175 GNUNET_free (body->file.uri);
176 break;
177 case GNUNET_MESSENGER_KIND_PRIVATE:
178 GNUNET_free (body->privacy.data);
179 break;
180 case GNUNET_MESSENGER_KIND_TICKET:
181 if (body->ticket.identifier)
182 GNUNET_free (body->ticket.identifier);
183 break;
184 case GNUNET_MESSENGER_KIND_TRANSCRIPT:
185 GNUNET_free (body->transcript.data);
186 break;
187 case GNUNET_MESSENGER_KIND_TAG:
188 if (body->tag.tag)
189 GNUNET_free (body->tag.tag);
190 break;
191 default:
192 break;
193 }
194}
195
196
197void
198cleanup_message (struct GNUNET_MESSENGER_Message *message)
199{
200 GNUNET_assert (message);
201
202 destroy_message_body (message->header.kind, &(message->body));
203}
204
205
206void
207destroy_message (struct GNUNET_MESSENGER_Message *message)
208{
209 GNUNET_assert (message);
210
211 destroy_message_body (message->header.kind, &(message->body));
212
213 GNUNET_free (message);
214}
215
216
217enum GNUNET_GenericReturnValue
218is_message_session_bound (const struct GNUNET_MESSENGER_Message *message)
219{
220 GNUNET_assert (message);
221
222 if ((GNUNET_MESSENGER_KIND_JOIN == message->header.kind) ||
223 (GNUNET_MESSENGER_KIND_LEAVE == message->header.kind) ||
224 (GNUNET_MESSENGER_KIND_NAME == message->header.kind) ||
225 (GNUNET_MESSENGER_KIND_KEY == message->header.kind) ||
226 (GNUNET_MESSENGER_KIND_ID == message->header.kind))
227 return GNUNET_YES;
228 else
229 return GNUNET_NO;
230}
231
232
233static void
234fold_short_message (const struct GNUNET_MESSENGER_Message *message,
235 struct GNUNET_MESSENGER_ShortMessage *shortened)
236{
237 shortened->kind = message->header.kind;
238
239 GNUNET_memcpy (&(shortened->body), &(message->body), sizeof(struct
240 GNUNET_MESSENGER_MessageBody));
241}
242
243
244static void
245unfold_short_message (struct GNUNET_MESSENGER_ShortMessage *shortened,
246 struct GNUNET_MESSENGER_Message *message)
247{
248 destroy_message_body (message->header.kind, &(message->body));
249
250 message->header.kind = shortened->kind;
251
252 GNUNET_memcpy (&(message->body), &(shortened->body),
253 sizeof(struct GNUNET_MESSENGER_MessageBody));
254}
255
256
257#define member_size(type, member) sizeof(((type*) NULL)->member)
258
259static uint16_t
260get_message_body_kind_size (enum GNUNET_MESSENGER_MessageKind kind)
261{
262 uint16_t length = 0;
263
264 switch (kind)
265 {
266 case GNUNET_MESSENGER_KIND_INFO:
267 length += member_size (struct GNUNET_MESSENGER_Message,
268 body.info.messenger_version);
269 break;
270 case GNUNET_MESSENGER_KIND_PEER:
271 length += member_size (struct GNUNET_MESSENGER_Message, body.peer.peer);
272 break;
273 case GNUNET_MESSENGER_KIND_ID:
274 length += member_size (struct GNUNET_MESSENGER_Message, body.id.id);
275 break;
276 case GNUNET_MESSENGER_KIND_MISS:
277 length += member_size (struct GNUNET_MESSENGER_Message, body.miss.peer);
278 break;
279 case GNUNET_MESSENGER_KIND_MERGE:
280 length += member_size (struct GNUNET_MESSENGER_Message,
281 body.merge.previous);
282 break;
283 case GNUNET_MESSENGER_KIND_REQUEST:
284 length += member_size (struct GNUNET_MESSENGER_Message, body.request.hash);
285 break;
286 case GNUNET_MESSENGER_KIND_INVITE:
287 length += member_size (struct GNUNET_MESSENGER_Message, body.invite.door);
288 length += member_size (struct GNUNET_MESSENGER_Message, body.invite.key);
289 break;
290 case GNUNET_MESSENGER_KIND_FILE:
291 length += member_size (struct GNUNET_MESSENGER_Message, body.file.key);
292 length += member_size (struct GNUNET_MESSENGER_Message, body.file.hash);
293 length += member_size (struct GNUNET_MESSENGER_Message, body.file.name);
294 break;
295 case GNUNET_MESSENGER_KIND_PRIVATE:
296 length += member_size (struct GNUNET_MESSENGER_Message, body.privacy.key);
297 break;
298 case GNUNET_MESSENGER_KIND_DELETE:
299 length += member_size (struct GNUNET_MESSENGER_Message, body.deletion.hash);
300 length += member_size (struct GNUNET_MESSENGER_Message,
301 body.deletion.delay);
302 break;
303 case GNUNET_MESSENGER_KIND_CONNECTION:
304 length += member_size (struct GNUNET_MESSENGER_Message,
305 body.connection.amount);
306 length += member_size (struct GNUNET_MESSENGER_Message,
307 body.connection.flags);
308 break;
309 case GNUNET_MESSENGER_KIND_TRANSCRIPT:
310 length += member_size (struct GNUNET_MESSENGER_Message,
311 body.transcript.hash);
312 break;
313 case GNUNET_MESSENGER_KIND_TAG:
314 length += member_size (struct GNUNET_MESSENGER_Message, body.tag.hash);
315 break;
316 default:
317 break;
318 }
319
320 return length;
321}
322
323
324typedef uint32_t kind_t;
325
326uint16_t
327get_message_kind_size (enum GNUNET_MESSENGER_MessageKind kind,
328 enum GNUNET_GenericReturnValue include_header)
329{
330 uint16_t length = 0;
331
332 if (GNUNET_YES == include_header)
333 {
334 length += member_size (struct GNUNET_MESSENGER_Message, header.timestamp);
335 length += member_size (struct GNUNET_MESSENGER_Message, header.sender_id);
336 length += member_size (struct GNUNET_MESSENGER_Message, header.previous);
337 }
338
339 length += sizeof(kind_t);
340
341 return length + get_message_body_kind_size (kind);
342}
343
344
345static uint16_t
346get_message_body_size (enum GNUNET_MESSENGER_MessageKind kind,
347 const struct GNUNET_MESSENGER_MessageBody *body)
348{
349 uint16_t length = 0;
350
351 switch (kind)
352 {
353 case GNUNET_MESSENGER_KIND_JOIN:
354 length += GNUNET_CRYPTO_public_key_get_length (&(body->join.key));
355 break;
356 case GNUNET_MESSENGER_KIND_NAME:
357 length += (body->name.name ? strlen (body->name.name) : 0);
358 break;
359 case GNUNET_MESSENGER_KIND_KEY:
360 length += GNUNET_CRYPTO_public_key_get_length (&(body->key.key));
361 break;
362 case GNUNET_MESSENGER_KIND_TEXT:
363 length += (body->text.text ? strlen (body->text.text) : 0);
364 break;
365 case GNUNET_MESSENGER_KIND_FILE:
366 length += (body->file.uri ? strlen (body->file.uri) : 0);
367 break;
368 case GNUNET_MESSENGER_KIND_PRIVATE:
369 length += body->privacy.length;
370 break;
371 case GNUNET_MESSENGER_KIND_TICKET:
372 length += (body->ticket.identifier ? strlen (body->ticket.identifier) : 0);
373 break;
374 case GNUNET_MESSENGER_KIND_TRANSCRIPT:
375 length += GNUNET_CRYPTO_public_key_get_length (&(body->transcript.key));
376 length += body->transcript.length;
377 break;
378 case GNUNET_MESSENGER_KIND_TAG:
379 length += (body->tag.tag ? strlen (body->tag.tag) : 0);
380 break;
381 default:
382 break;
383 }
384
385 return length;
386}
387
388
389uint16_t
390get_message_size (const struct GNUNET_MESSENGER_Message *message,
391 enum GNUNET_GenericReturnValue include_header)
392{
393 GNUNET_assert (message);
394
395 uint16_t length = 0;
396
397 if (GNUNET_YES == include_header)
398 length += GNUNET_CRYPTO_signature_get_length (
399 &(message->header.signature));
400
401 length += get_message_kind_size (message->header.kind, include_header);
402 length += get_message_body_size (message->header.kind, &(message->body));
403
404 return length;
405}
406
407
408static uint16_t
409get_short_message_size (const struct GNUNET_MESSENGER_ShortMessage *message,
410 enum GNUNET_GenericReturnValue include_body)
411{
412 const uint16_t minimum_size = sizeof(struct GNUNET_HashCode) + sizeof(kind_t);
413
414 if (message)
415 return minimum_size + get_message_body_kind_size (message->kind)
416 + (include_body == GNUNET_YES?
417 get_message_body_size (message->kind, &(message->body)) : 0);
418 else
419 return minimum_size;
420}
421
422
423static uint16_t
424calc_usual_padding ()
425{
426 uint16_t padding = 0;
427 uint16_t kind_size;
428
429 for (unsigned int i = 0; i <= GNUNET_MESSENGER_KIND_MAX; i++)
430 {
431 kind_size = get_message_kind_size ((enum GNUNET_MESSENGER_MessageKind) i,
432 GNUNET_YES);
433
434 if (kind_size > padding)
435 padding = kind_size;
436 }
437
438 return padding + GNUNET_MESSENGER_PADDING_MIN;
439}
440
441
442#define max(x, y) (x > y? x : y)
443
444static uint16_t
445calc_padded_length (uint16_t length)
446{
447 static uint16_t usual_padding = 0;
448
449 if (! usual_padding)
450 usual_padding = calc_usual_padding ();
451
452 const uint16_t padded_length = max (
453 length + GNUNET_MESSENGER_PADDING_MIN,
454 usual_padding
455 );
456
457 if (padded_length <= GNUNET_MESSENGER_PADDING_LEVEL0)
458 return GNUNET_MESSENGER_PADDING_LEVEL0;
459
460 if (padded_length <= GNUNET_MESSENGER_PADDING_LEVEL1)
461 return GNUNET_MESSENGER_PADDING_LEVEL1;
462
463 if (padded_length <= GNUNET_MESSENGER_PADDING_LEVEL2)
464 return GNUNET_MESSENGER_PADDING_LEVEL2;
465
466 return GNUNET_MESSENGER_MAX_MESSAGE_SIZE;
467
468}
469
470
471#define min(x, y) (x < y? x : y)
472
473#define encode_step_ext(dst, offset, src, size) do { \
474 GNUNET_memcpy (dst + offset, src, size); \
475 offset += size; \
476} while (0)
477
478#define encode_step(dst, offset, src) do { \
479 encode_step_ext (dst, offset, src, sizeof(*src)); \
480} while (0)
481
482#define encode_step_key(dst, offset, src, length) do { \
483 ssize_t result = GNUNET_CRYPTO_write_public_key_to_buffer ( \
484 src, dst + offset, length - offset \
485 ); \
486 if (result < 0) \
487 GNUNET_break (0); \
488 else \
489 offset += result; \
490} while (0)
491
492#define encode_step_signature(dst, offset, src, length) do { \
493 ssize_t result = GNUNET_CRYPTO_write_signature_to_buffer ( \
494 src, dst + offset, length - offset \
495 ); \
496 if (result < 0) \
497 GNUNET_break (0); \
498 else \
499 offset += result; \
500} while (0)
501
502static void
503encode_message_body (enum GNUNET_MESSENGER_MessageKind kind,
504 const struct GNUNET_MESSENGER_MessageBody *body,
505 uint16_t length,
506 char *buffer,
507 uint16_t offset)
508{
509 uint32_t value0, value1;
510 switch (kind)
511 {
512 case GNUNET_MESSENGER_KIND_INFO:
513 value0 = GNUNET_htobe32 (body->info.messenger_version);
514
515 encode_step (buffer, offset, &value0);
516 break;
517 case GNUNET_MESSENGER_KIND_JOIN:
518 encode_step_key (buffer, offset, &(body->join.key), length);
519 break;
520 case GNUNET_MESSENGER_KIND_LEAVE:
521 break;
522 case GNUNET_MESSENGER_KIND_NAME:
523 if (body->name.name)
524 encode_step_ext (buffer, offset, body->name.name, min (length - offset,
525 strlen (
526 body->name.name))
527 );
528 break;
529 case GNUNET_MESSENGER_KIND_KEY:
530 encode_step_key (buffer, offset, &(body->key.key), length);
531 break;
532 case GNUNET_MESSENGER_KIND_PEER:
533 encode_step (buffer, offset, &(body->peer.peer));
534 break;
535 case GNUNET_MESSENGER_KIND_ID:
536 encode_step (buffer, offset, &(body->id.id));
537 break;
538 case GNUNET_MESSENGER_KIND_MISS:
539 encode_step (buffer, offset, &(body->miss.peer));
540 break;
541 case GNUNET_MESSENGER_KIND_MERGE:
542 encode_step (buffer, offset, &(body->merge.previous));
543 break;
544 case GNUNET_MESSENGER_KIND_REQUEST:
545 encode_step (buffer, offset, &(body->request.hash));
546 break;
547 case GNUNET_MESSENGER_KIND_INVITE:
548 encode_step (buffer, offset, &(body->invite.door));
549 encode_step (buffer, offset, &(body->invite.key));
550 break;
551 case GNUNET_MESSENGER_KIND_TEXT:
552 if (body->text.text)
553 encode_step_ext (buffer, offset, body->text.text, min (length - offset,
554 strlen (
555 body->text.text))
556 );
557 break;
558 case GNUNET_MESSENGER_KIND_FILE:
559 encode_step (buffer, offset, &(body->file.key));
560 encode_step (buffer, offset, &(body->file.hash));
561 encode_step_ext (buffer, offset, body->file.name, sizeof(body->file.name));
562 if (body->file.uri)
563 encode_step_ext (buffer, offset, body->file.uri, min (length - offset,
564 strlen (
565 body->file.uri)));
566 break;
567 case GNUNET_MESSENGER_KIND_PRIVATE:
568 encode_step (buffer, offset, &(body->privacy.key));
569 encode_step_ext (buffer, offset, body->privacy.data, min (length - offset,
570 body->privacy.
571 length));
572 break;
573 case GNUNET_MESSENGER_KIND_DELETE:
574 encode_step (buffer, offset, &(body->deletion.hash));
575 encode_step (buffer, offset, &(body->deletion.delay));
576 break;
577 case GNUNET_MESSENGER_KIND_CONNECTION:
578 value0 = GNUNET_htobe32 (body->connection.amount);
579 value1 = GNUNET_htobe32 (body->connection.flags);
580
581 encode_step (buffer, offset, &value0);
582 encode_step (buffer, offset, &value1);
583 break;
584 case GNUNET_MESSENGER_KIND_TICKET:
585 encode_step_ext (buffer, offset, body->ticket.identifier,
586 min (length - offset, strlen (body->ticket.identifier)));
587 break;
588 case GNUNET_MESSENGER_KIND_TRANSCRIPT:
589 encode_step (buffer, offset, &(body->transcript.hash));
590 encode_step_key (buffer, offset, &(body->transcript.key), length);
591 encode_step_ext (buffer, offset, body->transcript.data, min (length
592 - offset,
593 body->
594 transcript.
595 length));
596 break;
597 case GNUNET_MESSENGER_KIND_TAG:
598 encode_step (buffer, offset, &(body->tag.hash));
599 if (body->tag.tag)
600 encode_step_ext (buffer, offset, body->tag.tag, min (length - offset,
601 strlen (
602 body->tag.tag)));
603 break;
604 default:
605 break;
606 }
607
608 if (offset >= length)
609 return;
610
611 const uint16_t padding = length - offset;
612 const uint16_t used_padding = sizeof(padding) + sizeof(char);
613
614 GNUNET_assert (padding >= used_padding);
615
616 buffer[offset++] = '\0';
617
618 if (padding > used_padding)
619 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, buffer + offset,
620 padding - used_padding);
621
622 GNUNET_memcpy (buffer + length - sizeof(padding), &padding, sizeof(padding));
623}
624
625
626void
627encode_message (const struct GNUNET_MESSENGER_Message *message,
628 uint16_t length,
629 char *buffer,
630 enum GNUNET_GenericReturnValue include_header)
631{
632 GNUNET_assert ((message) && (buffer));
633
634 uint16_t offset = 0;
635
636 if (GNUNET_YES == include_header)
637 encode_step_signature (buffer, offset, &(message->header.signature),
638 length);
639
640 const kind_t kind = GNUNET_htobe32 ((kind_t) message->header.kind);
641
642 if (GNUNET_YES == include_header)
643 {
644 encode_step (buffer, offset, &(message->header.timestamp));
645 encode_step (buffer, offset, &(message->header.sender_id));
646 encode_step (buffer, offset, &(message->header.previous));
647 }
648
649 encode_step (buffer, offset, &kind);
650
651 encode_message_body (message->header.kind, &(message->body),
652 length, buffer, offset);
653}
654
655
656static void
657encode_short_message (const struct GNUNET_MESSENGER_ShortMessage *message,
658 uint16_t length,
659 char *buffer)
660{
661 struct GNUNET_HashCode hash;
662 uint16_t offset = sizeof(hash);
663
664 const kind_t kind = GNUNET_htobe32 ((kind_t) message->kind);
665
666 encode_step (buffer, offset, &kind);
667
668 encode_message_body (message->kind, &(message->body), length, buffer, offset);
669
670 GNUNET_CRYPTO_hash (
671 buffer + sizeof(hash),
672 length - sizeof(hash),
673 &hash);
674
675 GNUNET_memcpy (buffer, &hash, sizeof(hash));
676}
677
678
679#define decode_step_ext(src, offset, dst, size) do { \
680 GNUNET_memcpy (dst, src + offset, size); \
681 offset += size; \
682} while (0)
683
684#define decode_step(src, offset, dst) do { \
685 decode_step_ext (src, offset, dst, sizeof(*dst)); \
686} while (0)
687
688#define decode_step_malloc(src, offset, dst, size, zero) do { \
689 dst = GNUNET_malloc (size + zero); \
690 if (zero) dst[size] = 0; \
691 decode_step_ext (src, offset, dst, size); \
692} while (0)
693
694#define decode_step_key(src, offset, dst, length) do { \
695 enum GNUNET_GenericReturnValue result; \
696 size_t read; \
697 result = GNUNET_CRYPTO_read_public_key_from_buffer ( \
698 src + offset, length - offset, dst, &read \
699 ); \
700 if (GNUNET_SYSERR == result) \
701 GNUNET_break (0); \
702 else \
703 offset += read; \
704} while (0)
705
706static uint16_t
707decode_message_body (enum GNUNET_MESSENGER_MessageKind *kind,
708 struct GNUNET_MESSENGER_MessageBody *body,
709 uint16_t length,
710 const char *buffer,
711 uint16_t offset)
712{
713 uint16_t padding = 0;
714
715 GNUNET_memcpy (&padding, buffer + length - sizeof(padding), sizeof(padding));
716
717 if (padding > length - offset)
718 padding = 0;
719
720 const uint16_t end_zero = length - padding;
721
722 if ((padding) && (buffer[end_zero] != '\0'))
723 padding = 0;
724
725 length -= padding;
726
727 uint32_t value0, value1;
728 switch (*kind)
729 {
730 case GNUNET_MESSENGER_KIND_INFO:
731 decode_step (buffer, offset, &value0);
732
733 body->info.messenger_version = GNUNET_be32toh (value0);
734 break;
735 case GNUNET_MESSENGER_KIND_JOIN:
736 decode_step_key (buffer, offset, &(body->join.key), length);
737 break;
738 case GNUNET_MESSENGER_KIND_LEAVE:
739 break;
740 case GNUNET_MESSENGER_KIND_NAME:
741 if (length > offset)
742 decode_step_malloc (buffer, offset, body->name.name, length - offset, 1);
743 else
744 body->name.name = NULL;
745 break;
746 case GNUNET_MESSENGER_KIND_KEY:
747 decode_step_key (buffer, offset, &(body->key.key), length);
748 break;
749 case GNUNET_MESSENGER_KIND_PEER:
750 decode_step (buffer, offset, &(body->peer.peer));
751 break;
752 case GNUNET_MESSENGER_KIND_ID:
753 decode_step (buffer, offset, &(body->id.id));
754 break;
755 case GNUNET_MESSENGER_KIND_MISS:
756 decode_step (buffer, offset, &(body->miss.peer));
757 break;
758 case GNUNET_MESSENGER_KIND_MERGE:
759 decode_step (buffer, offset, &(body->merge.previous));
760 break;
761 case GNUNET_MESSENGER_KIND_REQUEST:
762 decode_step (buffer, offset, &(body->request.hash));
763 break;
764 case GNUNET_MESSENGER_KIND_INVITE:
765 decode_step (buffer, offset, &(body->invite.door));
766 decode_step (buffer, offset, &(body->invite.key));
767 break;
768 case GNUNET_MESSENGER_KIND_TEXT:
769 if (length > offset)
770 decode_step_malloc (buffer, offset, body->text.text, length - offset, 1);
771 else
772 body->text.text = NULL;
773 break;
774 case GNUNET_MESSENGER_KIND_FILE:
775 decode_step (buffer, offset, &(body->file.key));
776 decode_step (buffer, offset, &(body->file.hash));
777 decode_step_ext (buffer, offset, body->file.name, sizeof(body->file.name));
778 if (length > offset)
779 decode_step_malloc (buffer, offset, body->file.uri, length - offset, 1);
780 else
781 body->file.uri = NULL;
782 break;
783 case GNUNET_MESSENGER_KIND_PRIVATE:
784 decode_step (buffer, offset, &(body->privacy.key));
785
786 body->privacy.length = (length - offset);
787 decode_step_malloc (buffer, offset, body->privacy.data, length - offset, 0);
788 break;
789 case GNUNET_MESSENGER_KIND_DELETE:
790 decode_step (buffer, offset, &(body->deletion.hash));
791 decode_step (buffer, offset, &(body->deletion.delay));
792 break;
793 case GNUNET_MESSENGER_KIND_CONNECTION:
794 decode_step (buffer, offset, &value0);
795 decode_step (buffer, offset, &value1);
796
797 body->connection.amount = GNUNET_be32toh (value0);
798 body->connection.flags = GNUNET_be32toh (value1);
799 break;
800 case GNUNET_MESSENGER_KIND_TICKET:
801 if (length > offset)
802 decode_step_malloc (buffer, offset, body->ticket.identifier, length
803 - offset, 1);
804 else
805 body->ticket.identifier = NULL;
806 break;
807 case GNUNET_MESSENGER_KIND_TRANSCRIPT:
808 decode_step (buffer, offset, &(body->transcript.hash));
809 decode_step_key (buffer, offset, &(body->transcript.key), length);
810
811 body->transcript.length = (length - offset);
812 decode_step_malloc (buffer, offset, body->transcript.data, length - offset,
813 0);
814 break;
815 case GNUNET_MESSENGER_KIND_TAG:
816 decode_step (buffer, offset, &(body->tag.hash));
817 if (length > offset)
818 decode_step_malloc (buffer, offset, body->tag.tag, length - offset, 1);
819 else
820 body->tag.tag = NULL;
821 break;
822 default:
823 *kind = GNUNET_MESSENGER_KIND_UNKNOWN;
824 break;
825 }
826
827 return padding;
828}
829
830
831enum GNUNET_GenericReturnValue
832decode_message (struct GNUNET_MESSENGER_Message *message,
833 uint16_t length,
834 const char *buffer,
835 enum GNUNET_GenericReturnValue include_header,
836 uint16_t *padding)
837{
838 GNUNET_assert (
839 (message) &&
840 (buffer) &&
841 (length >= get_message_kind_size (GNUNET_MESSENGER_KIND_UNKNOWN,
842 include_header))
843 );
844
845 uint16_t offset = 0;
846
847 if (GNUNET_YES == include_header)
848 {
849 ssize_t result = GNUNET_CRYPTO_read_signature_from_buffer (
850 &(message->header.signature), buffer, length - offset
851 );
852
853 if (result < 0)
854 return GNUNET_NO;
855 else
856 offset += result;
857 }
858
859 const uint16_t count = length - offset;
860
861 if (count < get_message_kind_size (GNUNET_MESSENGER_KIND_UNKNOWN,
862 include_header))
863 return GNUNET_NO;
864
865 kind_t kind;
866
867 if (GNUNET_YES == include_header)
868 {
869 decode_step (buffer, offset, &(message->header.timestamp));
870 decode_step (buffer, offset, &(message->header.sender_id));
871 decode_step (buffer, offset, &(message->header.previous));
872 }
873
874 decode_step (buffer, offset, &kind);
875
876 message->header.kind = (enum GNUNET_MESSENGER_MessageKind) GNUNET_be32toh (
877 kind);
878
879 if (count < get_message_kind_size (message->header.kind, include_header))
880 return GNUNET_NO;
881
882 const uint16_t result = decode_message_body (&(message->header.kind),
883 &(message->body), length, buffer,
884 offset);
885
886 if (padding)
887 *padding = result;
888
889 return GNUNET_YES;
890}
891
892
893static enum GNUNET_GenericReturnValue
894decode_short_message (struct GNUNET_MESSENGER_ShortMessage *message,
895 uint16_t length,
896 const char *buffer)
897{
898 struct GNUNET_HashCode expected, hash;
899 uint16_t offset = sizeof(hash);
900
901 if (length < get_short_message_size (NULL, GNUNET_NO))
902 return GNUNET_NO;
903
904 GNUNET_memcpy (&hash, buffer, sizeof(hash));
905
906 GNUNET_CRYPTO_hash (
907 buffer + sizeof(hash),
908 length - sizeof(hash),
909 &expected
910 );
911
912 if (0 != GNUNET_CRYPTO_hash_cmp (&hash, &expected))
913 return GNUNET_NO;
914
915 kind_t kind;
916
917 decode_step (buffer, offset, &kind);
918
919 message->kind = (enum GNUNET_MESSENGER_MessageKind) GNUNET_be32toh (kind);
920
921 if (length < get_short_message_size (message, GNUNET_NO))
922 return GNUNET_NO;
923
924 decode_message_body (&(message->kind), &(message->body), length, buffer,
925 offset);
926
927 if (GNUNET_MESSENGER_KIND_UNKNOWN == message->kind)
928 return GNUNET_NO;
929
930 return GNUNET_YES;
931}
932
933
934void
935hash_message (const struct GNUNET_MESSENGER_Message *message,
936 uint16_t length,
937 const char *buffer,
938 struct GNUNET_HashCode *hash)
939{
940 GNUNET_assert ((message) && (buffer) && (hash));
941
942 const ssize_t offset = GNUNET_CRYPTO_signature_get_length (
943 &(message->header.signature)
944 );
945
946 GNUNET_CRYPTO_hash (buffer + offset, length - offset, hash);
947}
948
949
950void
951sign_message (struct GNUNET_MESSENGER_Message *message,
952 uint16_t length,
953 char *buffer,
954 const struct GNUNET_HashCode *hash,
955 const struct GNUNET_CRYPTO_PrivateKey *key)
956{
957 GNUNET_assert ((message) && (buffer) && (hash) && (key));
958
959 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sign message by member: %s\n",
960 GNUNET_h2s (hash));
961
962 struct GNUNET_MESSENGER_MessageSignature signature;
963
964 signature.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CHAT_MESSAGE);
965 signature.purpose.size = htonl (sizeof(signature));
966
967 GNUNET_memcpy (&(signature.hash), hash, sizeof(signature.hash));
968 GNUNET_CRYPTO_sign (key, &signature, &(message->header.signature));
969
970 message->header.signature.type = key->type;
971
972 uint16_t offset = 0;
973 encode_step_signature (buffer, offset, &(message->header.signature), length);
974}
975
976
977void
978sign_message_by_peer (struct GNUNET_MESSENGER_Message *message,
979 uint16_t length,
980 char *buffer,
981 const struct GNUNET_HashCode *hash,
982 const struct GNUNET_CONFIGURATION_Handle *cfg)
983{
984 GNUNET_assert ((message) && (buffer) && (hash) && (cfg));
985
986 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sign message by peer: %s\n",
987 GNUNET_h2s (hash));
988
989 struct GNUNET_MESSENGER_MessageSignature signature;
990
991 signature.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CHAT_MESSAGE);
992 signature.purpose.size = htonl (sizeof(signature));
993
994 GNUNET_memcpy (&(signature.hash), hash, sizeof(signature.hash));
995 GNUNET_CRYPTO_sign_by_peer_identity (cfg, &(signature.purpose),
996 &(message->header.signature.
997 eddsa_signature));
998
999 message->header.signature.type = htonl (GNUNET_PUBLIC_KEY_TYPE_EDDSA);
1000
1001 uint16_t offset = 0;
1002 encode_step_signature (buffer, offset, &(message->header.signature), length);
1003}
1004
1005
1006enum GNUNET_GenericReturnValue
1007verify_message (const struct GNUNET_MESSENGER_Message *message,
1008 const struct GNUNET_HashCode *hash,
1009 const struct GNUNET_CRYPTO_PublicKey *key)
1010{
1011 GNUNET_assert ((message) && (hash) && (key));
1012
1013 if (key->type != message->header.signature.type)
1014 return GNUNET_SYSERR;
1015
1016 struct GNUNET_MESSENGER_MessageSignature signature;
1017
1018 signature.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CHAT_MESSAGE);
1019 signature.purpose.size = htonl (sizeof(signature));
1020
1021 GNUNET_memcpy (&(signature.hash), hash, sizeof(signature.hash));
1022
1023 return GNUNET_CRYPTO_signature_verify (
1024 GNUNET_SIGNATURE_PURPOSE_CHAT_MESSAGE, &signature,
1025 &(message->header.signature), key);
1026}
1027
1028
1029enum GNUNET_GenericReturnValue
1030verify_message_by_peer (const struct GNUNET_MESSENGER_Message *message,
1031 const struct GNUNET_HashCode *hash,
1032 const struct GNUNET_PeerIdentity *identity)
1033{
1034 GNUNET_assert ((message) && (hash) && (identity));
1035
1036 if (ntohl (GNUNET_PUBLIC_KEY_TYPE_EDDSA) != message->header.signature.type)
1037 return GNUNET_SYSERR;
1038
1039 struct GNUNET_MESSENGER_MessageSignature signature;
1040
1041 signature.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CHAT_MESSAGE);
1042 signature.purpose.size = htonl (sizeof(signature));
1043
1044 GNUNET_memcpy (&(signature.hash), hash, sizeof(signature.hash));
1045
1046 return GNUNET_CRYPTO_verify_peer_identity (
1047 GNUNET_SIGNATURE_PURPOSE_CHAT_MESSAGE, &(signature.purpose),
1048 &(message->header.signature.
1049 eddsa_signature), identity);
1050}
1051
1052
1053enum GNUNET_GenericReturnValue
1054encrypt_message (struct GNUNET_MESSENGER_Message *message,
1055 const struct GNUNET_CRYPTO_PublicKey *key)
1056{
1057 GNUNET_assert ((message) && (key));
1058
1059 if (GNUNET_YES == is_service_message (message))
1060 return GNUNET_NO;
1061
1062 struct GNUNET_MESSENGER_ShortMessage shortened;
1063
1064 fold_short_message (message, &shortened);
1065
1066 const uint16_t length = get_short_message_size (&shortened, GNUNET_YES);
1067 const uint16_t padded_length = calc_padded_length (
1068 length + GNUNET_CRYPTO_ENCRYPT_OVERHEAD_BYTES
1069 );
1070
1071 message->header.kind = GNUNET_MESSENGER_KIND_PRIVATE;
1072 message->body.privacy.data = GNUNET_malloc (padded_length);
1073 message->body.privacy.length = padded_length;
1074
1075 const uint16_t encoded_length = (
1076 padded_length - GNUNET_CRYPTO_ENCRYPT_OVERHEAD_BYTES
1077 );
1078
1079 encode_short_message (&shortened, encoded_length, message->body.privacy.data);
1080
1081 if (GNUNET_OK != GNUNET_CRYPTO_encrypt (message->body.privacy.data,
1082 encoded_length,
1083 key,
1084 message->body.privacy.data,
1085 padded_length))
1086 {
1087 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Encrypting message failed!\n");
1088
1089 unfold_short_message (&shortened, message);
1090 return GNUNET_NO;
1091 }
1092
1093 destroy_message_body (shortened.kind, &(shortened.body));
1094 return GNUNET_YES;
1095}
1096
1097
1098enum GNUNET_GenericReturnValue
1099decrypt_message (struct GNUNET_MESSENGER_Message *message,
1100 const struct GNUNET_CRYPTO_PrivateKey *key)
1101{
1102 GNUNET_assert ((message) && (key));
1103
1104 const uint16_t padded_length = message->body.privacy.length;
1105
1106 if (padded_length < GNUNET_CRYPTO_ENCRYPT_OVERHEAD_BYTES)
1107 {
1108 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1109 "Message length too short to decrypt!\n");
1110
1111 return GNUNET_NO;
1112 }
1113
1114 const uint16_t encoded_length = (
1115 padded_length - GNUNET_CRYPTO_ENCRYPT_OVERHEAD_BYTES
1116 );
1117
1118 if (GNUNET_OK != GNUNET_CRYPTO_decrypt (message->body.privacy.data,
1119 padded_length,
1120 key,
1121 message->body.privacy.data,
1122 encoded_length))
1123 {
1124 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Decrypting message failed!\n");
1125
1126 return GNUNET_NO;
1127 }
1128
1129 struct GNUNET_MESSENGER_ShortMessage shortened;
1130
1131 if (GNUNET_YES != decode_short_message (&shortened,
1132 encoded_length,
1133 message->body.privacy.data))
1134 {
1135 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1136 "Decoding decrypted message failed!\n");
1137
1138 return GNUNET_NO;
1139 }
1140
1141 unfold_short_message (&shortened, message);
1142 return GNUNET_YES;
1143}
1144
1145
1146struct GNUNET_MESSENGER_Message*
1147transcribe_message (const struct GNUNET_MESSENGER_Message *message,
1148 const struct GNUNET_CRYPTO_PublicKey *key)
1149{
1150 GNUNET_assert ((message) && (key));
1151
1152 if (GNUNET_YES == is_service_message (message))
1153 return NULL;
1154
1155 struct GNUNET_MESSENGER_Message *transcript = create_message (
1156 GNUNET_MESSENGER_KIND_TRANSCRIPT);
1157
1158 if (! transcript)
1159 {
1160 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Transcribing message failed!\n");
1161 return NULL;
1162 }
1163
1164 GNUNET_memcpy (&(transcript->body.transcript.key), key,
1165 sizeof(transcript->body.transcript.key));
1166
1167 struct GNUNET_MESSENGER_ShortMessage shortened;
1168
1169 fold_short_message (message, &shortened);
1170
1171 const uint16_t data_length = get_short_message_size (
1172 &shortened, GNUNET_YES);
1173
1174 transcript->body.transcript.data = GNUNET_malloc (data_length);
1175 transcript->body.transcript.length = data_length;
1176
1177 encode_short_message (&shortened, data_length,
1178 transcript->body.transcript.data);
1179
1180 return transcript;
1181}
1182
1183
1184enum GNUNET_GenericReturnValue
1185read_transcript_message (struct GNUNET_MESSENGER_Message *message)
1186{
1187 GNUNET_assert (message);
1188
1189 if (GNUNET_MESSENGER_KIND_TRANSCRIPT != message->header.kind)
1190 return GNUNET_NO;
1191
1192 const uint16_t data_length = message->body.transcript.length;
1193
1194 struct GNUNET_MESSENGER_ShortMessage shortened;
1195 if (GNUNET_YES != decode_short_message (&shortened,
1196 data_length,
1197 message->body.transcript.data))
1198 {
1199 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1200 "Decoding decrypted message failed!\n");
1201
1202 return GNUNET_NO;
1203 }
1204
1205 unfold_short_message (&shortened, message);
1206 return GNUNET_YES;
1207}
1208
1209
1210struct GNUNET_MQ_Envelope*
1211pack_message (struct GNUNET_MESSENGER_Message *message,
1212 struct GNUNET_HashCode *hash,
1213 const GNUNET_MESSENGER_SignFunction sign,
1214 enum GNUNET_MESSENGER_PackMode mode,
1215 const void *cls)
1216{
1217 GNUNET_assert (message);
1218
1219 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1220 "Packing message kind=%u and sender: %s\n",
1221 message->header.kind, GNUNET_sh2s (&(message->header.sender_id)));
1222
1223 struct GNUNET_MessageHeader *header;
1224
1225 const uint16_t length = get_message_size (message, GNUNET_YES);
1226 const uint16_t padded_length = calc_padded_length (length);
1227
1228 struct GNUNET_MQ_Envelope *env;
1229 char *buffer;
1230
1231 if (GNUNET_MESSENGER_PACK_MODE_ENVELOPE == mode)
1232 {
1233 env = GNUNET_MQ_msg_extra (header, padded_length,
1234 GNUNET_MESSAGE_TYPE_CADET_CLI);
1235
1236 buffer = (char*) &(header[1]);
1237 }
1238 else
1239 {
1240 env = NULL;
1241
1242 buffer = GNUNET_malloc (padded_length);
1243 }
1244
1245 encode_message (message, padded_length, buffer, GNUNET_YES);
1246
1247 if (hash)
1248 {
1249 hash_message (message, length, buffer, hash);
1250
1251 if (sign)
1252 sign (cls, message, length, buffer, hash);
1253 }
1254
1255 if (GNUNET_MESSENGER_PACK_MODE_ENVELOPE != mode)
1256 GNUNET_free (buffer);
1257
1258 return env;
1259}
1260
1261
1262enum GNUNET_GenericReturnValue
1263is_peer_message (const struct GNUNET_MESSENGER_Message *message)
1264{
1265 switch (message->header.kind)
1266 {
1267 case GNUNET_MESSENGER_KIND_INFO:
1268 case GNUNET_MESSENGER_KIND_PEER:
1269 case GNUNET_MESSENGER_KIND_MISS:
1270 case GNUNET_MESSENGER_KIND_MERGE:
1271 case GNUNET_MESSENGER_KIND_CONNECTION:
1272 return GNUNET_YES;
1273 default:
1274 return GNUNET_NO;
1275 }
1276}
1277
1278
1279enum GNUNET_GenericReturnValue
1280is_service_message (const struct GNUNET_MESSENGER_Message *message)
1281{
1282 if (GNUNET_YES == is_peer_message (message))
1283 return GNUNET_YES;
1284
1285 switch (message->header.kind)
1286 {
1287 case GNUNET_MESSENGER_KIND_INFO:
1288 return GNUNET_YES; // Reserved for connection handling only!
1289 case GNUNET_MESSENGER_KIND_JOIN:
1290 return GNUNET_YES; // Reserved for member handling only!
1291 case GNUNET_MESSENGER_KIND_LEAVE:
1292 return GNUNET_YES; // Reserved for member handling only!
1293 case GNUNET_MESSENGER_KIND_NAME:
1294 return GNUNET_YES; // Reserved for member name handling only!
1295 case GNUNET_MESSENGER_KIND_KEY:
1296 return GNUNET_YES; // Reserved for member key handling only!
1297 case GNUNET_MESSENGER_KIND_PEER:
1298 return GNUNET_YES; // Reserved for connection handling only!
1299 case GNUNET_MESSENGER_KIND_ID:
1300 return GNUNET_YES; // Reserved for member id handling only!
1301 case GNUNET_MESSENGER_KIND_MISS:
1302 return GNUNET_YES; // Reserved for connection handling only!
1303 case GNUNET_MESSENGER_KIND_MERGE:
1304 return GNUNET_YES; // Reserved for peers only!
1305 case GNUNET_MESSENGER_KIND_REQUEST:
1306 return GNUNET_YES; // Requests should not apply individually! (inefficieny)
1307 case GNUNET_MESSENGER_KIND_INVITE:
1308 return GNUNET_NO;
1309 case GNUNET_MESSENGER_KIND_TEXT:
1310 return GNUNET_NO;
1311 case GNUNET_MESSENGER_KIND_FILE:
1312 return GNUNET_NO;
1313 case GNUNET_MESSENGER_KIND_PRIVATE:
1314 return GNUNET_YES; // Prevent duplicate encryption breaking all access!
1315 case GNUNET_MESSENGER_KIND_DELETE:
1316 return GNUNET_YES; // Deletion should not apply individually! (inefficieny)
1317 case GNUNET_MESSENGER_KIND_CONNECTION:
1318 return GNUNET_YES; // Reserved for connection handling only!
1319 case GNUNET_MESSENGER_KIND_TICKET:
1320 return GNUNET_NO;
1321 case GNUNET_MESSENGER_KIND_TRANSCRIPT:
1322 return GNUNET_NO;
1323 case GNUNET_MESSENGER_KIND_TAG:
1324 return GNUNET_NO;
1325 default:
1326 return GNUNET_SYSERR;
1327 }
1328}
1329
1330
1331enum GNUNET_GenericReturnValue
1332filter_message_sending (const struct GNUNET_MESSENGER_Message *message)
1333{
1334 if (GNUNET_YES == is_peer_message (message))
1335 return GNUNET_SYSERR; // Requires signature of peer rather than member!
1336
1337 switch (message->header.kind)
1338 {
1339 case GNUNET_MESSENGER_KIND_INFO:
1340 return GNUNET_SYSERR; // Reserved for connection handling only!
1341 case GNUNET_MESSENGER_KIND_JOIN:
1342 return GNUNET_NO; // Use #GNUNET_MESSENGER_enter_room(...) instead!
1343 case GNUNET_MESSENGER_KIND_LEAVE:
1344 return GNUNET_NO; // Use #GNUNET_MESSENGER_close_room(...) instead!
1345 case GNUNET_MESSENGER_KIND_NAME:
1346 return GNUNET_YES;
1347 case GNUNET_MESSENGER_KIND_KEY:
1348 return GNUNET_NO; // Use #GNUNET_MESSENGER_set_key(...) instead!
1349 case GNUNET_MESSENGER_KIND_PEER:
1350 return GNUNET_SYSERR; // Use #GNUNET_MESSENGER_open_room(...) instead!
1351 case GNUNET_MESSENGER_KIND_ID:
1352 return GNUNET_NO; // Reserved for member id handling only!
1353 case GNUNET_MESSENGER_KIND_MISS:
1354 return GNUNET_SYSERR; // Reserved for connection handling only!
1355 case GNUNET_MESSENGER_KIND_MERGE:
1356 return GNUNET_SYSERR; // Reserved for peers only!
1357 case GNUNET_MESSENGER_KIND_REQUEST:
1358 return GNUNET_NO; // Use #GNUNET_MESSENGER_get_message(...) instead!
1359 case GNUNET_MESSENGER_KIND_INVITE:
1360 return GNUNET_YES;
1361 case GNUNET_MESSENGER_KIND_TEXT:
1362 return GNUNET_YES;
1363 case GNUNET_MESSENGER_KIND_FILE:
1364 return GNUNET_YES;
1365 case GNUNET_MESSENGER_KIND_PRIVATE:
1366 return GNUNET_NO; // Use #GNUNET_MESSENGER_send_message(...) with a contact instead!
1367 case GNUNET_MESSENGER_KIND_DELETE:
1368 return GNUNET_NO; // Use #GNUNET_MESSENGER_delete_message(...) instead!
1369 case GNUNET_MESSENGER_KIND_CONNECTION:
1370 return GNUNET_SYSERR; // Reserved for connection handling only!
1371 case GNUNET_MESSENGER_KIND_TICKET:
1372 return GNUNET_YES;
1373 case GNUNET_MESSENGER_KIND_TRANSCRIPT:
1374 return GNUNET_NO; // Use #GNUNET_MESSENGER_send_message(...) with a contact instead!
1375 case GNUNET_MESSENGER_KIND_TAG:
1376 return GNUNET_YES;
1377 default:
1378 return GNUNET_SYSERR;
1379 }
1380}
diff --git a/src/service/messenger/messenger_api_message.h b/src/service/messenger/messenger_api_message.h
new file mode 100644
index 000000000..20b85dc03
--- /dev/null
+++ b/src/service/messenger/messenger_api_message.h
@@ -0,0 +1,351 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/messenger_api_message.h
23 * @brief messenger api: client and service implementation of GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_MESSENGER_API_MESSAGE_H
27#define GNUNET_MESSENGER_API_MESSAGE_H
28
29#include "gnunet_util_lib.h"
30
31#include "gnunet_messenger_service.h"
32
33#define GNUNET_MESSENGER_MAX_MESSAGE_SIZE (GNUNET_MAX_MESSAGE_SIZE \
34 - GNUNET_MIN_MESSAGE_SIZE)
35
36#define GNUNET_MESSENGER_PADDING_MIN (sizeof(uint16_t) + sizeof(char))
37#define GNUNET_MESSENGER_PADDING_LEVEL0 (512)
38#define GNUNET_MESSENGER_PADDING_LEVEL1 (4096)
39#define GNUNET_MESSENGER_PADDING_LEVEL2 (32768)
40
41/**
42 * Creates and allocates a new message with a specific <i>kind</i>.
43 *
44 * @param[in] kind Kind of message
45 * @return New message
46 */
47struct GNUNET_MESSENGER_Message*
48create_message (enum GNUNET_MESSENGER_MessageKind kind);
49
50/**
51 * Creates and allocates a copy of a given <i>message</i>.
52 *
53 * @param[in] message Message
54 * @return New message
55 */
56struct GNUNET_MESSENGER_Message*
57copy_message (const struct GNUNET_MESSENGER_Message *message);
58
59/**
60 * Copy message <i>header</i> details from another message to
61 * a given <i>message</i>.
62 *
63 * @param[in,out] message Message
64 * @param[in] header Message header
65 */
66void
67copy_message_header (struct GNUNET_MESSENGER_Message *message,
68 const struct GNUNET_MESSENGER_MessageHeader *header);
69
70/**
71 * Frees the messages body memory.
72 *
73 * @param[in,out] message Message
74 */
75void
76cleanup_message (struct GNUNET_MESSENGER_Message *message);
77
78/**
79 * Destroys a message and frees its memory fully.
80 *
81 * @param[in,out] message Message
82 */
83void
84destroy_message (struct GNUNET_MESSENGER_Message *message);
85
86/**
87 * Returns if the message should be bound to a member session.
88 *
89 * @param[in] message Message
90 * @return #GNUNET_YES or #GNUNET_NO
91 */
92enum GNUNET_GenericReturnValue
93is_message_session_bound (const struct GNUNET_MESSENGER_Message *message);
94
95/**
96 * Returns the minimal size in bytes to encode a message of a specific <i>kind</i>.
97 *
98 * @param[in] kind Kind of message
99 * @param[in] include_header Flag to include header
100 * @return Minimal size to encode
101 */
102uint16_t
103get_message_kind_size (enum GNUNET_MESSENGER_MessageKind kind,
104 enum GNUNET_GenericReturnValue include_header);
105
106/**
107 * Returns the exact size in bytes to encode a given <i>message</i>.
108 *
109 * @param[in] message Message
110 * @param[in] include_header Flag to include header
111 * @return Size to encode
112 */
113uint16_t
114get_message_size (const struct GNUNET_MESSENGER_Message *message,
115 enum GNUNET_GenericReturnValue include_header);
116
117/**
118 * Encodes a given <i>message</i> into a <i>buffer</i> of a maximal <i>length</i> in bytes.
119 *
120 * @param[in] message Message
121 * @param[in] length Maximal length to encode
122 * @param[out] buffer Buffer
123 * @param[in] include_header Flag to include header
124 */
125void
126encode_message (const struct GNUNET_MESSENGER_Message *message,
127 uint16_t length,
128 char *buffer,
129 enum GNUNET_GenericReturnValue include_header);
130
131/**
132 * Decodes a <i>message</i> from a given <i>buffer</i> of a maximal <i>length</i> in bytes.
133 *
134 * If the buffer is too small for a message of its decoded kind the function fails with
135 * resulting #GNUNET_NO after decoding only the messages header.
136 *
137 * On success the function returns #GNUNET_YES.
138 *
139 * @param[out] message Message
140 * @param[in] length Maximal length to decode
141 * @param[in] buffer Buffer
142 * @param[in] include_header Flag to include header
143 * @param[out] padding Padding
144 * @return #GNUNET_YES on success, otherwise #GNUNET_NO
145 */
146enum GNUNET_GenericReturnValue
147decode_message (struct GNUNET_MESSENGER_Message *message,
148 uint16_t length,
149 const char *buffer,
150 enum GNUNET_GenericReturnValue include_header,
151 uint16_t *padding);
152
153/**
154 * Calculates a <i>hash</i> of a given <i>buffer</i> with a <i>length</i> in bytes
155 * from a <i>message</i>.
156 *
157 * @param[in] message Message
158 * @param[in] length Length of buffer
159 * @param[in] buffer Buffer
160 * @param[out] hash Hash
161 */
162void
163hash_message (const struct GNUNET_MESSENGER_Message *message,
164 uint16_t length,
165 const char *buffer,
166 struct GNUNET_HashCode *hash);
167
168/**
169 * Signs the <i>hash</i> of a <i>message</i> with a given private <i>key</i> and writes
170 * the signature into the <i>buffer</i> as well.
171 *
172 * @param[in,out] message Message
173 * @param[in] length Length of buffer
174 * @param[out] buffer Buffer
175 * @param[in] hash Hash of message
176 * @param[in] key Private key
177 */
178void
179sign_message (struct GNUNET_MESSENGER_Message *message,
180 uint16_t length,
181 char *buffer,
182 const struct GNUNET_HashCode *hash,
183 const struct GNUNET_CRYPTO_PrivateKey *key);
184
185/**
186 * Signs the <i>hash</i> of a <i>message</i> with the peer identity of a given <i>config</i>
187 * and writes the signature into the <i>buffer</i> as well.
188 *
189 * @param[in,out] message Message
190 * @param[in] length Length of buffer
191 * @param[out] buffer Buffer
192 * @param[in] hash Hash of message
193 * @param[in] cfg Peer configuration
194 */
195void
196sign_message_by_peer (struct GNUNET_MESSENGER_Message *message,
197 uint16_t length,
198 char *buffer,
199 const struct GNUNET_HashCode *hash,
200 const struct GNUNET_CONFIGURATION_Handle *cfg);
201
202/**
203 * Verifies the signature of a given <i>message</i> and its <i>hash</i> with a specific
204 * public key. The function returns #GNUNET_OK if the signature was valid, otherwise
205 * #GNUNET_SYSERR.
206 *
207 * @param[in] message Message
208 * @param[in] hash Hash of message
209 * @param[in] key Public key
210 * @return #GNUNET_OK on success, otherwise #GNUNET_SYSERR
211 */
212enum GNUNET_GenericReturnValue
213verify_message (const struct GNUNET_MESSENGER_Message *message,
214 const struct GNUNET_HashCode *hash,
215 const struct GNUNET_CRYPTO_PublicKey *key);
216
217/**
218 * Verifies the signature of a given <i>message</i> and its <i>hash</i> with a specific
219 * peer's <i>identity</i>. The function returns #GNUNET_OK if the signature was valid,
220 * otherwise #GNUNET_SYSERR.
221 *
222 * @param[in] message Message
223 * @param[in] hash Hash of message
224 * @param[in] identity Peer identity
225 * @return #GNUNET_OK on success, otherwise #GNUNET_SYSERR
226 */
227enum GNUNET_GenericReturnValue
228verify_message_by_peer (const struct GNUNET_MESSENGER_Message *message,
229 const struct GNUNET_HashCode *hash,
230 const struct GNUNET_PeerIdentity *identity);
231
232/**
233 * Encrypts a <i>message</i> using a given public <i>key</i> and replaces its body
234 * and kind with the now private encrypted <i>message</i>. The function returns
235 * #GNUNET_YES if the operation succeeded, otherwise #GNUNET_NO.
236 *
237 * @param[in,out] message Message
238 * @param[in] key Public key
239 * @return #GNUNET_YES on success, otherwise #GNUNET_NO
240 */
241enum GNUNET_GenericReturnValue
242encrypt_message (struct GNUNET_MESSENGER_Message *message,
243 const struct GNUNET_CRYPTO_PublicKey *key);
244
245/**
246 * Decrypts a private <i>message</i> using a given private <i>key</i> and replaces its body
247 * and kind with the inner encrypted message. The function returns #GNUNET_YES if the
248 * operation succeeded, otherwise #GNUNET_NO.
249 *
250 * @param[in,out] message Message
251 * @param[in] key Private key
252 * @return #GNUNET_YES on success, otherwise #GNUNET_NO
253 */
254enum GNUNET_GenericReturnValue
255decrypt_message (struct GNUNET_MESSENGER_Message *message,
256 const struct GNUNET_CRYPTO_PrivateKey *key);
257
258/**
259 * Transcribes a <i>message</i> as a new transcript message using a given public
260 * <i>key</i> from the recipient of the encrypted message content.
261 *
262 * @param[in] message Message
263 * @param[in] key Public key
264 * @return Message transcript
265 */
266struct GNUNET_MESSENGER_Message*
267transcribe_message (const struct GNUNET_MESSENGER_Message *message,
268 const struct GNUNET_CRYPTO_PublicKey *key);
269
270/**
271 * Read the original message from a transcript <i>message</i> and replaces its body
272 * and kind with the inner encrypted message. The function returns #GNUNET_YES if the
273 * operation succeeded, otherwise #GNUNET_NO.
274 *
275 * @param[in,out] transcript Message transcript
276 * @return #GNUNET_YES on success, otherwise #GNUNET_NO
277 */
278enum GNUNET_GenericReturnValue
279read_transcript_message (struct GNUNET_MESSENGER_Message *message);
280
281typedef void (*GNUNET_MESSENGER_SignFunction)(
282 const void *cls,
283 struct GNUNET_MESSENGER_Message *message,
284 uint16_t length,
285 char *buffer,
286 const struct GNUNET_HashCode *hash
287 );
288
289enum GNUNET_MESSENGER_PackMode
290{
291 GNUNET_MESSENGER_PACK_MODE_ENVELOPE = 0x1,
292 GNUNET_MESSENGER_PACK_MODE_UNKNOWN = 0x0,
293};
294
295/**
296 * Encodes the <i>message</i> to pack it into a newly allocated envelope if <i>mode</i>
297 * is equal to #GNUNET_MESSENGER_PACK_MODE_ENVELOPE. Independent of the mode the message
298 * will be hashed if <i>hash</i> is not NULL and it will be signed if the <i>sign</i>
299 * function is not NULL.
300 *
301 * @param[out] message Message
302 * @param[out] hash Hash of message
303 * @param[in] sign Function to sign
304 * @param[in] mode Mode of packing
305 * @param[in,out] cls Closure for signing
306 * @return Envelope or NULL
307 */
308struct GNUNET_MQ_Envelope*
309pack_message (struct GNUNET_MESSENGER_Message *message,
310 struct GNUNET_HashCode *hash,
311 const GNUNET_MESSENGER_SignFunction sign,
312 enum GNUNET_MESSENGER_PackMode mode,
313 const void *cls);
314
315/**
316 * Returns whether a specific kind of message can be sent by the service without usage of a
317 * clients private key. The function returns #GNUNET_YES if the kind of message can be signed
318 * via a peer's identity, otherwise #GNUNET_NO.
319 *
320 * @param[in] message Message
321 * @return #GNUNET_YES if sending is allowed, #GNUNET_NO otherwise
322 */
323enum GNUNET_GenericReturnValue
324is_peer_message (const struct GNUNET_MESSENGER_Message *message);
325
326/**
327 * Returns whether a specific kind of message contains service critical information. That kind
328 * of information should not be encrypted via private messages for example to guarantee the
329 * service to work properly. The function returns #GNUNET_YES if the kind of message needs to
330 * be transferred accessible to all peers and their running service. It returns #GNUNET_NO
331 * if the message can be encrypted to specific subgroups of members without issues. If the kind
332 * of message is unknown it returns #GNUNET_SYSERR.
333 *
334 * @param[in] message Message
335 * @return #GNUNET_YES if encrypting is disallowed, #GNUNET_NO or #GNUNET_SYSERR otherwise
336 */
337enum GNUNET_GenericReturnValue
338is_service_message (const struct GNUNET_MESSENGER_Message *message);
339
340/**
341 * Returns whether a specific kind of message should be sent by a client. The function returns
342 * #GNUNET_YES or #GNUNET_NO for recommendations and #GNUNET_SYSERR for specific kinds
343 * of messages which should not be sent manually at all.
344 *
345 * @param[in] message Message
346 * @return #GNUNET_YES if sending is allowed, #GNUNET_NO or #GNUNET_SYSERR otherwise
347 */
348enum GNUNET_GenericReturnValue
349filter_message_sending (const struct GNUNET_MESSENGER_Message *message);
350
351#endif //GNUNET_MESSENGER_API_MESSAGE_H
diff --git a/src/service/messenger/messenger_api_message_control.c b/src/service/messenger/messenger_api_message_control.c
new file mode 100644
index 000000000..e8d0333dc
--- /dev/null
+++ b/src/service/messenger/messenger_api_message_control.c
@@ -0,0 +1,251 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/messenger_api_message_control.c
23 * @brief messenger api: client and service implementation of GNUnet MESSENGER service
24 */
25
26#include "messenger_api_message_control.h"
27
28#include "gnunet_common.h"
29#include "gnunet_messenger_service.h"
30#include "gnunet_scheduler_lib.h"
31#include "messenger_api_contact.h"
32#include "messenger_api_contact_store.h"
33#include "messenger_api_handle.h"
34#include "messenger_api_message.h"
35#include "messenger_api_room.h"
36
37struct GNUNET_MESSENGER_MessageControl*
38create_message_control (struct GNUNET_MESSENGER_Room *room)
39{
40 GNUNET_assert (room);
41
42 struct GNUNET_MESSENGER_MessageControl *control;
43
44 control = GNUNET_new (struct GNUNET_MESSENGER_MessageControl);
45 control->room = room;
46
47 control->peer_messages = GNUNET_CONTAINER_multishortmap_create (8, GNUNET_NO);
48 control->member_messages = GNUNET_CONTAINER_multishortmap_create (8,
49 GNUNET_NO);
50
51 control->head = NULL;
52 control->tail = NULL;
53
54 return control;
55}
56
57
58void
59destroy_message_control (struct GNUNET_MESSENGER_MessageControl *control)
60{
61 GNUNET_assert (control);
62
63 struct GNUNET_MESSENGER_MessageControlQueue *queue;
64 while (control->head)
65 {
66 queue = control->head;
67
68 if (queue->task)
69 GNUNET_SCHEDULER_cancel (queue->task);
70
71 destroy_message (queue->message);
72
73 GNUNET_CONTAINER_DLL_remove (control->head, control->tail, queue);
74 GNUNET_free (queue);
75 }
76
77 GNUNET_CONTAINER_multishortmap_destroy (control->peer_messages);
78 GNUNET_CONTAINER_multishortmap_destroy (control->member_messages);
79
80 GNUNET_free (control);
81}
82
83
84static void
85enqueue_message_control (struct GNUNET_MESSENGER_MessageControl *control,
86 const struct GNUNET_HashCode *sender,
87 const struct GNUNET_HashCode *context,
88 const struct GNUNET_HashCode *hash,
89 const struct GNUNET_MESSENGER_Message *message,
90 enum GNUNET_MESSENGER_MessageFlags flags)
91{
92 GNUNET_assert ((control) && (sender) && (context) && (hash) && (message));
93
94 struct GNUNET_CONTAINER_MultiShortmap *map;
95 if (GNUNET_YES == is_peer_message (message))
96 map = control->peer_messages;
97 else
98 map = control->member_messages;
99
100 struct GNUNET_MESSENGER_MessageControlQueue *queue;
101
102 queue = GNUNET_new (struct GNUNET_MESSENGER_MessageControlQueue);
103 queue->control = control;
104
105 GNUNET_memcpy (&(queue->sender), sender, sizeof (queue->sender));
106 GNUNET_memcpy (&(queue->context), context, sizeof (queue->context));
107 GNUNET_memcpy (&(queue->hash), hash, sizeof (queue->hash));
108
109 queue->message = copy_message (message);
110 queue->flags = flags;
111 queue->task = NULL;
112
113 GNUNET_CONTAINER_DLL_insert (control->head, control->tail, queue);
114
115 GNUNET_CONTAINER_multishortmap_put (map,
116 &(message->header.sender_id),
117 queue,
118 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
119}
120
121
122static void
123handle_message_control (struct GNUNET_MESSENGER_MessageControl *control,
124 struct GNUNET_MESSENGER_Contact *contact,
125 const struct GNUNET_HashCode *hash,
126 const struct GNUNET_MESSENGER_Message *message,
127 enum GNUNET_MESSENGER_MessageFlags flags)
128{
129 GNUNET_assert ((control) && (hash) && (message));
130
131 handle_room_message (control->room, contact, message, hash, flags);
132
133 if (flags & GNUNET_MESSENGER_FLAG_RECENT)
134 update_room_last_message (control->room, hash);
135
136 callback_room_message (control->room, hash);
137}
138
139
140static void
141task_message_control (void *cls)
142{
143 GNUNET_assert (cls);
144
145 struct GNUNET_MESSENGER_MessageControlQueue *queue = cls;
146 struct GNUNET_MESSENGER_MessageControl *control = queue->control;
147
148 queue->task = NULL;
149
150 struct GNUNET_MESSENGER_Handle *handle = get_room_handle (control->room);
151 struct GNUNET_MESSENGER_ContactStore *store = get_handle_contact_store (
152 handle);
153
154 struct GNUNET_MESSENGER_Contact *contact = get_store_contact_raw (
155 store, &(queue->context), &(queue->sender));
156
157 struct GNUNET_CONTAINER_MultiShortmap *map;
158 if (GNUNET_YES == is_peer_message (queue->message))
159 map = control->peer_messages;
160 else
161 map = control->member_messages;
162
163 GNUNET_CONTAINER_multishortmap_remove (map,
164 &(queue->message->header.sender_id),
165 queue);
166
167 GNUNET_CONTAINER_DLL_remove (control->head, control->tail, queue);
168
169 handle_message_control (control,
170 contact,
171 &(queue->hash),
172 queue->message,
173 queue->flags);
174
175 destroy_message (queue->message);
176
177 GNUNET_free (queue);
178}
179
180
181static enum GNUNET_GenericReturnValue
182iterate_message_control (void *cls,
183 const struct GNUNET_ShortHashCode *key,
184 void *value)
185{
186 GNUNET_assert ((key) && (value));
187
188 struct GNUNET_MESSENGER_MessageControlQueue *queue = value;
189
190 if (queue->task)
191 return GNUNET_YES;
192
193 queue->task = GNUNET_SCHEDULER_add_now (task_message_control, queue);
194 return GNUNET_YES;
195}
196
197
198void
199process_message_control (struct GNUNET_MESSENGER_MessageControl *control,
200 const struct GNUNET_HashCode *sender,
201 const struct GNUNET_HashCode *context,
202 const struct GNUNET_HashCode *hash,
203 const struct GNUNET_MESSENGER_Message *message,
204 enum GNUNET_MESSENGER_MessageFlags flags)
205{
206 GNUNET_assert ((control) && (sender) && (context) && (hash) && (message));
207
208 struct GNUNET_MESSENGER_Handle *handle = get_room_handle (control->room);
209 struct GNUNET_MESSENGER_ContactStore *store = get_handle_contact_store (
210 handle);
211
212 struct GNUNET_MESSENGER_Contact *contact = get_store_contact_raw (
213 store, context, sender);
214
215 if ((! contact) &&
216 (GNUNET_MESSENGER_KIND_JOIN != message->header.kind) &&
217 (GNUNET_MESSENGER_KIND_PEER != message->header.kind))
218 enqueue_message_control (control, sender, context, hash, message, flags);
219 else
220 handle_message_control (control, contact, hash, message, flags);
221
222 struct GNUNET_CONTAINER_MultiShortmap *map = NULL;
223 const struct GNUNET_ShortHashCode *id = &(message->header.sender_id);
224
225 if (GNUNET_YES == is_peer_message (message))
226 map = control->peer_messages;
227
228 switch (message->header.kind)
229 {
230 case GNUNET_MESSENGER_KIND_JOIN:
231 map = control->member_messages;
232 break;
233 case GNUNET_MESSENGER_KIND_PEER:
234 map = control->peer_messages;
235 break;
236 case GNUNET_MESSENGER_KIND_ID:
237 map = control->member_messages;
238 id = &(message->body.id.id);
239 break;
240 default:
241 break;
242 }
243
244 if (! map)
245 return;
246
247 GNUNET_CONTAINER_multishortmap_get_multiple (map,
248 id,
249 iterate_message_control,
250 NULL);
251}
diff --git a/src/service/messenger/messenger_api_message_control.h b/src/service/messenger/messenger_api_message_control.h
new file mode 100644
index 000000000..a990210f0
--- /dev/null
+++ b/src/service/messenger/messenger_api_message_control.h
@@ -0,0 +1,105 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/messenger_api_message_control.h
23 * @brief messenger api: client and service implementation of GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_MESSENGER_API_MESSAGE_CONTROL_H
27#define GNUNET_MESSENGER_API_MESSAGE_CONTROL_H
28
29#include "gnunet_common.h"
30#include "gnunet_messenger_service.h"
31#include "gnunet_util_lib.h"
32
33struct GNUNET_MESSENGER_Message;
34struct GNUNET_MESSENGER_MessageControl;
35
36struct GNUNET_MESSENGER_MessageControlQueue
37{
38 struct GNUNET_MESSENGER_MessageControl *control;
39
40 struct GNUNET_HashCode sender;
41 struct GNUNET_HashCode context;
42 struct GNUNET_HashCode hash;
43
44 struct GNUNET_MESSENGER_Message *message;
45 enum GNUNET_MESSENGER_MessageFlags flags;
46 struct GNUNET_SCHEDULER_Task *task;
47
48 struct GNUNET_MESSENGER_MessageControlQueue *prev;
49 struct GNUNET_MESSENGER_MessageControlQueue *next;
50};
51
52struct GNUNET_MESSENGER_Room;
53
54struct GNUNET_MESSENGER_MessageControl
55{
56 struct GNUNET_MESSENGER_Room *room;
57
58 struct GNUNET_CONTAINER_MultiShortmap *peer_messages;
59 struct GNUNET_CONTAINER_MultiShortmap *member_messages;
60
61 struct GNUNET_MESSENGER_MessageControlQueue *head;
62 struct GNUNET_MESSENGER_MessageControlQueue *tail;
63};
64
65/**
66 * Creates and allocates a new message control for a <i>room</i> of the client API.
67 *
68 * @param[in,out] room Room
69 * @return New message control
70 */
71struct GNUNET_MESSENGER_MessageControl*
72create_message_control (struct GNUNET_MESSENGER_Room *room);
73
74/**
75 * Destroys a message control and frees its memory fully from the client API.
76 *
77 * @param[in,out] control Message control
78 */
79void
80destroy_message_control (struct GNUNET_MESSENGER_MessageControl *control);
81
82/**
83 * Processes a new <i>message</i> with its <i>hash</i> and regarding information about
84 * <i>sender</i>, <i>context</i> and message <i>flags</i> using a selected message
85 * <i>control</i>.
86 *
87 * The message control will ensure order of messages so that senders of messages
88 * can be identified via previously processed messages.
89 *
90 * @param[in,out] control Message control
91 * @param[in] sender Sender hash
92 * @param[in] context Context hash
93 * @param[in] hash Message hash
94 * @param[in] message Message
95 * @param[in] flags Message flags
96 */
97void
98process_message_control (struct GNUNET_MESSENGER_MessageControl *control,
99 const struct GNUNET_HashCode *sender,
100 const struct GNUNET_HashCode *context,
101 const struct GNUNET_HashCode *hash,
102 const struct GNUNET_MESSENGER_Message *message,
103 enum GNUNET_MESSENGER_MessageFlags flags);
104
105#endif //GNUNET_MESSENGER_API_MESSAGE_CONTROL_H \ No newline at end of file
diff --git a/src/service/messenger/messenger_api_message_kind.c b/src/service/messenger/messenger_api_message_kind.c
new file mode 100644
index 000000000..d423c5dda
--- /dev/null
+++ b/src/service/messenger/messenger_api_message_kind.c
@@ -0,0 +1,209 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/messenger_api_message_kind.c
23 * @brief messenger api: client and service implementation of GNUnet MESSENGER service
24 */
25
26#include "messenger_api_message_kind.h"
27
28#include "messenger_api_message.h"
29
30struct GNUNET_MESSENGER_Message*
31create_message_join (const struct GNUNET_CRYPTO_PrivateKey *key)
32{
33 if (! key)
34 return NULL;
35
36 struct GNUNET_MESSENGER_Message *message = create_message (
37 GNUNET_MESSENGER_KIND_JOIN);
38
39 if (! message)
40 return NULL;
41
42 GNUNET_CRYPTO_key_get_public (key, &(message->body.join.key));
43 return message;
44}
45
46
47struct GNUNET_MESSENGER_Message*
48create_message_leave ()
49{
50 return create_message (GNUNET_MESSENGER_KIND_LEAVE);
51}
52
53
54struct GNUNET_MESSENGER_Message*
55create_message_name (const char *name)
56{
57 if (! name)
58 return NULL;
59
60 struct GNUNET_MESSENGER_Message *message = create_message (
61 GNUNET_MESSENGER_KIND_NAME);
62
63 if (! message)
64 return NULL;
65
66 message->body.name.name = GNUNET_strdup (name);
67 return message;
68}
69
70
71struct GNUNET_MESSENGER_Message*
72create_message_key (const struct GNUNET_CRYPTO_PrivateKey *key)
73{
74 if (! key)
75 return NULL;
76
77 struct GNUNET_MESSENGER_Message *message = create_message (
78 GNUNET_MESSENGER_KIND_KEY);
79
80 if (! message)
81 return NULL;
82
83 GNUNET_CRYPTO_key_get_public (key, &(message->body.key.key));
84 return message;
85}
86
87
88struct GNUNET_MESSENGER_Message*
89create_message_id (const struct GNUNET_ShortHashCode *unique_id)
90{
91 if (! unique_id)
92 return NULL;
93
94 struct GNUNET_MESSENGER_Message *message = create_message (
95 GNUNET_MESSENGER_KIND_ID);
96
97 if (! message)
98 return NULL;
99
100 GNUNET_memcpy (&(message->body.id.id), unique_id, sizeof(struct
101 GNUNET_ShortHashCode)
102 );
103
104 return message;
105}
106
107
108struct GNUNET_MESSENGER_Message*
109create_message_request (const struct GNUNET_HashCode *hash)
110{
111 if (! hash)
112 return NULL;
113
114 struct GNUNET_HashCode zero;
115 memset (&zero, 0, sizeof(zero));
116
117 if (0 == GNUNET_CRYPTO_hash_cmp (hash, &zero))
118 return NULL;
119
120 struct GNUNET_MESSENGER_Message *message = create_message (
121 GNUNET_MESSENGER_KIND_REQUEST);
122
123 if (! message)
124 return NULL;
125
126 GNUNET_memcpy (&(message->body.request.hash), hash, sizeof(struct
127 GNUNET_HashCode));
128
129 return message;
130}
131
132
133struct GNUNET_MESSENGER_Message*
134create_message_invite (const struct GNUNET_PeerIdentity *door,
135 const struct GNUNET_HashCode *key)
136{
137 if ((! door) || (! key))
138 return NULL;
139
140 struct GNUNET_MESSENGER_Message *message = create_message (
141 GNUNET_MESSENGER_KIND_INVITE);
142
143 if (! message)
144 return NULL;
145
146 GNUNET_memcpy (&(message->body.invite.door), door, sizeof(struct
147 GNUNET_PeerIdentity)
148 );
149 GNUNET_memcpy (&(message->body.invite.key), key, sizeof(struct
150 GNUNET_HashCode));
151
152 return message;
153}
154
155
156struct GNUNET_MESSENGER_Message*
157create_message_text (const char *text)
158{
159 if (! text)
160 return NULL;
161
162 struct GNUNET_MESSENGER_Message *message = create_message (
163 GNUNET_MESSENGER_KIND_TEXT);
164
165 if (! message)
166 return NULL;
167
168 message->body.text.text = GNUNET_strdup (text);
169 return message;
170}
171
172
173struct GNUNET_MESSENGER_Message*
174create_message_delete (const struct GNUNET_HashCode *hash,
175 const struct GNUNET_TIME_Relative delay)
176{
177 if (! hash)
178 return NULL;
179
180 struct GNUNET_MESSENGER_Message *message = create_message (
181 GNUNET_MESSENGER_KIND_DELETE);
182
183 if (! message)
184 return NULL;
185
186 GNUNET_memcpy (&(message->body.deletion.hash), hash, sizeof(struct
187 GNUNET_HashCode));
188 message->body.deletion.delay = GNUNET_TIME_relative_hton (delay);
189
190 return message;
191}
192
193
194struct GNUNET_MESSENGER_Message*
195create_message_ticket (const struct GNUNET_RECLAIM_Ticket *ticket)
196{
197 if (! ticket)
198 return NULL;
199
200 struct GNUNET_MESSENGER_Message *message = create_message (
201 GNUNET_MESSENGER_KIND_TICKET);
202
203 if (! message)
204 return NULL;
205
206 message->body.ticket.identifier = GNUNET_strdup (ticket->gns_name);
207
208 return message;
209}
diff --git a/src/service/messenger/messenger_api_message_kind.h b/src/service/messenger/messenger_api_message_kind.h
new file mode 100644
index 000000000..5f4107f61
--- /dev/null
+++ b/src/service/messenger/messenger_api_message_kind.h
@@ -0,0 +1,138 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/messenger_api_message_kind.h
23 * @brief messenger api: client and service implementation of GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_MESSENGER_API_MESSAGE_KIND_H
27#define GNUNET_MESSENGER_API_MESSAGE_KIND_H
28
29#include "gnunet_messenger_service.h"
30#include "gnunet_reclaim_service.h"
31#include "gnunet_util_lib.h"
32
33/**
34 * Creates and allocates a new join message containing the clients public <i>key</i>.
35 * (all values are stored as copy)
36 *
37 * @param[in] key Private key
38 * @return New message
39 */
40struct GNUNET_MESSENGER_Message*
41create_message_join (const struct GNUNET_CRYPTO_PrivateKey *key);
42
43/**
44 * Creates and allocates a new leave message.
45 *
46 * @return New message
47 */
48struct GNUNET_MESSENGER_Message*
49create_message_leave ();
50
51/**
52 * Creates and allocates a new name message containing the <i>name</i> to change to.
53 * (all values are stored as copy)
54 *
55 * @param[in] name New name
56 * @return New message
57 */
58struct GNUNET_MESSENGER_Message*
59create_message_name (const char *name);
60
61/**
62 * Creates and allocates a new key message containing the public <i>key</i> to change to derived
63 * from its private counterpart. (all values are stored as copy)
64 *
65 * @param[in] key Private key
66 * @return New message
67 */
68struct GNUNET_MESSENGER_Message*
69create_message_key (const struct GNUNET_CRYPTO_PrivateKey *key);
70
71/**
72 * Creates and allocates a new id message containing the unique member id to change to.
73 * (all values are stored as copy)
74 *
75 * @param[in] unique_id Unique member id
76 * @return New message
77 */
78struct GNUNET_MESSENGER_Message*
79create_message_id (const struct GNUNET_ShortHashCode *unique_id);
80
81/**
82 * Creates and allocates a new request message containing the <i>hash</i> of a missing message.
83 * (all values are stored as copy)
84 *
85 * @param[in] hash Hash of message
86 * @return New message
87 */
88struct GNUNET_MESSENGER_Message*
89create_message_request (const struct GNUNET_HashCode *hash);
90
91/**
92 * Creates and allocates a new invite message containing the peer identity of an entrance peer
93 * to a room using a given <i>key</i> as shared secret for communication.
94 * (all values are stored as copy)
95 *
96 * @param[in] door Peer identity
97 * @param[in] key Shared secret of a room
98 * @return New message
99 */
100struct GNUNET_MESSENGER_Message*
101create_message_invite (const struct GNUNET_PeerIdentity *door,
102 const struct GNUNET_HashCode *key);
103
104/**
105 * Creates and allocates a new <i>text</i> message containing a string representing text.
106 * (all values are stored as copy)
107 *
108 * @param[in] text Text
109 * @return New message
110 */
111struct GNUNET_MESSENGER_Message*
112create_message_text (const char *text);
113
114/**
115 * Creates and allocates a new delete message containing the <i>hash</i> of a message to delete
116 * after a specific <i>delay</i>.
117 * (all values are stored as copy)
118 *
119 * @param[in] hash Hash of message
120 * @param[in] delay Delay of deletion
121 * @return New message
122 */
123struct GNUNET_MESSENGER_Message*
124create_message_delete (const struct GNUNET_HashCode *hash,
125 const struct GNUNET_TIME_Relative delay);
126
127/**
128 * Creates and allocates a new ticket message containing the <i>identifier</i> of a ticket to
129 * exchange it with a given audience.
130 * (all values are stored as copy)
131 *
132 * @param[in] identifier Identifier of ticket
133 * @return New message
134 */
135struct GNUNET_MESSENGER_Message*
136create_message_ticket (const struct GNUNET_RECLAIM_Ticket *ticket);
137
138#endif //GNUNET_MESSENGER_API_MESSAGE_KIND_H
diff --git a/src/service/messenger/messenger_api_queue_messages.c b/src/service/messenger/messenger_api_queue_messages.c
new file mode 100644
index 000000000..33e591da3
--- /dev/null
+++ b/src/service/messenger/messenger_api_queue_messages.c
@@ -0,0 +1,133 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2023--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/messenger_api_queue_messages.c
23 * @brief messenger api: client implementation of GNUnet MESSENGER service
24 */
25
26#include "messenger_api_queue_messages.h"
27
28#include "gnunet_messenger_service.h"
29#include "messenger_api_message.h"
30
31void
32init_queue_messages (struct GNUNET_MESSENGER_QueueMessages *messages)
33{
34 GNUNET_assert (messages);
35
36 messages->head = NULL;
37 messages->tail = NULL;
38}
39
40
41void
42clear_queue_messages (struct GNUNET_MESSENGER_QueueMessages *messages)
43{
44 GNUNET_assert (messages);
45
46 while (messages->head)
47 {
48 struct GNUNET_MESSENGER_QueueMessage *element = messages->head;
49
50 GNUNET_CONTAINER_DLL_remove (messages->head, messages->tail, element);
51
52 if (element->message)
53 destroy_message (element->message);
54
55 if (element->transcript)
56 destroy_message (element->transcript);
57
58 GNUNET_free (element);
59 }
60
61 messages->head = NULL;
62 messages->tail = NULL;
63}
64
65
66void
67enqueue_to_messages (struct GNUNET_MESSENGER_QueueMessages *messages,
68 const struct GNUNET_CRYPTO_PrivateKey *sender,
69 struct GNUNET_MESSENGER_Message *message,
70 struct GNUNET_MESSENGER_Message *transcript,
71 enum GNUNET_GenericReturnValue priority)
72{
73 GNUNET_assert ((messages) && (sender) && (message));
74
75 struct GNUNET_MESSENGER_QueueMessage *element = GNUNET_new (struct
76 GNUNET_MESSENGER_QueueMessage);
77
78 if (! element)
79 return;
80
81 element->message = message;
82 element->transcript = transcript;
83
84 GNUNET_memcpy (&(element->sender), sender, sizeof (element->sender));
85
86 if (! element->message)
87 {
88 if (element->transcript)
89 destroy_message (element->transcript);
90
91 GNUNET_free (element);
92 return;
93 }
94
95 if (GNUNET_YES == priority)
96 GNUNET_CONTAINER_DLL_insert (messages->head, messages->tail, element);
97 else
98 GNUNET_CONTAINER_DLL_insert_tail (messages->head, messages->tail, element);
99}
100
101
102struct GNUNET_MESSENGER_Message*
103dequeue_from_messages (struct GNUNET_MESSENGER_QueueMessages *messages,
104 struct GNUNET_CRYPTO_PrivateKey *sender,
105 struct GNUNET_MESSENGER_Message **transcript)
106{
107 GNUNET_assert (messages);
108
109 struct GNUNET_MESSENGER_QueueMessage *element = messages->head;
110
111 if (! element)
112 {
113 if (transcript)
114 *transcript = NULL;
115
116 return NULL;
117 }
118
119 struct GNUNET_MESSENGER_Message *message = element->message;
120
121 if (transcript)
122 *transcript = element->transcript;
123 else if (element->transcript)
124 destroy_message (element->transcript);
125
126 GNUNET_CONTAINER_DLL_remove (messages->head, messages->tail, element);
127
128 if (sender)
129 GNUNET_memcpy (sender, &(element->sender), sizeof (*sender));
130
131 GNUNET_free (element);
132 return message;
133}
diff --git a/src/service/messenger/messenger_api_queue_messages.h b/src/service/messenger/messenger_api_queue_messages.h
new file mode 100644
index 000000000..aeed2e5d9
--- /dev/null
+++ b/src/service/messenger/messenger_api_queue_messages.h
@@ -0,0 +1,94 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2023--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/messenger_api_queue_messages.h
23 * @brief messenger api: client implementation of GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_MESSENGER_API_QUEUE_MESSAGES_H
27#define GNUNET_MESSENGER_API_QUEUE_MESSAGES_H
28
29#include "gnunet_util_lib.h"
30
31struct GNUNET_MESSENGER_QueueMessage
32{
33 struct GNUNET_MESSENGER_QueueMessage *prev;
34 struct GNUNET_MESSENGER_QueueMessage *next;
35
36 struct GNUNET_CRYPTO_PrivateKey sender;
37
38 struct GNUNET_MESSENGER_Message *message;
39 struct GNUNET_MESSENGER_Message *transcript;
40};
41
42struct GNUNET_MESSENGER_QueueMessages
43{
44 struct GNUNET_MESSENGER_QueueMessage *head;
45 struct GNUNET_MESSENGER_QueueMessage *tail;
46};
47
48/**
49 * Initializes queue of messages as empty queue.
50 *
51 * @param[out] messages Queue of messages
52 */
53void
54init_queue_messages (struct GNUNET_MESSENGER_QueueMessages *messages);
55
56/**
57 * Clears the queue of messages.
58 *
59 * @param[in,out] messages Queue of messages
60 */
61void
62clear_queue_messages (struct GNUNET_MESSENGER_QueueMessages *messages);
63
64/**
65 * Adds a specific <i>message</i> to the end or the beginning of
66 * the queue depending on its <i>priority</i>.
67 *
68 * @param[in,out] messages Queue of messages
69 * @param[in] sender Private sender key
70 * @param[in] message Message
71 * @param[in] transcript Message transcript
72 * @param[in] priority Whether the message has priority
73 */
74void
75enqueue_to_messages (struct GNUNET_MESSENGER_QueueMessages *messages,
76 const struct GNUNET_CRYPTO_PrivateKey *sender,
77 struct GNUNET_MESSENGER_Message *message,
78 struct GNUNET_MESSENGER_Message *transcript,
79 enum GNUNET_GenericReturnValue priority);
80
81/**
82 * Remove the message from the front of the queue and returns it.
83 *
84 * @param[in,out] messages Queue of messages
85 * @param[out] sender Private sender key
86 * @param[out] transcript Message transcript
87 * @return Message from front or NULL
88 */
89struct GNUNET_MESSENGER_Message*
90dequeue_from_messages (struct GNUNET_MESSENGER_QueueMessages *messages,
91 struct GNUNET_CRYPTO_PrivateKey *sender,
92 struct GNUNET_MESSENGER_Message **transcript);
93
94#endif //GNUNET_MESSENGER_API_QUEUE_MESSAGES_H
diff --git a/src/service/messenger/messenger_api_room.c b/src/service/messenger/messenger_api_room.c
new file mode 100644
index 000000000..cddd43b22
--- /dev/null
+++ b/src/service/messenger/messenger_api_room.c
@@ -0,0 +1,913 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/messenger_api_room.c
23 * @brief messenger api: client implementation of GNUnet MESSENGER service
24 */
25
26#include "messenger_api_room.h"
27
28#include "gnunet_common.h"
29#include "gnunet_messenger_service.h"
30#include "messenger_api_contact_store.h"
31#include "messenger_api_handle.h"
32#include "messenger_api_message.h"
33#include "messenger_api_message_control.h"
34#include <string.h>
35
36struct GNUNET_MESSENGER_Room*
37create_room (struct GNUNET_MESSENGER_Handle *handle,
38 const struct GNUNET_HashCode *key)
39{
40 GNUNET_assert ((handle) && (key));
41
42 struct GNUNET_MESSENGER_Room *room = GNUNET_new (struct
43 GNUNET_MESSENGER_Room);
44
45 room->handle = handle;
46 GNUNET_memcpy (&(room->key), key, sizeof(*key));
47
48 memset (&(room->last_message), 0, sizeof(room->last_message));
49
50 room->opened = GNUNET_NO;
51 room->use_handle_name = GNUNET_YES;
52 room->wait_for_sync = GNUNET_NO;
53
54 room->sender_id = NULL;
55
56 init_list_tunnels (&(room->entries));
57
58 room->messages = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
59 room->members = GNUNET_CONTAINER_multishortmap_create (8, GNUNET_NO);
60 room->links = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
61
62 init_queue_messages (&(room->queue));
63
64 room->control = create_message_control (room);
65
66 return room;
67}
68
69
70static enum GNUNET_GenericReturnValue
71iterate_destroy_message (void *cls,
72 const struct GNUNET_HashCode *key,
73 void *value)
74{
75 struct GNUNET_MESSENGER_RoomMessageEntry *entry = value;
76
77 destroy_message (entry->message);
78 GNUNET_free (entry);
79
80 return GNUNET_YES;
81}
82
83
84static enum GNUNET_GenericReturnValue
85iterate_destroy_link (void *cls,
86 const struct GNUNET_HashCode *key,
87 void *value)
88{
89 struct GNUNET_HashCode *hash = value;
90 GNUNET_free (hash);
91 return GNUNET_YES;
92}
93
94
95void
96destroy_room (struct GNUNET_MESSENGER_Room *room)
97{
98 GNUNET_assert (room);
99
100 destroy_message_control (room->control);
101
102 clear_queue_messages (&(room->queue));
103 clear_list_tunnels (&(room->entries));
104
105 if (room->messages)
106 {
107 GNUNET_CONTAINER_multihashmap_iterate (room->messages,
108 iterate_destroy_message, NULL);
109
110 GNUNET_CONTAINER_multihashmap_destroy (room->messages);
111 }
112
113 if (room->members)
114 GNUNET_CONTAINER_multishortmap_destroy (room->members);
115
116 if (room->links)
117 {
118 GNUNET_CONTAINER_multihashmap_iterate (room->links,
119 iterate_destroy_link, NULL);
120
121 GNUNET_CONTAINER_multihashmap_destroy (room->links);
122 }
123
124 if (room->sender_id)
125 GNUNET_free (room->sender_id);
126
127 GNUNET_free (room);
128}
129
130
131enum GNUNET_GenericReturnValue
132is_room_available (const struct GNUNET_MESSENGER_Room *room)
133{
134 GNUNET_assert (room);
135
136 if (! get_room_sender_id (room))
137 return GNUNET_NO;
138
139 if ((GNUNET_YES == room->opened) || (room->entries.head))
140 return GNUNET_YES;
141 else
142 return GNUNET_NO;
143}
144
145
146struct GNUNET_MESSENGER_Handle*
147get_room_handle (struct GNUNET_MESSENGER_Room *room)
148{
149 GNUNET_assert (room);
150
151 return room->handle;
152}
153
154
155const struct GNUNET_ShortHashCode*
156get_room_sender_id (const struct GNUNET_MESSENGER_Room *room)
157{
158 GNUNET_assert (room);
159
160 return room->sender_id;
161}
162
163
164void
165set_room_sender_id (struct GNUNET_MESSENGER_Room *room,
166 const struct GNUNET_ShortHashCode *id)
167{
168 GNUNET_assert (room);
169
170 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Set member id for room: %s\n",
171 GNUNET_h2s (&(room->key)));
172
173 if (! id)
174 {
175 if (room->sender_id)
176 GNUNET_free (room->sender_id);
177
178 room->sender_id = NULL;
179 return;
180 }
181
182 if (! room->sender_id)
183 room->sender_id = GNUNET_new (struct GNUNET_ShortHashCode);
184
185 GNUNET_memcpy (room->sender_id, id, sizeof(struct GNUNET_ShortHashCode));
186}
187
188
189const struct GNUNET_MESSENGER_Message*
190get_room_message (const struct GNUNET_MESSENGER_Room *room,
191 const struct GNUNET_HashCode *hash)
192{
193 GNUNET_assert ((room) && (hash));
194
195 struct GNUNET_MESSENGER_RoomMessageEntry *entry =
196 GNUNET_CONTAINER_multihashmap_get (
197 room->messages, hash);
198
199 if ((! entry) || (GNUNET_YES != entry->completed))
200 return NULL;
201
202 return entry->message;
203}
204
205
206struct GNUNET_MESSENGER_Contact*
207get_room_sender (const struct GNUNET_MESSENGER_Room *room,
208 const struct GNUNET_HashCode *hash)
209{
210 GNUNET_assert ((room) && (hash));
211
212 struct GNUNET_MESSENGER_RoomMessageEntry *entry =
213 GNUNET_CONTAINER_multihashmap_get (
214 room->messages, hash);
215
216 if ((! entry) || (GNUNET_YES != entry->completed))
217 return NULL;
218
219 return entry->sender;
220}
221
222
223struct GNUNET_MESSENGER_Contact*
224get_room_recipient (const struct GNUNET_MESSENGER_Room *room,
225 const struct GNUNET_HashCode *hash)
226{
227 GNUNET_assert ((room) && (hash));
228
229 struct GNUNET_MESSENGER_RoomMessageEntry *entry =
230 GNUNET_CONTAINER_multihashmap_get (
231 room->messages, hash);
232
233 if ((! entry) || (GNUNET_YES != entry->completed))
234 return NULL;
235
236 return entry->recipient;
237}
238
239
240void
241callback_room_message (struct GNUNET_MESSENGER_Room *room,
242 const struct GNUNET_HashCode *hash)
243{
244 GNUNET_assert ((room) && (hash));
245
246 struct GNUNET_MESSENGER_Handle *handle = room->handle;
247
248 if (! handle)
249 return;
250
251 struct GNUNET_MESSENGER_RoomMessageEntry *entry;
252 entry = GNUNET_CONTAINER_multihashmap_get (room->messages, hash);
253
254 if (! entry)
255 return;
256
257 if (handle->msg_callback)
258 handle->msg_callback (handle->msg_cls, room,
259 entry->sender,
260 entry->recipient,
261 entry->message,
262 hash,
263 entry->flags);
264
265 if (entry->flags & GNUNET_MESSENGER_FLAG_UPDATE)
266 entry->flags ^= GNUNET_MESSENGER_FLAG_UPDATE;
267}
268
269
270static void
271handle_message (struct GNUNET_MESSENGER_Room *room,
272 const struct GNUNET_HashCode *hash,
273 struct GNUNET_MESSENGER_RoomMessageEntry *entry);
274
275
276void
277handle_join_message (struct GNUNET_MESSENGER_Room *room,
278 const struct GNUNET_HashCode *hash,
279 struct GNUNET_MESSENGER_RoomMessageEntry *entry)
280{
281 GNUNET_assert ((room) && (hash) && (entry));
282
283 if (! entry->sender)
284 {
285 struct GNUNET_MESSENGER_ContactStore *store = get_handle_contact_store (
286 room->handle);
287 struct GNUNET_HashCode context;
288
289 get_context_from_member (&(room->key), &(entry->message->header.sender_id),
290 &context);
291
292 entry->sender = get_store_contact (store, &context,
293 &(entry->message->body.join.key));
294 }
295
296 if ((GNUNET_YES != GNUNET_CONTAINER_multishortmap_contains_value (
297 room->members, &(entry->message->header.sender_id), entry->sender)) &&
298 (GNUNET_OK == GNUNET_CONTAINER_multishortmap_put (room->members,
299 &(entry->message->header
300 .sender_id),
301 entry->sender,
302 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)))
303
304 increase_contact_rc (entry->sender);
305}
306
307
308static void
309handle_leave_message (struct GNUNET_MESSENGER_Room *room,
310 const struct GNUNET_HashCode *hash,
311 struct GNUNET_MESSENGER_RoomMessageEntry *entry)
312{
313 GNUNET_assert ((room) && (hash) && (entry));
314
315 if ((! entry->sender) ||
316 (GNUNET_YES != GNUNET_CONTAINER_multishortmap_remove (room->members,
317 &(entry->message->
318 header.sender_id),
319 entry->sender)))
320 return;
321
322 if (GNUNET_YES == decrease_contact_rc (entry->sender))
323 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
324 "A contact does not share any room with you anymore!\n");
325}
326
327
328static void
329handle_name_message (struct GNUNET_MESSENGER_Room *room,
330 const struct GNUNET_HashCode *hash,
331 struct GNUNET_MESSENGER_RoomMessageEntry *entry)
332{
333 GNUNET_assert ((room) && (hash) && (entry));
334
335 if (GNUNET_MESSENGER_FLAG_SENT & entry->flags)
336 {
337 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
338 "Set rule for using handle name in room: %s\n",
339 GNUNET_h2s (&(room->key)));
340
341 const char *handle_name = get_handle_name (room->handle);
342
343 if ((handle_name) && (0 == strcmp (handle_name,
344 entry->message->body.name.name)))
345 room->use_handle_name = GNUNET_YES;
346 }
347
348 if (! entry->sender)
349 return;
350
351 set_contact_name (entry->sender, entry->message->body.name.name);
352}
353
354
355static void
356handle_key_message (struct GNUNET_MESSENGER_Room *room,
357 const struct GNUNET_HashCode *hash,
358 struct GNUNET_MESSENGER_RoomMessageEntry *entry)
359{
360 GNUNET_assert ((room) && (hash) && (entry));
361
362 if (! entry->sender)
363 return;
364
365 struct GNUNET_HashCode context;
366 get_context_from_member (&(room->key), &(entry->message->header.sender_id),
367 &context);
368
369 struct GNUNET_MESSENGER_ContactStore *store = get_handle_contact_store (
370 room->handle);
371
372 update_store_contact (store, entry->sender, &context, &context,
373 &(entry->message->body.key.key));
374}
375
376
377static void
378handle_id_message (struct GNUNET_MESSENGER_Room *room,
379 const struct GNUNET_HashCode *hash,
380 struct GNUNET_MESSENGER_RoomMessageEntry *entry)
381{
382 GNUNET_assert ((room) && (hash) && (entry));
383
384 if (GNUNET_MESSENGER_FLAG_SENT & entry->flags)
385 set_room_sender_id (room, &(entry->message->body.id.id));
386
387 if ((! entry->sender) ||
388 (GNUNET_YES != GNUNET_CONTAINER_multishortmap_remove (room->members,
389 &(entry->message->
390 header.sender_id),
391 entry->sender)) ||
392 (GNUNET_OK != GNUNET_CONTAINER_multishortmap_put (room->members,
393 &(entry->message->body.
394 id.id),
395 entry->sender,
396 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)))
397
398 return;
399
400 struct GNUNET_HashCode context, next_context;
401 get_context_from_member (&(room->key), &(entry->message->header.sender_id),
402 &context);
403 get_context_from_member (&(room->key), &(entry->message->body.id.id),
404 &next_context);
405
406 struct GNUNET_MESSENGER_ContactStore *store = get_handle_contact_store (
407 room->handle);
408
409 update_store_contact (store, entry->sender, &context, &next_context,
410 get_contact_key (entry->sender));
411}
412
413
414static void
415handle_miss_message (struct GNUNET_MESSENGER_Room *room,
416 const struct GNUNET_HashCode *hash,
417 struct GNUNET_MESSENGER_RoomMessageEntry *entry)
418{
419 GNUNET_assert ((room) && (hash) && (entry));
420
421 if (0 == (GNUNET_MESSENGER_FLAG_SENT & entry->flags))
422 return;
423
424 struct GNUNET_MESSENGER_ListTunnel *match = find_list_tunnels (
425 &(room->entries), &(entry->message->body.miss.peer), NULL);
426
427 if (match)
428 remove_from_list_tunnels (&(room->entries), match);
429}
430
431
432static void
433handle_private_message (struct GNUNET_MESSENGER_Room *room,
434 const struct GNUNET_HashCode *hash,
435 struct GNUNET_MESSENGER_RoomMessageEntry *entry)
436{
437 GNUNET_assert ((room) && (hash) && (entry));
438
439 struct GNUNET_MESSENGER_Message *private_message = copy_message (
440 entry->message);
441
442 if (! private_message)
443 return;
444
445 if (GNUNET_YES != decrypt_message (private_message,
446 get_handle_key (room->handle)))
447 {
448 destroy_message (private_message);
449 private_message = NULL;
450 }
451
452 if (! private_message)
453 return;
454
455 destroy_message (entry->message);
456
457 entry->recipient = get_handle_contact (room->handle, &(room->key));
458
459 entry->message = private_message;
460 entry->flags |= GNUNET_MESSENGER_FLAG_PRIVATE;
461
462 if ((entry->sender) && (entry->recipient))
463 handle_message (room, hash, entry);
464}
465
466
467extern void
468delete_message_in_room (struct GNUNET_MESSENGER_Room *room,
469 const struct GNUNET_HashCode *hash,
470 const struct GNUNET_TIME_Relative delay);
471
472
473static void
474handle_delete_message (struct GNUNET_MESSENGER_Room *room,
475 const struct GNUNET_HashCode *hash,
476 struct GNUNET_MESSENGER_RoomMessageEntry *entry)
477{
478 GNUNET_assert ((room) && (hash) && (entry));
479
480 const struct GNUNET_HashCode *target_hash =
481 &(entry->message->body.deletion.hash);
482
483 if (get_handle_contact (room->handle, &(room->key)) == entry->sender)
484 {
485 struct GNUNET_TIME_Relative delay;
486 struct GNUNET_TIME_Absolute action;
487
488 delay = GNUNET_TIME_relative_ntoh (entry->message->body.deletion.delay);
489
490 action = GNUNET_TIME_absolute_ntoh (entry->message->header.timestamp);
491 action = GNUNET_TIME_absolute_add (action, delay);
492
493 delay = GNUNET_TIME_absolute_get_difference (GNUNET_TIME_absolute_get (),
494 action);
495
496 link_room_deletion (room, target_hash, delay, delete_message_in_room);
497 }
498
499 struct GNUNET_MESSENGER_RoomMessageEntry *target =
500 GNUNET_CONTAINER_multihashmap_get (room->messages, target_hash);
501
502 if (! target)
503 return;
504
505 if (((target->sender != entry->sender) &&
506 (get_handle_contact (room->handle, &(room->key)) != entry->sender)))
507 return;
508
509 target->flags |= GNUNET_MESSENGER_FLAG_DELETE;
510 callback_room_message (room, target_hash);
511
512 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (room->messages,
513 target_hash,
514 target))
515 {
516 destroy_message (target->message);
517 GNUNET_free (target);
518 }
519}
520
521
522static void
523handle_transcript_message (struct GNUNET_MESSENGER_Room *room,
524 const struct GNUNET_HashCode *hash,
525 struct GNUNET_MESSENGER_RoomMessageEntry *entry)
526{
527 GNUNET_assert ((room) && (hash) && (entry));
528
529 if (get_handle_contact (room->handle, &(room->key)) != entry->sender)
530 return;
531
532 const struct GNUNET_HashCode *original_hash =
533 &(entry->message->body.transcript.hash);
534 struct GNUNET_MESSENGER_ContactStore *store = get_handle_contact_store (
535 room->handle);
536
537 struct GNUNET_MESSENGER_RoomMessageEntry *original =
538 GNUNET_CONTAINER_multihashmap_get (room->messages, original_hash);
539 struct GNUNET_MESSENGER_Message *original_message;
540
541 if (original)
542 goto read_transcript;
543
544 original = GNUNET_new (struct GNUNET_MESSENGER_RoomMessageEntry);
545
546 if (! original)
547 return;
548
549 original->sender = NULL;
550 original->recipient = NULL;
551
552 original->message = NULL;
553 original->flags = GNUNET_MESSENGER_FLAG_NONE;
554 original->completed = GNUNET_NO;
555
556 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (room->messages,
557 original_hash,
558 original,
559 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
560 {
561 GNUNET_free (original);
562 return;
563 }
564
565read_transcript:
566 original_message = copy_message (entry->message);
567
568 if (! original_message)
569 return;
570
571 if (GNUNET_YES != read_transcript_message (original_message))
572 {
573 destroy_message (original_message);
574 return;
575 }
576
577 original->recipient = get_store_contact (store,
578 NULL,
579 &(entry->message->body.transcript.key
580 ));
581
582 if (original->message)
583 {
584 if (GNUNET_MESSENGER_KIND_PRIVATE == original->message->header.kind)
585 original->flags |= GNUNET_MESSENGER_FLAG_PRIVATE;
586
587 copy_message_header (original_message, &(original->message->header));
588 destroy_message (original->message);
589 }
590
591 original->message = original_message;
592
593 link_room_message (room, hash, original_hash);
594 link_room_message (room, original_hash, hash);
595
596 if ((original->sender) && (original->recipient))
597 {
598 original->flags |= GNUNET_MESSENGER_FLAG_UPDATE;
599 handle_message (room, original_hash, original);
600 }
601}
602
603
604static void
605handle_message (struct GNUNET_MESSENGER_Room *room,
606 const struct GNUNET_HashCode *hash,
607 struct GNUNET_MESSENGER_RoomMessageEntry *entry)
608{
609 GNUNET_assert ((room) && (hash) && (entry));
610
611 switch (entry->message->header.kind)
612 {
613 case GNUNET_MESSENGER_KIND_JOIN:
614 handle_join_message (room, hash, entry);
615 break;
616 case GNUNET_MESSENGER_KIND_LEAVE:
617 handle_leave_message (room, hash, entry);
618 break;
619 case GNUNET_MESSENGER_KIND_NAME:
620 handle_name_message (room, hash, entry);
621 break;
622 case GNUNET_MESSENGER_KIND_KEY:
623 handle_key_message (room, hash, entry);
624 break;
625 case GNUNET_MESSENGER_KIND_ID:
626 handle_id_message (room, hash, entry);
627 break;
628 case GNUNET_MESSENGER_KIND_MISS:
629 handle_miss_message (room, hash, entry);
630 break;
631 case GNUNET_MESSENGER_KIND_PRIVATE:
632 handle_private_message (room, hash, entry);
633 break;
634 case GNUNET_MESSENGER_KIND_DELETE:
635 handle_delete_message (room, hash, entry);
636 break;
637 case GNUNET_MESSENGER_KIND_TRANSCRIPT:
638 handle_transcript_message (room, hash, entry);
639 break;
640 default:
641 break;
642 }
643
644 if (entry->flags & GNUNET_MESSENGER_FLAG_UPDATE)
645 callback_room_message (room, hash);
646}
647
648
649void
650handle_room_message (struct GNUNET_MESSENGER_Room *room,
651 struct GNUNET_MESSENGER_Contact *sender,
652 const struct GNUNET_MESSENGER_Message *message,
653 const struct GNUNET_HashCode *hash,
654 enum GNUNET_MESSENGER_MessageFlags flags)
655{
656 GNUNET_assert ((room) && (message) && (hash));
657
658 struct GNUNET_MESSENGER_RoomMessageEntry *entry;
659 entry = GNUNET_CONTAINER_multihashmap_get (room->messages, hash);
660
661 if (entry)
662 goto update_entry;
663
664 entry = GNUNET_new (struct GNUNET_MESSENGER_RoomMessageEntry);
665
666 if (! entry)
667 return;
668
669 entry->sender = NULL;
670 entry->recipient = NULL;
671
672 entry->message = NULL;
673 entry->flags = GNUNET_MESSENGER_FLAG_NONE;
674 entry->completed = GNUNET_NO;
675
676 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (room->messages, hash,
677 entry,
678 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
679 {
680 GNUNET_free (entry);
681 return;
682 }
683
684update_entry:
685 entry->sender = sender;
686 entry->flags = flags;
687
688 if (entry->message)
689 {
690 if (GNUNET_MESSENGER_KIND_PRIVATE == message->header.kind)
691 entry->flags |= GNUNET_MESSENGER_FLAG_PRIVATE;
692
693 copy_message_header (entry->message, &(message->header));
694 }
695 else
696 entry->message = copy_message (message);
697
698 entry->completed = GNUNET_YES;
699
700 handle_message (room, hash, entry);
701}
702
703
704void
705update_room_last_message (struct GNUNET_MESSENGER_Room *room,
706 const struct GNUNET_HashCode *hash)
707{
708 GNUNET_assert ((room) && (hash));
709
710 GNUNET_memcpy (&(room->last_message), hash, sizeof(room->last_message));
711}
712
713
714struct GNUNET_MESSENGER_MemberCall
715{
716 struct GNUNET_MESSENGER_Room *room;
717 GNUNET_MESSENGER_MemberCallback callback;
718 void *cls;
719};
720
721static enum GNUNET_GenericReturnValue
722iterate_local_members (void *cls,
723 const struct GNUNET_ShortHashCode *key,
724 void *value)
725{
726 struct GNUNET_MESSENGER_MemberCall *call = cls;
727 struct GNUNET_MESSENGER_Contact *contact = value;
728
729 return call->callback (call->cls, call->room, contact);
730}
731
732
733int
734iterate_room_members (struct GNUNET_MESSENGER_Room *room,
735 GNUNET_MESSENGER_MemberCallback callback,
736 void *cls)
737{
738 GNUNET_assert (room);
739
740 if (! callback)
741 return GNUNET_CONTAINER_multishortmap_iterate (room->members, NULL, NULL);
742
743 struct GNUNET_MESSENGER_MemberCall call;
744
745 call.room = room;
746 call.callback = callback;
747 call.cls = cls;
748
749 GNUNET_assert (callback);
750
751 return GNUNET_CONTAINER_multishortmap_iterate (room->members,
752 iterate_local_members,
753 &call);
754}
755
756
757struct GNUNET_MESSENGER_MemberFind
758{
759 const struct GNUNET_MESSENGER_Contact *contact;
760 enum GNUNET_GenericReturnValue result;
761};
762
763static enum GNUNET_GenericReturnValue
764iterate_find_member (void *cls,
765 const struct GNUNET_ShortHashCode *key,
766 void *value)
767{
768 struct GNUNET_MESSENGER_MemberFind *find = cls;
769 struct GNUNET_MESSENGER_Contact *contact = value;
770
771 if (contact == find->contact)
772 {
773 find->result = GNUNET_YES;
774 return GNUNET_NO;
775 }
776
777 return GNUNET_YES;
778}
779
780
781enum GNUNET_GenericReturnValue
782find_room_member (const struct GNUNET_MESSENGER_Room *room,
783 const struct GNUNET_MESSENGER_Contact *contact)
784{
785 GNUNET_assert (room);
786
787 struct GNUNET_MESSENGER_MemberFind find;
788
789 find.contact = contact;
790 find.result = GNUNET_NO;
791
792 GNUNET_CONTAINER_multishortmap_iterate (room->members, iterate_find_member,
793 &find);
794
795 return find.result;
796}
797
798
799static enum GNUNET_GenericReturnValue
800find_linked_hash (void *cls,
801 const struct GNUNET_HashCode *key,
802 void *value)
803{
804 const struct GNUNET_HashCode **result = cls;
805 struct GNUNET_HashCode *hash = value;
806
807 if (0 == GNUNET_CRYPTO_hash_cmp (hash, *result))
808 {
809 *result = NULL;
810 return GNUNET_NO;
811 }
812
813 return GNUNET_YES;
814}
815
816
817void
818link_room_message (struct GNUNET_MESSENGER_Room *room,
819 const struct GNUNET_HashCode *hash,
820 const struct GNUNET_HashCode *other)
821{
822 GNUNET_assert ((room) && (hash) && (other));
823
824 const struct GNUNET_HashCode **result = &other;
825 GNUNET_CONTAINER_multihashmap_get_multiple (room->links, hash,
826 find_linked_hash, result);
827
828 if (! *result)
829 return;
830
831 struct GNUNET_HashCode *value = GNUNET_memdup (other, sizeof(struct
832 GNUNET_HashCode))
833 ;
834 if (! value)
835 return;
836
837 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (room->links, hash, value,
838 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE))
839
840 GNUNET_free (value);
841}
842
843
844struct GNUNET_MESSENGER_RoomLinkDeletionInfo
845{
846 struct GNUNET_MESSENGER_Room *room;
847 struct GNUNET_TIME_Relative delay;
848 GNUNET_MESSENGER_RoomLinkDeletion deletion;
849};
850
851
852static enum GNUNET_GenericReturnValue
853clear_linked_hash (void *cls,
854 const struct GNUNET_HashCode *key,
855 void *value)
856{
857 struct GNUNET_HashCode **linked = cls;
858 struct GNUNET_HashCode *hash = value;
859
860 if (0 != GNUNET_CRYPTO_hash_cmp (*linked, hash))
861 return GNUNET_YES;
862
863 *linked = hash;
864 return GNUNET_NO;
865}
866
867
868static enum GNUNET_GenericReturnValue
869delete_linked_hash (void *cls,
870 const struct GNUNET_HashCode *key,
871 void *value)
872{
873 struct GNUNET_MESSENGER_RoomLinkDeletionInfo *info = cls;
874 struct GNUNET_HashCode *hash = value;
875
876 struct GNUNET_HashCode key_value;
877 GNUNET_memcpy (&key_value, key, sizeof (key_value));
878
879 struct GNUNET_HashCode *linked = &key_value;
880
881 GNUNET_CONTAINER_multihashmap_get_multiple (info->room->links, hash,
882 clear_linked_hash, &linked);
883
884 if ((linked != &key_value) &&
885 (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (info->room->links,
886 hash, linked)))
887 GNUNET_free (linked);
888
889 if (info->deletion)
890 info->deletion (info->room, hash, info->delay);
891
892 GNUNET_free (hash);
893 return GNUNET_YES;
894}
895
896
897void
898link_room_deletion (struct GNUNET_MESSENGER_Room *room,
899 const struct GNUNET_HashCode *hash,
900 const struct GNUNET_TIME_Relative delay,
901 GNUNET_MESSENGER_RoomLinkDeletion deletion)
902{
903 GNUNET_assert ((room) && (hash));
904
905 struct GNUNET_MESSENGER_RoomLinkDeletionInfo info;
906 info.room = room;
907 info.delay = delay;
908 info.deletion = deletion;
909
910 GNUNET_CONTAINER_multihashmap_get_multiple (room->links, hash,
911 delete_linked_hash, &info);
912 GNUNET_CONTAINER_multihashmap_remove_all (room->links, hash);
913}
diff --git a/src/service/messenger/messenger_api_room.h b/src/service/messenger/messenger_api_room.h
new file mode 100644
index 000000000..f8460f4e1
--- /dev/null
+++ b/src/service/messenger/messenger_api_room.h
@@ -0,0 +1,270 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/messenger_api_room.h
23 * @brief messenger api: client implementation of GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_MESSENGER_API_ROOM_H
27#define GNUNET_MESSENGER_API_ROOM_H
28
29#include "gnunet_common.h"
30#include "gnunet_time_lib.h"
31#include "gnunet_util_lib.h"
32
33#include "gnunet_messenger_service.h"
34
35#include "messenger_api_handle.h"
36#include "messenger_api_list_tunnels.h"
37#include "messenger_api_contact.h"
38#include "messenger_api_message_control.h"
39#include "messenger_api_queue_messages.h"
40
41struct GNUNET_MESSENGER_RoomMessageEntry
42{
43 struct GNUNET_MESSENGER_Contact *sender;
44 struct GNUNET_MESSENGER_Contact *recipient;
45
46 struct GNUNET_MESSENGER_Message *message;
47 enum GNUNET_MESSENGER_MessageFlags flags;
48 enum GNUNET_GenericReturnValue completed;
49};
50
51struct GNUNET_MESSENGER_Room
52{
53 struct GNUNET_MESSENGER_Handle *handle;
54 struct GNUNET_HashCode key;
55
56 struct GNUNET_HashCode last_message;
57
58 enum GNUNET_GenericReturnValue opened;
59 enum GNUNET_GenericReturnValue use_handle_name;
60 enum GNUNET_GenericReturnValue wait_for_sync;
61
62 struct GNUNET_ShortHashCode *sender_id;
63
64 struct GNUNET_MESSENGER_ListTunnels entries;
65
66 struct GNUNET_CONTAINER_MultiHashMap *messages;
67 struct GNUNET_CONTAINER_MultiShortmap *members;
68 struct GNUNET_CONTAINER_MultiHashMap *links;
69
70 struct GNUNET_MESSENGER_QueueMessages queue;
71
72 struct GNUNET_MESSENGER_MessageControl *control;
73};
74
75typedef void (*GNUNET_MESSENGER_RoomLinkDeletion) (struct
76 GNUNET_MESSENGER_Room *room,
77 const struct
78 GNUNET_HashCode *hash,
79 const struct
80 GNUNET_TIME_Relative delay);
81
82/**
83 * Creates and allocates a new room for a <i>handle</i> with a given <i>key</i> for the client API.
84 *
85 * @param[in,out] handle Handle
86 * @param[in] key Key of room
87 * @return New room
88 */
89struct GNUNET_MESSENGER_Room*
90create_room (struct GNUNET_MESSENGER_Handle *handle,
91 const struct GNUNET_HashCode *key);
92
93/**
94 * Destroys a room and frees its memory fully from the client API.
95 *
96 * @param[in,out] room Room
97 */
98void
99destroy_room (struct GNUNET_MESSENGER_Room *room);
100
101/**
102 * Checks whether a room is available to send messages.
103 *
104 * @param[in] room Room
105 * @return GNUNET_YES if the room is available, otherwise GNUNET_NO
106 */
107enum GNUNET_GenericReturnValue
108is_room_available (const struct GNUNET_MESSENGER_Room *room);
109
110/**
111 * Returns the messenger handle of the <i>room</i>.
112 *
113 * @param[in,out] room Room
114 * @return Messenger handle or NULL
115 */
116struct GNUNET_MESSENGER_Handle*
117get_room_handle (struct GNUNET_MESSENGER_Room *room);
118
119/**
120 * Returns the member id of the <i>room</i>'s sender.
121 *
122 * @param[in] room Room
123 * @return Member id or NULL
124 */
125const struct GNUNET_ShortHashCode*
126get_room_sender_id (const struct GNUNET_MESSENGER_Room *room);
127
128/**
129 * Sets the member id of the <i>room</i>'s sender to a specific <i>id</i> or NULL.
130 *
131 * @param[in,out] room Room
132 * @param[in] id Member id or NULL
133 */
134void
135set_room_sender_id (struct GNUNET_MESSENGER_Room *room,
136 const struct GNUNET_ShortHashCode *id);
137
138/**
139 * Returns a message locally stored from a map for a given <i>hash</i> in a <i>room</i>. If no matching
140 * message is found, NULL gets returned.
141 *
142 * @param[in] room Room
143 * @param[in] hash Hash of message
144 * @return Message or NULL
145 */
146const struct GNUNET_MESSENGER_Message*
147get_room_message (const struct GNUNET_MESSENGER_Room *room,
148 const struct GNUNET_HashCode *hash);
149
150/**
151 * Returns a messages sender locally stored from a map for a given <i>hash</i> in a <i>room</i>. If no
152 * matching message is found, NULL gets returned.
153 *
154 * @param[in] room Room
155 * @param[in] hash Hash of message
156 * @return Contact of sender or NULL
157 */
158struct GNUNET_MESSENGER_Contact*
159get_room_sender (const struct GNUNET_MESSENGER_Room *room,
160 const struct GNUNET_HashCode *hash);
161
162/**
163 * Returns a messages recipient locally stored from a map for a given <i>hash</i> in a <i>room</i>. If no
164 * matching message is found or the message has not been privately received, NULL gets returned.
165 *
166 * @param[in] room Room
167 * @param[in] hash Hash of message
168 * @return Contact of recipient or NULL
169 */
170struct GNUNET_MESSENGER_Contact*
171get_room_recipient (const struct GNUNET_MESSENGER_Room *room,
172 const struct GNUNET_HashCode *hash);
173
174/**
175 * Executes the message callback for a given <i>hash</i> in a <i>room</i>.
176 *
177 * @param[in,out] room Room
178 * @param[in] hash Hash of message
179 */
180void
181callback_room_message (struct GNUNET_MESSENGER_Room *room,
182 const struct GNUNET_HashCode *hash);
183
184/**
185 * Handles a <i>message</i> with a given <i>hash</i> in a <i>room</i> for the client API to update
186 * members and its information. The function also stores the message in map locally for access afterwards.
187 *
188 * The contact of the message's sender could be updated or even created. It may not be freed or destroyed though!
189 * (The contact may still be in use for old messages...)
190 *
191 * @param[in,out] room Room
192 * @param[in,out] sender Contact of sender
193 * @param[in] message Message
194 * @param[in] hash Hash of message
195 * @param[in] flags Flags of message
196 */
197void
198handle_room_message (struct GNUNET_MESSENGER_Room *room,
199 struct GNUNET_MESSENGER_Contact *sender,
200 const struct GNUNET_MESSENGER_Message *message,
201 const struct GNUNET_HashCode *hash,
202 enum GNUNET_MESSENGER_MessageFlags flags);
203
204/**
205 * Updates the last message <i>hash</i> of a <i>room</i> for the client API so that new messages can
206 * point to the latest message hash while sending.
207 *
208 * @param[in,out] room Room
209 * @param[in] hash Hash of message
210 */
211void
212update_room_last_message (struct GNUNET_MESSENGER_Room *room,
213 const struct GNUNET_HashCode *hash);
214
215/**
216 * Iterates through all members of a given <i>room</i> to forward each of them to a selected
217 * <i>callback</i> with a custom closure.
218 *
219 * @param[in,out] room Room
220 * @param[in] callback Function called for each member
221 * @param[in,out] cls Closure
222 * @return Amount of members iterated
223 */
224int
225iterate_room_members (struct GNUNET_MESSENGER_Room *room,
226 GNUNET_MESSENGER_MemberCallback callback,
227 void *cls);
228
229/**
230 * Checks through all members of a given <i>room</i> if a specific <i>contact</i> is found and
231 * returns a result depending on that.
232 *
233 * @param[in] room Room
234 * @param[in] contact
235 * @return #GNUNET_YES if found, otherwise #GNUNET_NO
236 */
237enum GNUNET_GenericReturnValue
238find_room_member (const struct GNUNET_MESSENGER_Room *room,
239 const struct GNUNET_MESSENGER_Contact *contact);
240
241/**
242 * Links a message identified by its <i>hash</i> inside a given <i>room</i> with another
243 * message identified by its <i>other</i> hash. Linked messages will be deleted automatically,
244 * if any linked message to it gets deleted.
245 *
246 * @param[in,out] room Room
247 * @param[in] hash Hash of message
248 * @param[in] other Hash of other message
249 */
250void
251link_room_message (struct GNUNET_MESSENGER_Room *room,
252 const struct GNUNET_HashCode *hash,
253 const struct GNUNET_HashCode *other);
254
255/**
256 * Delete all remaining links to a certain message identified by its <i>hash</i> inside a given
257 * <i>room</i> and cause a <i>deletion</i> process to all of the linked messages.
258 *
259 * @param[in,out] room Room
260 * @param[in] hash Hash of message
261 * @param[in] delay Delay for linked deletion
262 * @param[in] deletion Function called for each linked deletion
263 */
264void
265link_room_deletion (struct GNUNET_MESSENGER_Room *room,
266 const struct GNUNET_HashCode *hash,
267 const struct GNUNET_TIME_Relative delay,
268 GNUNET_MESSENGER_RoomLinkDeletion deletion);
269
270#endif //GNUNET_MESSENGER_API_ROOM_H
diff --git a/src/service/messenger/messenger_api_traits.c b/src/service/messenger/messenger_api_traits.c
new file mode 100644
index 000000000..b6affc90d
--- /dev/null
+++ b/src/service/messenger/messenger_api_traits.c
@@ -0,0 +1,29 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2023--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file messenger_api_traits.c
23 * @brief testing lib for messenger service
24 * @author Tobias Frisch
25 */
26
27#include "messenger-testing-cmds.h"
28
29GNUNET_MESSENGER_SIMPLE_TRAITS (GNUNET_MESSENGER_MAKE_IMPL_SIMPLE_TRAIT)
diff --git a/src/service/messenger/messenger_api_util.c b/src/service/messenger/messenger_api_util.c
new file mode 100644
index 000000000..1d38f87a1
--- /dev/null
+++ b/src/service/messenger/messenger_api_util.c
@@ -0,0 +1,129 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/messenger_api_util.c
23 * @brief messenger api: client implementation of GNUnet MESSENGER service
24 */
25
26#include "messenger_api_util.h"
27
28#include "gnunet_identity_service.h"
29#include "gnunet_messenger_service.h"
30
31static void
32callback_close_channel (void *cls)
33{
34 struct GNUNET_CADET_Channel *channel = cls;
35
36 if (channel)
37 GNUNET_CADET_channel_destroy (channel);
38}
39
40
41void
42delayed_disconnect_channel (struct GNUNET_CADET_Channel *channel)
43{
44 GNUNET_assert (channel);
45
46 GNUNET_SCHEDULER_add_delayed_with_priority (GNUNET_TIME_relative_get_zero_ (),
47 GNUNET_SCHEDULER_PRIORITY_URGENT,
48 callback_close_channel, channel);
49}
50
51
52enum GNUNET_GenericReturnValue
53generate_free_member_id (struct GNUNET_ShortHashCode *id,
54 const struct GNUNET_CONTAINER_MultiShortmap *members)
55{
56 GNUNET_assert (id);
57
58 size_t counter = 1 + (members ? GNUNET_CONTAINER_multishortmap_size (
59 members) : 0);
60
61 do
62 {
63 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG, id, sizeof(struct
64 GNUNET_ShortHashCode));
65
66 if ((members) && (GNUNET_YES == GNUNET_CONTAINER_multishortmap_contains (
67 members, id)))
68 counter--;
69 else
70 break;
71 }
72 while (counter > 0);
73
74 if (counter)
75 return GNUNET_YES;
76
77 return GNUNET_NO;
78}
79
80
81const struct GNUNET_CRYPTO_PrivateKey*
82get_anonymous_private_key ()
83{
84 const struct GNUNET_IDENTITY_Ego *ego = GNUNET_IDENTITY_ego_get_anonymous ();
85 return GNUNET_IDENTITY_ego_get_private_key (ego);
86}
87
88
89const struct GNUNET_CRYPTO_PublicKey*
90get_anonymous_public_key ()
91{
92 static struct GNUNET_CRYPTO_PublicKey public_key;
93 static struct GNUNET_IDENTITY_Ego *ego = NULL;
94
95 if (! ego)
96 {
97 ego = GNUNET_IDENTITY_ego_get_anonymous ();
98 GNUNET_IDENTITY_ego_get_public_key (ego, &public_key);
99 }
100
101 return &public_key;
102}
103
104
105void
106convert_messenger_key_to_port (const struct GNUNET_HashCode *key,
107 struct GNUNET_HashCode *port)
108{
109 static uint32_t version_value = 0;
110 static struct GNUNET_HashCode version;
111
112 if (! version_value)
113 {
114 version_value = (uint32_t) (GNUNET_MESSENGER_VERSION);
115 version_value = ((version_value >> 16) & 0xFFFF);
116 version_value = GNUNET_htole32 (version_value);
117 GNUNET_CRYPTO_hash (&version_value, sizeof(version_value), &version);
118 }
119
120 GNUNET_CRYPTO_hash_sum (key, &version, port);
121}
122
123
124void
125convert_peer_identity_to_id (const struct GNUNET_PeerIdentity *identity,
126 struct GNUNET_ShortHashCode *id)
127{
128 GNUNET_memcpy (id, identity, sizeof(struct GNUNET_ShortHashCode));
129}
diff --git a/src/service/messenger/messenger_api_util.h b/src/service/messenger/messenger_api_util.h
new file mode 100644
index 000000000..877491c93
--- /dev/null
+++ b/src/service/messenger/messenger_api_util.h
@@ -0,0 +1,95 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/messenger_api_util.h
23 * @brief messenger api: client implementation of GNUnet MESSENGER service
24 */
25
26#ifndef GNUNET_SERVICE_MESSENGER_UTIL_H
27#define GNUNET_SERVICE_MESSENGER_UTIL_H
28
29#include "gnunet_cadet_service.h"
30#include "gnunet_util_lib.h"
31
32/**
33 * Starts an urgent task to close a CADET channel asynchronously.
34 *
35 * @param[in,out] channel Channel
36 */
37void
38delayed_disconnect_channel (struct GNUNET_CADET_Channel *channel);
39
40/**
41 * Tries to generate an unused member id and store it into the <i>id</i> parameter.
42 * A map containing all currently used member ids is used to check against.
43 *
44 * @param[out] id New member id
45 * @param[in] members Map of member ids
46 * @return #GNUNET_YES on success, #GNUNET_NO on failure
47 */
48enum GNUNET_GenericReturnValue
49generate_free_member_id (struct GNUNET_ShortHashCode *id,
50 const struct GNUNET_CONTAINER_MultiShortmap *members);
51
52/**
53 * Returns the private identity key of #GNUNET_IDENTITY_ego_get_anonymous() without
54 * recalculating it every time.
55 *
56 * @return anonymous private key
57 */
58const struct GNUNET_CRYPTO_PrivateKey*
59get_anonymous_private_key ();
60
61/**
62 * Returns the public identity key of #GNUNET_IDENTITY_ego_get_anonymous() without
63 * recalculating it every time.
64 *
65 * @return anonymous public key
66 */
67const struct GNUNET_CRYPTO_PublicKey*
68get_anonymous_public_key ();
69
70/**
71 * Converts a Messenger service key of a room to the specific port which
72 * gets used for the CADET channels.
73 *
74 * The port includes upper bits of the #GNUNET_MESSENGER_VERSION to
75 * reduce the chance of incompatible connections.
76 *
77 * @param[in] key Messenger service room key
78 * @param[out] port CADET service port
79 */
80void
81convert_messenger_key_to_port (const struct GNUNET_HashCode *key,
82 struct GNUNET_HashCode *port);
83
84/**
85 * Converts a peers identity to a short hash code which can be used
86 * as id to refer to a peer via sender id as attached in messages.
87 *
88 * @param[in] identity Peer identity
89 * @param[out] id Short peer id
90 */
91void
92convert_peer_identity_to_id (const struct GNUNET_PeerIdentity *identity,
93 struct GNUNET_ShortHashCode *id);
94
95#endif //GNUNET_SERVICE_MESSENGER_UTIL_H
diff --git a/src/service/messenger/test_messenger.c b/src/service/messenger/test_messenger.c
new file mode 100644
index 000000000..4f7a51e34
--- /dev/null
+++ b/src/service/messenger/test_messenger.c
@@ -0,0 +1,218 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2023 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file messenger/test_messenger.c
22 * @author Tobias Frisch
23 * @brief Test for the messenger service using cadet API.
24 */
25
26#include <stdio.h>
27#include "gnunet_util_lib.h"
28#include "gnunet_testing_lib.h"
29#include "gnunet_messenger_service.h"
30
31/**
32 * How long until we really give up on a particular testcase portion?
33 */
34#define TOTAL_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, \
35 60)
36
37/**
38 * How long until we give up on any particular operation (and retry)?
39 */
40#define BASE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
41
42#define TESTER_NAME "tester"
43
44static int status = 1;
45
46static struct GNUNET_SCHEDULER_Task *die_task = NULL;
47static struct GNUNET_SCHEDULER_Task *op_task = NULL;
48static struct GNUNET_SCHEDULER_Task *it_task = NULL;
49
50struct GNUNET_MESSENGER_Handle *messenger = NULL;
51
52static struct GNUNET_CRYPTO_PrivateKey identity;
53
54static void
55end (void *cls)
56{
57 die_task = NULL;
58
59 if (it_task)
60 {
61 GNUNET_SCHEDULER_cancel (it_task);
62 it_task = NULL;
63 }
64
65 if (op_task)
66 {
67 GNUNET_SCHEDULER_cancel (op_task);
68 op_task = NULL;
69 }
70
71 if (messenger)
72 {
73 GNUNET_MESSENGER_disconnect (messenger);
74 messenger = NULL;
75 }
76
77 GNUNET_CRYPTO_private_key_clear (&identity);
78 status = 0;
79}
80
81
82static void
83end_badly (void *cls)
84{
85 fprintf (stderr, "Testcase failed (timeout).\n");
86
87 end (NULL);
88 status = 1;
89}
90
91
92static void
93end_operation (void *cls)
94{
95 op_task = NULL;
96
97 fprintf (stderr, "Testcase failed (operation: '%s').\n", cls ? (const
98 char*) cls :
99 "unknown");
100
101 if (die_task)
102 GNUNET_SCHEDULER_cancel (die_task);
103
104 end (NULL);
105 status = 1;
106}
107
108
109static int identity_counter = 0;
110
111/**
112 * Function called when an identity is retrieved.
113 *
114 * @param cls Closure
115 * @param handle Handle of messenger service
116 */
117static void
118on_iteration (void *cls)
119{
120 struct GNUNET_MESSENGER_Handle *handle = cls;
121 it_task = NULL;
122
123 if (op_task)
124 {
125 GNUNET_SCHEDULER_cancel (op_task);
126 op_task = NULL;
127 }
128
129 const char *name = GNUNET_MESSENGER_get_name (handle);
130
131 if ((! name) || (0 != strcmp (name, TESTER_NAME)))
132 {
133 op_task = GNUNET_SCHEDULER_add_now (&end_operation, "name");
134 return;
135 }
136
137 const struct GNUNET_CRYPTO_PublicKey *key = GNUNET_MESSENGER_get_key (
138 handle);
139
140 struct GNUNET_CRYPTO_PublicKey pubkey;
141 GNUNET_CRYPTO_key_get_public (&identity, &pubkey);
142
143 if (((! identity_counter) && (key)) || ((identity_counter) && ((! key) ||
144 (0 !=
145 GNUNET_memcmp (
146 key,
147 &pubkey)))))
148 {
149 op_task = GNUNET_SCHEDULER_add_now (&end_operation, "key");
150 return;
151 }
152
153 if (identity_counter)
154 {
155 GNUNET_MESSENGER_disconnect (handle);
156
157 op_task = NULL;
158 messenger = NULL;
159
160 if (die_task)
161 GNUNET_SCHEDULER_cancel (die_task);
162
163 die_task = GNUNET_SCHEDULER_add_now (&end, NULL);
164 return;
165 }
166
167 GNUNET_MESSENGER_set_key (handle, &identity);
168 identity_counter++;
169
170 it_task = GNUNET_SCHEDULER_add_now (&on_iteration, handle);
171}
172
173
174/**
175 * Main function for testcase.
176 *
177 * @param cls Closure
178 * @param cfg Configuration
179 * @param peer Peer for testing
180 */
181static void
182run (void *cls,
183 const struct GNUNET_CONFIGURATION_Handle *cfg,
184 struct GNUNET_TESTING_Peer *peer)
185{
186 die_task = GNUNET_SCHEDULER_add_delayed (TOTAL_TIMEOUT, &end_badly, NULL);
187
188 identity_counter = 0;
189
190 op_task = GNUNET_SCHEDULER_add_delayed (BASE_TIMEOUT, &end_operation,
191 "connect");
192 messenger = GNUNET_MESSENGER_connect (cfg, TESTER_NAME, NULL, NULL, NULL);
193
194 identity.type = htonl (GNUNET_PUBLIC_KEY_TYPE_ECDSA);
195 GNUNET_CRYPTO_ecdsa_key_create (&(identity.ecdsa_key));
196
197 if (messenger)
198 it_task = GNUNET_SCHEDULER_add_now (&on_iteration, messenger);
199}
200
201
202/**
203 * The main function.
204 *
205 * @param argc number of arguments from the command line
206 * @param argv command line arguments
207 * @return 0 ok, 1 on error
208 */
209int
210main (int argc,
211 char **argv)
212{
213 if (0 != GNUNET_TESTING_peer_run ("test-messenger", "test_messenger_api.conf",
214 &run, NULL))
215 return 1;
216
217 return status;
218}
diff --git a/src/service/messenger/test_messenger_anonymous.c b/src/service/messenger/test_messenger_anonymous.c
new file mode 100644
index 000000000..5f77cca53
--- /dev/null
+++ b/src/service/messenger/test_messenger_anonymous.c
@@ -0,0 +1,190 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2023 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file messenger/test_messenger_anonymous.c
22 * @author Tobias Frisch
23 * @brief Test for the messenger service using cadet API.
24 */
25
26#include <stdio.h>
27#include "gnunet_util_lib.h"
28#include "gnunet_testing_lib.h"
29#include "gnunet_messenger_service.h"
30
31/**
32 * How long until we really give up on a particular testcase portion?
33 */
34#define TOTAL_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, \
35 60)
36
37/**
38 * How long until we give up on any particular operation (and retry)?
39 */
40#define BASE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
41
42static int status = 1;
43
44static struct GNUNET_SCHEDULER_Task *die_task = NULL;
45static struct GNUNET_SCHEDULER_Task *op_task = NULL;
46static struct GNUNET_SCHEDULER_Task *it_task = NULL;
47
48struct GNUNET_MESSENGER_Handle *messenger = NULL;
49
50static void
51end (void *cls)
52{
53 die_task = NULL;
54
55 if (it_task)
56 {
57 GNUNET_SCHEDULER_cancel (it_task);
58 it_task = NULL;
59 }
60
61 if (op_task)
62 {
63 GNUNET_SCHEDULER_cancel (op_task);
64 op_task = NULL;
65 }
66
67 if (messenger)
68 {
69 GNUNET_MESSENGER_disconnect (messenger);
70 messenger = NULL;
71 }
72
73 status = 0;
74}
75
76
77static void
78end_badly (void *cls)
79{
80 fprintf (stderr, "Testcase failed (timeout).\n");
81
82 end (NULL);
83 status = 1;
84}
85
86
87static void
88end_operation (void *cls)
89{
90 op_task = NULL;
91
92 fprintf (stderr, "Testcase failed (operation: '%s').\n", cls ? (const
93 char*) cls :
94 "unknown");
95
96 if (die_task)
97 GNUNET_SCHEDULER_cancel (die_task);
98
99 end (NULL);
100 status = 1;
101}
102
103
104/**
105 * Function called when an identity is retrieved.
106 *
107 * @param cls Closure
108 * @param handle Handle of messenger service
109 */
110static void
111on_iteration (void *cls)
112{
113 struct GNUNET_MESSENGER_Handle *handle = cls;
114
115 it_task = NULL;
116
117 if (op_task)
118 {
119 GNUNET_SCHEDULER_cancel (op_task);
120 op_task = NULL;
121 }
122
123 const char *name = GNUNET_MESSENGER_get_name (handle);
124
125 if (NULL != name)
126 {
127 op_task = GNUNET_SCHEDULER_add_now (&end_operation, "name-anonymous");
128 return;
129 }
130
131 const struct GNUNET_CRYPTO_PublicKey *key = GNUNET_MESSENGER_get_key (
132 handle);
133
134 if (key)
135 {
136 op_task = GNUNET_SCHEDULER_add_now (&end_operation, "key-anonymous");
137 return;
138 }
139
140 GNUNET_MESSENGER_disconnect (handle);
141
142 messenger = NULL;
143
144 if (die_task)
145 GNUNET_SCHEDULER_cancel (die_task);
146
147 die_task = GNUNET_SCHEDULER_add_now (&end, NULL);
148}
149
150
151/**
152 * Main function for testcase.
153 *
154 * @param cls Closure
155 * @param cfg Configuration
156 * @param peer Peer for testing
157 */
158static void
159run (void *cls,
160 const struct GNUNET_CONFIGURATION_Handle *cfg,
161 struct GNUNET_TESTING_Peer *peer)
162{
163 die_task = GNUNET_SCHEDULER_add_delayed (TOTAL_TIMEOUT, &end_badly, NULL);
164
165 op_task = GNUNET_SCHEDULER_add_delayed (BASE_TIMEOUT, &end_operation,
166 "connect");
167 messenger = GNUNET_MESSENGER_connect (cfg, NULL, NULL, NULL, NULL);
168
169 if (messenger)
170 it_task = GNUNET_SCHEDULER_add_now (&on_iteration, messenger);
171}
172
173
174/**
175 * The main function.
176 *
177 * @param argc number of arguments from the command line
178 * @param argv command line arguments
179 * @return 0 ok, 1 on error
180 */
181int
182main (int argc,
183 char **argv)
184{
185 if (0 != GNUNET_TESTING_peer_run ("test-messenger", "test_messenger_api.conf",
186 &run, NULL))
187 return 1;
188
189 return status;
190}
diff --git a/src/service/messenger/test_messenger_api.conf b/src/service/messenger/test_messenger_api.conf
new file mode 100644
index 000000000..c6c7ea2d3
--- /dev/null
+++ b/src/service/messenger/test_messenger_api.conf
@@ -0,0 +1,49 @@
1@INLINE@ ../../../contrib/conf/gnunet/no_forcestart.conf
2@INLINE@ ../../../contrib/conf/gnunet/no_autostart_above_core.conf
3
4[testbed]
5HOSTNAME = localhost
6OVERLAY_TOPOLOGY = CLIQUE
7
8[arm]
9GLOBAL_POSTFIX = -l $GNUNET_CACHE_HOME/{}-logs -L verbose
10
11[transport]
12IMMEDIATE_START = YES
13
14[core]
15START_ON_DEMAND = YES
16IMMEDIATE_START = YES
17USE_EPHEMERAL_KEYS = NO
18
19[PATHS]
20GNUNET_TEST_HOME = $GNUNET_TMP/test-messenger-api/
21
22[peerinfo]
23NO_IO = YES
24
25[cadet]
26START_ON_DEMAND = YES
27REFRESH_CONNECTION_TIME = 1 s
28ID_ANNOUNCE_TIME = 5 s
29CONNECT_TIMEOUT = 30 s
30DEFAULT_TTL = 16
31DHT_REPLICATION_LEVEL = 10
32MAX_TUNNELS = 10
33MAX_CONNECTIONS = 10
34MAX_MSGS_QUEUE = 20
35DISABLE_TRY_CONNECT = YES
36REKEY_PERIOD = 2 s
37
38[identity]
39START_ON_DEMAND = YES
40
41[messenger]
42START_ON_DEMAND = YES
43MESSENGER_AUTO_CONNECTING = NO
44MESSENGER_AUTO_ROUTING = NO
45
46[nat]
47ENABLE_UPNP = NO
48RETURN_LOCAL_ADDRESSES = YES
49IMMEDIATE_START = NO \ No newline at end of file
diff --git a/src/service/messenger/test_messenger_plugin_cmd_simple_join.c b/src/service/messenger/test_messenger_plugin_cmd_simple_join.c
new file mode 100644
index 000000000..4f50e4c06
--- /dev/null
+++ b/src/service/messenger/test_messenger_plugin_cmd_simple_join.c
@@ -0,0 +1,400 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2023 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file test_messenger_plugin_cmd_simple_join.c
23 * @brief a plugin to provide the API for running test cases.
24 * @author Tobias Frisch
25 */
26
27#include "platform.h"
28#include "gnunet_testing_barrier.h"
29#include "gnunet_testing_netjail_lib.h"
30#include "gnunet_util_lib.h"
31#include "gnunet_transport_application_service.h"
32#include "gnunet_transport_core_service.h"
33#include "gnunet_testing_barrier.h"
34#include "gnunet_core_service.h"
35#include "gnunet_core_testing_lib.h"
36#include "gnunet_transport_testing_ng_lib.h"
37#include "messenger-testing-cmds.h"
38
39/**
40 * Generic logging shortcut
41 */
42#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__)
43
44#define BASE_DIR "testdir"
45
46#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 600)
47
48#define MAX_RECEIVED 1000
49
50#define MESSAGE_SIZE 65000
51
52static struct GNUNET_TESTING_Command block_script;
53
54static struct GNUNET_TESTING_Command connect_peers;
55
56static struct GNUNET_TESTING_Command local_prepared;
57
58static struct GNUNET_TESTING_Command start_peer;
59
60static struct GNUNET_TESTING_Command start_service;
61
62static struct GNUNET_TESTING_Interpreter *is;
63
64struct TestState
65{
66 /**
67 * Callback to write messages to the master loop.
68 *
69 */
70 GNUNET_TESTING_cmd_helper_write_cb write_message;
71
72 /**
73 * Callback to notify the helper test case has finished.
74 */
75 GNUNET_TESTING_cmd_helper_finish_cb finished_cb;
76
77 /**
78 * The name for a specific test environment directory.
79 *
80 */
81 char *testdir;
82
83 /**
84 * The name for the configuration file of the specific node.
85 *
86 */
87 char *cfgname;
88
89 /**
90 * The complete topology information.
91 */
92 struct GNUNET_TESTING_NetjailTopology *topology;
93
94 struct GNUNET_MESSENGER_TestStageTopology *chat_topology;
95};
96
97struct Sender
98{
99 /**
100 * Number of received messages from sender.
101 */
102 unsigned long long num_received;
103
104 /**
105 * Sample mean time the message traveled.
106 */
107 struct GNUNET_TIME_Relative mean_time;
108
109 /**
110 * Time the first message was send.
111 */
112 struct GNUNET_TIME_Absolute time_first;
113};
114
115
116struct GNUNET_TESTING_BarrierList*
117get_waiting_for_barriers ()
118{
119 struct GNUNET_TESTING_BarrierList*barriers;
120 struct GNUNET_TESTING_BarrierListEntry *ble;
121
122 barriers = GNUNET_new (struct GNUNET_TESTING_BarrierList);
123 ble = GNUNET_new (struct GNUNET_TESTING_BarrierListEntry);
124 ble->barrier_name = "ready-to-connect";
125 ble->expected_reaches = 1;
126 GNUNET_CONTAINER_DLL_insert (barriers->head,
127 barriers->tail,
128 ble);
129
130 ble = GNUNET_new (struct GNUNET_TESTING_BarrierListEntry);
131 ble->barrier_name = "test-case-finished";
132 ble->expected_reaches = 1;
133 GNUNET_CONTAINER_DLL_insert (barriers->head,
134 barriers->tail,
135 ble);
136 return barriers;
137}
138
139
140/**
141 * Function called with the final result of the test.
142 *
143 * @param cls the `struct MainParams`
144 * @param rv #GNUNET_OK if the test passed
145 */
146static void
147handle_result (void *cls,
148 enum GNUNET_GenericReturnValue rv)
149{
150 struct TestState *ts = cls;
151
152 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
153 "Local test exits with status %d\n",
154 rv);
155
156 ts->finished_cb (rv);
157 GNUNET_free (ts->testdir);
158 GNUNET_free (ts->cfgname);
159 GNUNET_MESSENGER_destroy_topo (ts->chat_topology);
160 GNUNET_TESTING_free_topology (ts->topology);
161 GNUNET_free (ts);
162}
163
164
165static void
166child_completed_callback (void *cls,
167 enum GNUNET_OS_ProcessStatusType type,
168 long unsigned int exit_code)
169{
170
171}
172
173
174/**
175 * Function to start a local test case.
176 *
177 * @param write_message Callback to send a message to the master loop.
178 * @param router_ip Global address of the network namespace.
179 * @param node_ip The IP address of the node.
180 * @param m The number of the node in a network namespace.
181 * @param n The number of the network namespace.
182 * @param local_m The number of nodes in a network namespace.
183 * @param topology_data A file name for the file containing the topology configuration, or a string containing
184 * the topology configuration.
185 * @param read_file If read_file is GNUNET_YES this string is the filename for the topology configuration,
186 * if read_file is GNUNET_NO the string contains the topology configuration.
187 * @param finish_cb Callback function which writes a message from the helper process running on a netjail
188 * node to the master process * signaling that the test case running on the netjail node finished.
189 * @return Returns the struct GNUNET_TESTING_Interpreter of the command loop running on this netjail node.
190 */
191static struct GNUNET_TESTING_Interpreter *
192start_testcase (GNUNET_TESTING_cmd_helper_write_cb write_message,
193 const char *router_ip,
194 const char *node_ip,
195 const char *m,
196 const char *n,
197 const char *local_m,
198 const char *topology_data,
199 unsigned int *read_file,
200 GNUNET_TESTING_cmd_helper_finish_cb finished_cb)
201{
202
203 unsigned int n_int;
204 unsigned int m_int;
205 unsigned int local_m_int;
206 unsigned int num;
207 struct TestState *ts = GNUNET_new (struct TestState);
208 struct GNUNET_TESTING_NetjailTopology *topology;
209 struct GNUNET_MESSENGER_TestStageTopology *chat_topology;
210 unsigned int sscanf_ret = 0;
211 char **argv = NULL;
212 int argc = 0;
213
214 ts->finished_cb = finished_cb;
215 LOG (GNUNET_ERROR_TYPE_ERROR,
216 "n %s m %s\n",
217 n,
218 m);
219
220 if (GNUNET_YES == *read_file)
221 {
222 LOG (GNUNET_ERROR_TYPE_DEBUG,
223 "read from file\n");
224 topology = GNUNET_TESTING_get_topo_from_file (topology_data);
225 }
226 else
227 topology = GNUNET_TESTING_get_topo_from_string (topology_data);
228
229 ts->topology = topology;
230
231 errno = 0;
232 sscanf_ret = sscanf (m, "%u", &m_int);
233 if (errno != 0)
234 {
235 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sscanf");
236 }
237 GNUNET_assert (0 < sscanf_ret);
238 errno = 0;
239 sscanf_ret = sscanf (n, "%u", &n_int);
240 if (errno != 0)
241 {
242 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sscanf");
243 }
244 GNUNET_assert (0 < sscanf_ret);
245 errno = 0;
246 sscanf_ret = sscanf (local_m, "%u", &local_m_int);
247 if (errno != 0)
248 {
249 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sscanf");
250 }
251 GNUNET_assert (0 < sscanf_ret);
252
253 if (0 == n_int)
254 num = m_int;
255 else
256 num = (n_int - 1) * local_m_int + m_int + topology->nodes_x;
257
258 block_script = GNUNET_TESTING_cmd_block_until_external_trigger (
259 "block-script");
260 connect_peers = GNUNET_CORE_cmd_connect_peers ("connect-peers",
261 "start-peer",
262 "system-create",
263 num,
264 topology,
265 0,
266 GNUNET_NO,
267 NULL);
268 local_prepared = GNUNET_TESTING_cmd_local_test_prepared (
269 "local-test-prepared",
270 write_message);
271
272
273 GNUNET_asprintf (&ts->cfgname,
274 "test_messenger_api.conf");
275
276 LOG (GNUNET_ERROR_TYPE_DEBUG,
277 "plugin cfgname: %s\n",
278 ts->cfgname);
279
280 LOG (GNUNET_ERROR_TYPE_DEBUG,
281 "node ip: %s\n",
282 node_ip);
283
284 GNUNET_asprintf (&ts->testdir,
285 "%s%s%s",
286 BASE_DIR,
287 m,
288 n);
289
290 start_peer = GNUNET_TESTING_cmd_start_peer ("start-peer",
291 "system-create",
292 num,
293 node_ip,
294 ts->cfgname,
295 GNUNET_NO);
296
297 const struct GNUNET_MESSENGER_TestStage stages[4] = {
298 GNUNET_MESSENGER_create_stage_open_room (),
299 GNUNET_MESSENGER_create_stage_open_room (),
300 GNUNET_MESSENGER_create_stage_enter_room (2),
301 GNUNET_MESSENGER_create_stage_enter_room (1)
302 };
303
304 chat_topology = GNUNET_MESSENGER_create_topo (2, 2, stages);
305 ts->chat_topology = chat_topology;
306
307 start_service = GNUNET_MESSENGER_cmd_start_service ("start-messenger",
308 "start-peer",
309 "system-create",
310 chat_topology,
311 num);
312
313 struct GNUNET_TESTING_Command commands[] = {
314 GNUNET_TESTING_cmd_system_create ("system-create",
315 ts->testdir),
316 start_peer,
317 GNUNET_TESTING_cmd_barrier_reached ("ready-to-connect-reached",
318 "ready-to-connect",
319 GNUNET_NO,
320 num,
321 GNUNET_NO,
322 write_message),
323 connect_peers,
324 GNUNET_TESTING_cmd_exec_bash_script ("script",
325 "block.sh",
326 argv,
327 argc,
328 &child_completed_callback),
329 block_script,
330 start_service,
331 GNUNET_MESSENGER_cmd_join_room ("join-room-1",
332 "start-messenger",
333 "test-room"),
334 GNUNET_MESSENGER_cmd_join_room ("join-room-2",
335 "start-messenger",
336 "test-room"),
337 GNUNET_MESSENGER_cmd_stop_service ("stop-messenger",
338 "start-messenger"),
339 GNUNET_TESTING_cmd_barrier_reached ("test-case-finished-reached",
340 "test-case-finished",
341 GNUNET_NO,
342 num,
343 GNUNET_NO,
344 write_message),
345 GNUNET_TESTING_cmd_stop_peer ("stop-peer",
346 "start-peer"),
347 GNUNET_TESTING_cmd_system_destroy ("system-destroy",
348 "system-create"),
349 GNUNET_TESTING_cmd_end ()
350 };
351
352 ts->write_message = write_message;
353
354 is = GNUNET_TESTING_run (commands,
355 TIMEOUT,
356 &handle_result,
357 ts);
358 return is;
359}
360
361
362/**
363 * Entry point for the plugin.
364 *
365 * @param cls NULL
366 * @return the exported block API
367 */
368void *
369libgnunet_test_messenger_plugin_cmd_simple_join_init (void *cls)
370{
371 struct GNUNET_TESTING_PluginFunctions *api;
372
373 GNUNET_log_setup ("simple-join",
374 "DEBUG",
375 NULL);
376
377 api = GNUNET_new (struct GNUNET_TESTING_PluginFunctions);
378 api->start_testcase = &start_testcase;
379 api->get_waiting_for_barriers = get_waiting_for_barriers;
380 return api;
381}
382
383
384/**
385 * Exit point from the plugin.
386 *
387 * @param cls the return value from #libgnunet_test_messenger_plugin_cmd_simple_join_init
388 * @return NULL
389 */
390void *
391libgnunet_test_messenger_plugin_cmd_simple_join_done (void *cls)
392{
393 struct GNUNET_TESTING_PluginFunctions *api = cls;
394
395 GNUNET_free (api);
396 return NULL;
397}
398
399
400/* end of plugin_cmd_simple_send.c */
diff --git a/src/service/messenger/test_messenger_start_testcase.sh b/src/service/messenger/test_messenger_start_testcase.sh
new file mode 100755
index 000000000..29788638e
--- /dev/null
+++ b/src/service/messenger/test_messenger_start_testcase.sh
@@ -0,0 +1,16 @@
1#!/bin/bash
2read -p "Test case configuration to use:" conf
3if ! [ -d "/run/netns" ]; then
4 echo You have to create the directory /run/netns.
5fi
6if [ -f /proc/sys/kernel/unprivileged_userns_clone ]; then
7 if [ "$(cat /proc/sys/kernel/unprivileged_userns_clone)" != 1 ]; then
8 echo -e "Error during test setup: The kernel parameter kernel.unprivileged_userns_clone has to be set to 1! One has to execute\n\n sysctl kernel.unprivileged_userns_clone=1\n"
9 exit 78
10 fi
11fi
12START_WITH_CONFIG=/usr/local/lib/gnunet/libexec/test_testing_start_with_config
13if [ ! -f /usr/local/lib/gnunet/libexec/test_testing_start_with_config ]; then
14 START_WITH_CONFIG=/usr/lib/gnunet/libexec/test_testing_start_with_config
15fi
16exec unshare -r -nmU bash -c "mount -t tmpfs --make-rshared tmpfs /run/netns; $START_WITH_CONFIG $conf" \ No newline at end of file