diff options
Diffstat (limited to 'src/service/messenger')
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 @@ | |||
1 | gnunet-service-messenger | ||
2 | gnunet-messenger | ||
3 | test_messenger_api | ||
4 | test_messenger_anonymous | ||
5 | test_messenger_sync_client | ||
6 | test_messenger_async_client | ||
7 | test_messenger_worst_client | ||
8 | test_messenger_sync_p2p | ||
9 | test_messenger_async_p2p | ||
10 | test_messenger_worst_p2p | ||
11 | test_messenger_server | ||
12 | test_messenger_growth | ||
13 | test_messenger_ring | ||
14 | test_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 | ||
2 | AM_CPPFLAGS = -I$(top_srcdir)/src/include | ||
3 | |||
4 | if USE_COVERAGE | ||
5 | AM_CFLAGS = --coverage -O0 | ||
6 | XLIB = -lgcov | ||
7 | endif | ||
8 | |||
9 | pkgcfgdir= $(pkgdatadir)/config.d/ | ||
10 | |||
11 | libexecdir= $(pkglibdir)/libexec/ | ||
12 | |||
13 | pkgcfg_DATA = \ | ||
14 | messenger.conf | ||
15 | |||
16 | plugindir = $(libdir)/gnunet | ||
17 | |||
18 | AM_CLFAGS = -g | ||
19 | |||
20 | libexec_PROGRAMS = \ | ||
21 | gnunet-service-messenger \ | ||
22 | $(EXP_LIBEXEC) | ||
23 | |||
24 | plugin_LTLIBRARIES = \ | ||
25 | libgnunet_test_messenger_plugin_cmd_simple_join.la | ||
26 | |||
27 | TESTING_LIBS = \ | ||
28 | libgnunetmessengertesting.la | ||
29 | |||
30 | lib_LTLIBRARIES = \ | ||
31 | libgnunetmessenger.la \ | ||
32 | $(EXP_LIB) \ | ||
33 | $(TESTING_LIBS) | ||
34 | |||
35 | libgnunetmessenger_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 | ||
47 | libgnunetmessenger_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) | ||
53 | libgnunetmessenger_la_LDFLAGS = \ | ||
54 | $(GN_LIB_LDFLAGS) \ | ||
55 | -version-info 0:0:0 | ||
56 | |||
57 | libgnunetmessengertesting_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 | ||
63 | libgnunetmessengertesting_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 | ||
76 | libgnunetmessengertesting_la_LDFLAGS = \ | ||
77 | $(GN_LIBINTL) \ | ||
78 | $(GN_LIB_LDFLAGS) \ | ||
79 | -version-info 0:0:0 | ||
80 | |||
81 | libgnunet_test_messenger_plugin_cmd_simple_join_la_SOURCES = \ | ||
82 | messenger-testing-cmds.h \ | ||
83 | test_messenger_plugin_cmd_simple_join.c | ||
84 | libgnunet_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) | ||
101 | libgnunet_test_messenger_plugin_cmd_simple_join_la_LDFLAGS = \ | ||
102 | $(GN_PLUGIN_LDFLAGS) | ||
103 | |||
104 | gnunet_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 | ||
126 | gnunet_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 | |||
133 | check_PROGRAMS = \ | ||
134 | test_messenger_api \ | ||
135 | test_messenger_anonymous | ||
136 | |||
137 | #check_SCRIPTS= \ | ||
138 | # test_messenger_start_testcase.sh | ||
139 | |||
140 | if ENABLE_TEST_RUN | ||
141 | AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME; | ||
142 | TESTS = $(check_PROGRAMS) \ | ||
143 | $(check_SCRIPTS) | ||
144 | endif | ||
145 | |||
146 | test_messenger_api_SOURCES = \ | ||
147 | test_messenger.c | ||
148 | test_messenger_api_LDADD = \ | ||
149 | libgnunetmessenger.la \ | ||
150 | $(top_builddir)/src/lib/testing/libgnunettesting.la \ | ||
151 | $(top_builddir)/src/lib/util/libgnunetutil.la | ||
152 | |||
153 | test_messenger_anonymous_SOURCES = \ | ||
154 | test_messenger_anonymous.c | ||
155 | test_messenger_anonymous_LDADD = \ | ||
156 | libgnunetmessenger.la \ | ||
157 | $(top_builddir)/src/lib/testing/libgnunettesting.la \ | ||
158 | $(top_builddir)/src/lib/util/libgnunetutil.la | ||
159 | |||
160 | EXTRA_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 | |||
34 | struct GNUNET_MESSENGER_Client | ||
35 | { | ||
36 | struct GNUNET_SERVICE_Client *client; | ||
37 | struct GNUNET_MESSENGER_SrvHandle *handle; | ||
38 | }; | ||
39 | |||
40 | struct GNUNET_MESSENGER_Service *messenger; | ||
41 | |||
42 | static void | ||
43 | handle_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 | |||
54 | static void | ||
55 | handle_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 | |||
66 | static enum GNUNET_GenericReturnValue | ||
67 | check_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 | |||
92 | static void | ||
93 | initialize_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 | |||
121 | static enum GNUNET_GenericReturnValue | ||
122 | check_room_open (void *cls, | ||
123 | const struct GNUNET_MESSENGER_RoomMessage *msg) | ||
124 | { | ||
125 | return check_room_initial_key (msg); | ||
126 | } | ||
127 | |||
128 | |||
129 | static void | ||
130 | handle_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 | |||
168 | static enum GNUNET_GenericReturnValue | ||
169 | check_room_entry (void *cls, | ||
170 | const struct GNUNET_MESSENGER_RoomMessage *msg) | ||
171 | { | ||
172 | return check_room_initial_key (msg); | ||
173 | } | ||
174 | |||
175 | |||
176 | static void | ||
177 | handle_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 | |||
218 | static void | ||
219 | handle_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 | |||
249 | static void | ||
250 | handle_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 | |||
274 | static enum GNUNET_GenericReturnValue | ||
275 | check_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 | |||
320 | static void | ||
321 | handle_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 | |||
349 | static void | ||
350 | callback_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 | |||
420 | static void | ||
421 | handle_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 | |||
484 | end_handling: | ||
485 | GNUNET_SERVICE_client_continue (msg_client->client); | ||
486 | } | ||
487 | |||
488 | |||
489 | static void* | ||
490 | callback_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 | |||
504 | static void | ||
505 | callback_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 | */ | ||
524 | static void | ||
525 | run (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 | */ | ||
539 | GNUNET_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 | */ | ||
34 | struct GNUNET_MESSENGER_CreateMessage | ||
35 | { | ||
36 | struct GNUNET_MessageHeader header; | ||
37 | }; | ||
38 | |||
39 | /** | ||
40 | * Message to destroy the handle for a client | ||
41 | */ | ||
42 | struct GNUNET_MESSENGER_DestroyMessage | ||
43 | { | ||
44 | struct GNUNET_MessageHeader header; | ||
45 | }; | ||
46 | |||
47 | /** | ||
48 | * General message to confirm interaction with a room | ||
49 | */ | ||
50 | struct 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 | */ | ||
62 | struct 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 | */ | ||
74 | struct 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 | */ | ||
84 | struct 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 | */ | ||
95 | struct 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 | |||
28 | size_t | ||
29 | count_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 | |||
43 | enum GNUNET_GenericReturnValue | ||
44 | should_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 | |||
55 | enum GNUNET_GenericReturnValue | ||
56 | required_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 | */ | ||
37 | size_t | ||
38 | count_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 | */ | ||
50 | enum GNUNET_GenericReturnValue | ||
51 | should_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 | */ | ||
65 | enum GNUNET_GenericReturnValue | ||
66 | required_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 | |||
35 | struct GNUNET_MESSENGER_NextMemberId | ||
36 | { | ||
37 | struct GNUNET_ShortHashCode id; | ||
38 | enum GNUNET_GenericReturnValue reset; | ||
39 | }; | ||
40 | |||
41 | struct GNUNET_MESSENGER_SrvHandle* | ||
42 | create_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 | |||
63 | static enum GNUNET_GenericReturnValue | ||
64 | iterate_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 | |||
74 | static enum GNUNET_GenericReturnValue | ||
75 | iterate_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 | |||
84 | void | ||
85 | destroy_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 | |||
108 | void | ||
109 | set_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 | |||
127 | const struct GNUNET_CRYPTO_PublicKey* | ||
128 | get_srv_handle_key (const struct GNUNET_MESSENGER_SrvHandle *handle) | ||
129 | { | ||
130 | GNUNET_assert (handle); | ||
131 | |||
132 | return handle->key; | ||
133 | } | ||
134 | |||
135 | |||
136 | void | ||
137 | get_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 | |||
152 | static enum GNUNET_GenericReturnValue | ||
153 | create_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 | |||
183 | const struct GNUNET_ShortHashCode* | ||
184 | get_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 | |||
193 | enum GNUNET_GenericReturnValue | ||
194 | change_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 | |||
233 | enum GNUNET_GenericReturnValue | ||
234 | open_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 | |||
255 | enum GNUNET_GenericReturnValue | ||
256 | entry_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 | |||
271 | enum GNUNET_GenericReturnValue | ||
272 | close_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 | |||
302 | enum GNUNET_GenericReturnValue | ||
303 | is_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 | |||
312 | void | ||
313 | sync_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 | |||
334 | enum GNUNET_GenericReturnValue | ||
335 | send_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 | |||
376 | static const struct GNUNET_HashCode* | ||
377 | get_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 | |||
387 | static const struct GNUNET_MESSENGER_MemberSession* | ||
388 | get_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 | |||
422 | void | ||
423 | notify_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 | |||
495 | static enum GNUNET_GenericReturnValue | ||
496 | iterate_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 | |||
523 | static void | ||
524 | task_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 | |||
535 | void | ||
536 | notify_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 | |||
34 | struct 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 | */ | ||
55 | struct GNUNET_MESSENGER_SrvHandle* | ||
56 | create_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 | */ | ||
64 | void | ||
65 | destroy_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 | */ | ||
73 | void | ||
74 | set_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 | */ | ||
83 | const struct GNUNET_CRYPTO_PublicKey* | ||
84 | get_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 | */ | ||
94 | void | ||
95 | get_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 | */ | ||
108 | const struct GNUNET_ShortHashCode* | ||
109 | get_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 | */ | ||
123 | enum GNUNET_GenericReturnValue | ||
124 | change_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 | */ | ||
136 | enum GNUNET_GenericReturnValue | ||
137 | open_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 | */ | ||
149 | enum GNUNET_GenericReturnValue | ||
150 | entry_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 | */ | ||
162 | enum GNUNET_GenericReturnValue | ||
163 | close_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 | */ | ||
174 | enum GNUNET_GenericReturnValue | ||
175 | is_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 | */ | ||
190 | void | ||
191 | sync_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 | */ | ||
204 | enum GNUNET_GenericReturnValue | ||
205 | send_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 | */ | ||
219 | void | ||
220 | notify_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 | */ | ||
235 | void | ||
236 | notify_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 | |||
30 | void | ||
31 | init_list_handles (struct GNUNET_MESSENGER_ListHandles *handles) | ||
32 | { | ||
33 | GNUNET_assert (handles); | ||
34 | |||
35 | handles->head = NULL; | ||
36 | handles->tail = NULL; | ||
37 | } | ||
38 | |||
39 | |||
40 | void | ||
41 | clear_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 | |||
59 | void | ||
60 | add_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 | |||
74 | enum GNUNET_GenericReturnValue | ||
75 | remove_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 | |||
96 | struct GNUNET_MESSENGER_SrvHandle* | ||
97 | find_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 | |||
31 | struct GNUNET_MESSENGER_SrvHandle; | ||
32 | |||
33 | struct 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 | |||
41 | struct 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 | */ | ||
52 | void | ||
53 | init_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 | */ | ||
60 | void | ||
61 | clear_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 | */ | ||
69 | void | ||
70 | add_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 | */ | ||
81 | enum GNUNET_GenericReturnValue | ||
82 | remove_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 | */ | ||
96 | struct GNUNET_MESSENGER_SrvHandle* | ||
97 | find_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 | |||
30 | void | ||
31 | init_list_messages (struct GNUNET_MESSENGER_ListMessages *messages) | ||
32 | { | ||
33 | GNUNET_assert (messages); | ||
34 | |||
35 | messages->head = NULL; | ||
36 | messages->tail = NULL; | ||
37 | } | ||
38 | |||
39 | |||
40 | void | ||
41 | clear_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 | |||
58 | void | ||
59 | add_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 | |||
73 | void | ||
74 | copy_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 | |||
86 | void | ||
87 | remove_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 | |||
104 | void | ||
105 | load_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 | |||
142 | void | ||
143 | save_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 | |||
31 | struct GNUNET_MESSENGER_ListMessage | ||
32 | { | ||
33 | struct GNUNET_MESSENGER_ListMessage *prev; | ||
34 | struct GNUNET_MESSENGER_ListMessage *next; | ||
35 | |||
36 | struct GNUNET_HashCode hash; | ||
37 | }; | ||
38 | |||
39 | struct 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 | */ | ||
50 | void | ||
51 | init_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 | */ | ||
58 | void | ||
59 | clear_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 | */ | ||
67 | void | ||
68 | add_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 | */ | ||
77 | void | ||
78 | copy_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 | */ | ||
87 | void | ||
88 | remove_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 | */ | ||
97 | void | ||
98 | load_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 | */ | ||
107 | void | ||
108 | save_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 | |||
33 | struct GNUNET_MESSENGER_Member* | ||
34 | create_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 | |||
59 | static enum GNUNET_GenericReturnValue | ||
60 | iterate_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 | |||
70 | void | ||
71 | destroy_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 | |||
83 | const struct GNUNET_ShortHashCode* | ||
84 | get_member_id (const struct GNUNET_MESSENGER_Member *member) | ||
85 | { | ||
86 | GNUNET_assert (member); | ||
87 | |||
88 | return &(member->id); | ||
89 | } | ||
90 | |||
91 | |||
92 | static enum GNUNET_GenericReturnValue | ||
93 | callback_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 | |||
112 | void | ||
113 | load_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 | |||
142 | destroy_config: | ||
143 | |||
144 | GNUNET_CONFIGURATION_destroy (cfg); | ||
145 | |||
146 | free_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 | |||
162 | static enum GNUNET_GenericReturnValue | ||
163 | iterate_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 | |||
183 | void | ||
184 | load_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 | |||
199 | static enum GNUNET_GenericReturnValue | ||
200 | iterate_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 | |||
221 | void | ||
222 | save_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 | |||
262 | static void | ||
263 | sync_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 | |||
278 | static enum GNUNET_GenericReturnValue | ||
279 | iterate_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 | |||
292 | void | ||
293 | sync_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 | |||
302 | struct GNUNET_MESSENGER_MemberSession* | ||
303 | get_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 | |||
315 | struct 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 | |||
323 | static enum GNUNET_GenericReturnValue | ||
324 | iterate_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 | |||
340 | static struct GNUNET_MESSENGER_MemberSession* | ||
341 | try_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 | |||
359 | struct GNUNET_MESSENGER_MemberSession* | ||
360 | get_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 | |||
384 | void | ||
385 | add_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 | |||
408 | void | ||
409 | remove_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 | |||
428 | struct GNUNET_MESSENGER_ClosureIterateSessions | ||
429 | { | ||
430 | GNUNET_MESSENGER_MemberIteratorCallback it; | ||
431 | void *cls; | ||
432 | }; | ||
433 | |||
434 | static enum GNUNET_GenericReturnValue | ||
435 | iterate_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 | |||
447 | int | ||
448 | iterate_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 | |||
31 | struct 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 | */ | ||
49 | struct GNUNET_MESSENGER_Member* | ||
50 | create_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 | */ | ||
58 | void | ||
59 | destroy_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 | */ | ||
67 | const struct GNUNET_ShortHashCode* | ||
68 | get_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 | */ | ||
78 | void | ||
79 | load_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 | */ | ||
89 | void | ||
90 | load_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 | */ | ||
100 | void | ||
101 | save_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 | */ | ||
110 | void | ||
111 | sync_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 | */ | ||
121 | struct GNUNET_MESSENGER_MemberSession* | ||
122 | get_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 | */ | ||
135 | struct GNUNET_MESSENGER_MemberSession* | ||
136 | get_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 | */ | ||
146 | void | ||
147 | add_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 | */ | ||
156 | void | ||
157 | remove_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 | */ | ||
170 | int | ||
171 | iterate_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 | |||
33 | struct GNUNET_MESSENGER_MemberSession* | ||
34 | create_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 | |||
85 | static void | ||
86 | check_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 | |||
151 | completion: | ||
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 | |||
173 | static enum GNUNET_GenericReturnValue | ||
174 | iterate_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 | |||
187 | struct GNUNET_MESSENGER_MemberSession* | ||
188 | switch_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 | |||
264 | void | ||
265 | destroy_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 | |||
287 | enum GNUNET_GenericReturnValue | ||
288 | reset_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 | |||
310 | clear_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 | |||
322 | void | ||
323 | close_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 | |||
332 | enum GNUNET_GenericReturnValue | ||
333 | is_member_session_closed (const struct GNUNET_MESSENGER_MemberSession *session) | ||
334 | { | ||
335 | GNUNET_assert (session); | ||
336 | |||
337 | return session->closed; | ||
338 | } | ||
339 | |||
340 | |||
341 | enum GNUNET_GenericReturnValue | ||
342 | is_member_session_completed (const struct | ||
343 | GNUNET_MESSENGER_MemberSession *session) | ||
344 | { | ||
345 | GNUNET_assert (session); | ||
346 | |||
347 | return session->completed; | ||
348 | } | ||
349 | |||
350 | |||
351 | struct GNUNET_TIME_Absolute | ||
352 | get_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 | |||
363 | const struct GNUNET_HashCode* | ||
364 | get_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 | |||
372 | const struct GNUNET_ShortHashCode* | ||
373 | get_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 | |||
381 | const struct GNUNET_CRYPTO_PublicKey* | ||
382 | get_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 | |||
391 | const struct GNUNET_HashCode* | ||
392 | get_member_session_context (const struct | ||
393 | GNUNET_MESSENGER_MemberSession *session) | ||
394 | { | ||
395 | GNUNET_assert (session); | ||
396 | |||
397 | return &(session->context); | ||
398 | } | ||
399 | |||
400 | |||
401 | struct GNUNET_MESSENGER_Contact* | ||
402 | get_member_session_contact (struct GNUNET_MESSENGER_MemberSession *session) | ||
403 | { | ||
404 | GNUNET_assert (session); | ||
405 | |||
406 | return session->contact; | ||
407 | } | ||
408 | |||
409 | |||
410 | enum GNUNET_GenericReturnValue | ||
411 | verify_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 | |||
443 | enum GNUNET_GenericReturnValue | ||
444 | check_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 | |||
459 | static void | ||
460 | update_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 | |||
475 | void | ||
476 | update_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 | |||
504 | static void | ||
505 | clear_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 | |||
516 | void | ||
517 | clear_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 | |||
526 | struct GNUNET_MESSENGER_MemberSessionHistoryEntry | ||
527 | { | ||
528 | struct GNUNET_HashCode hash; | ||
529 | unsigned char ownership; | ||
530 | }; | ||
531 | |||
532 | static void | ||
533 | load_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 | |||
581 | void | ||
582 | load_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 | |||
639 | destroy_config: | ||
640 | GNUNET_CONFIGURATION_destroy (cfg); | ||
641 | |||
642 | free_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 | |||
664 | static struct GNUNET_MESSENGER_MemberSession* | ||
665 | get_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 | |||
684 | void | ||
685 | load_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 | |||
737 | destroy_config: | ||
738 | GNUNET_CONFIGURATION_destroy (cfg); | ||
739 | |||
740 | free_config: | ||
741 | GNUNET_free (config_file); | ||
742 | } | ||
743 | |||
744 | |||
745 | static enum GNUNET_GenericReturnValue | ||
746 | iterate_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 | |||
760 | static void | ||
761 | save_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 | |||
790 | void | ||
791 | save_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 | |||
37 | struct 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 | */ | ||
68 | struct GNUNET_MESSENGER_MemberSession* | ||
69 | create_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 | */ | ||
84 | struct GNUNET_MESSENGER_MemberSession* | ||
85 | switch_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 | */ | ||
94 | void | ||
95 | destroy_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 | */ | ||
107 | enum GNUNET_GenericReturnValue | ||
108 | reset_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 | */ | ||
120 | void | ||
121 | close_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 | */ | ||
129 | enum GNUNET_GenericReturnValue | ||
130 | is_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 | */ | ||
141 | enum GNUNET_GenericReturnValue | ||
142 | is_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 | */ | ||
151 | struct GNUNET_TIME_Absolute | ||
152 | get_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 | */ | ||
160 | const struct GNUNET_HashCode* | ||
161 | get_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 | */ | ||
169 | const struct GNUNET_ShortHashCode* | ||
170 | get_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 | */ | ||
178 | const struct GNUNET_CRYPTO_PublicKey* | ||
179 | get_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 | */ | ||
188 | const struct GNUNET_HashCode* | ||
189 | get_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 | */ | ||
198 | struct GNUNET_MESSENGER_Contact* | ||
199 | get_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 | */ | ||
213 | enum GNUNET_GenericReturnValue | ||
214 | verify_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 | */ | ||
229 | enum GNUNET_GenericReturnValue | ||
230 | check_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 | */ | ||
245 | void | ||
246 | update_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 | */ | ||
257 | void | ||
258 | clear_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 | */ | ||
269 | void | ||
270 | load_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 | */ | ||
281 | void | ||
282 | load_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 | */ | ||
292 | void | ||
293 | save_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 | |||
35 | void | ||
36 | init_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 | |||
46 | static enum GNUNET_GenericReturnValue | ||
47 | iterate_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 | |||
57 | void | ||
58 | clear_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 | |||
71 | struct GNUNET_MESSENGER_ContactStore* | ||
72 | get_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 | |||
82 | const struct GNUNET_HashCode* | ||
83 | get_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 | |||
92 | static enum GNUNET_GenericReturnValue | ||
93 | callback_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 | |||
113 | static enum GNUNET_GenericReturnValue | ||
114 | iterate_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 | |||
137 | static enum GNUNET_GenericReturnValue | ||
138 | iterate_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 | |||
152 | void | ||
153 | load_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 | |||
177 | static enum GNUNET_GenericReturnValue | ||
178 | iterate_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 | |||
202 | void | ||
203 | save_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 | |||
223 | struct GNUNET_MESSENGER_Member* | ||
224 | get_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 | |||
233 | struct GNUNET_MESSENGER_Member* | ||
234 | get_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 | |||
249 | struct GNUNET_MESSENGER_Member* | ||
250 | add_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 | |||
282 | struct GNUNET_MESSENGER_ClosureIterateMembers | ||
283 | { | ||
284 | GNUNET_MESSENGER_MemberIteratorCallback it; | ||
285 | void *cls; | ||
286 | }; | ||
287 | |||
288 | static int | ||
289 | iterate_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 | |||
300 | int | ||
301 | iterate_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 | |||
33 | struct GNUNET_MESSENGER_SrvRoom; | ||
34 | |||
35 | struct GNUNET_MESSENGER_Member; | ||
36 | struct GNUNET_MESSENGER_MemberSession; | ||
37 | |||
38 | struct GNUNET_MESSENGER_MemberStore | ||
39 | { | ||
40 | struct GNUNET_MESSENGER_SrvRoom *room; | ||
41 | |||
42 | struct GNUNET_CONTAINER_MultiShortmap *members; | ||
43 | }; | ||
44 | |||
45 | typedef 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 | */ | ||
56 | void | ||
57 | init_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 | */ | ||
65 | void | ||
66 | clear_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 | */ | ||
74 | struct GNUNET_MESSENGER_ContactStore* | ||
75 | get_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 | */ | ||
83 | const struct GNUNET_HashCode* | ||
84 | get_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 | */ | ||
92 | void | ||
93 | load_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 | */ | ||
102 | void | ||
103 | save_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 | */ | ||
114 | struct GNUNET_MESSENGER_Member* | ||
115 | get_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 | */ | ||
128 | struct GNUNET_MESSENGER_Member* | ||
129 | get_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 | */ | ||
139 | struct GNUNET_MESSENGER_Member* | ||
140 | add_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 | */ | ||
153 | int | ||
154 | iterate_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 | |||
30 | static void | ||
31 | handle_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 | |||
44 | void | ||
45 | handle_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 | |||
66 | void | ||
67 | handle_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 | |||
80 | void | ||
81 | handle_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 | |||
90 | void | ||
91 | handle_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 | |||
110 | void | ||
111 | handle_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 | |||
127 | void | ||
128 | handle_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 | |||
151 | void | ||
152 | handle_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 | |||
171 | void | ||
172 | handle_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 | */ | ||
40 | void | ||
41 | handle_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 | */ | ||
55 | void | ||
56 | handle_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 | */ | ||
70 | void | ||
71 | handle_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 | */ | ||
85 | void | ||
86 | handle_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 | */ | ||
100 | void | ||
101 | handle_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 | */ | ||
115 | void | ||
116 | handle_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 | */ | ||
130 | void | ||
131 | handle_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 | */ | ||
145 | void | ||
146 | handle_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 | |||
32 | struct GNUNET_MESSENGER_Message* | ||
33 | create_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 | |||
50 | struct GNUNET_MESSENGER_Message* | ||
51 | create_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 | |||
73 | struct GNUNET_MESSENGER_Message* | ||
74 | create_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 | |||
94 | struct GNUNET_MESSENGER_Message* | ||
95 | create_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 | |||
113 | struct GNUNET_MESSENGER_Message* | ||
114 | create_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 | */ | ||
40 | struct GNUNET_MESSENGER_Message* | ||
41 | create_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 | */ | ||
50 | struct GNUNET_MESSENGER_Message* | ||
51 | create_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 | */ | ||
60 | struct GNUNET_MESSENGER_Message* | ||
61 | create_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 | */ | ||
71 | struct GNUNET_MESSENGER_Message* | ||
72 | create_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 | */ | ||
82 | struct GNUNET_MESSENGER_Message* | ||
83 | create_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 | |||
32 | static void | ||
33 | forward_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 | |||
67 | static enum GNUNET_GenericReturnValue | ||
68 | iterate_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 | |||
87 | enum GNUNET_GenericReturnValue | ||
88 | recv_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 | |||
145 | enum GNUNET_GenericReturnValue | ||
146 | recv_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 | |||
167 | enum GNUNET_GenericReturnValue | ||
168 | recv_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 | |||
183 | static void | ||
184 | callback_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 | */ | ||
212 | enum GNUNET_GenericReturnValue | ||
213 | recv_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 | */ | ||
41 | enum GNUNET_GenericReturnValue | ||
42 | recv_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 | */ | ||
57 | enum GNUNET_GenericReturnValue | ||
58 | recv_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 | */ | ||
73 | enum GNUNET_GenericReturnValue | ||
74 | recv_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 | */ | ||
90 | enum GNUNET_GenericReturnValue | ||
91 | recv_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 | |||
36 | struct GNUNET_MESSENGER_MemberNotify | ||
37 | { | ||
38 | struct GNUNET_MESSENGER_SrvRoom *room; | ||
39 | struct GNUNET_MESSENGER_SrvHandle *handle; | ||
40 | struct GNUNET_MESSENGER_MemberSession *session; | ||
41 | }; | ||
42 | |||
43 | static void | ||
44 | notify_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 | |||
102 | static enum GNUNET_GenericReturnValue | ||
103 | iterate_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 | |||
127 | void | ||
128 | send_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, ¬ify); | ||
163 | |||
164 | skip_member_notification: | ||
165 | check_srv_room_peer_status (room, NULL); | ||
166 | } | ||
167 | |||
168 | |||
169 | void | ||
170 | send_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 | |||
179 | void | ||
180 | send_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 | |||
194 | void | ||
195 | send_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 | |||
205 | void | ||
206 | send_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 | */ | ||
40 | void | ||
41 | send_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 | */ | ||
54 | void | ||
55 | send_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 | */ | ||
69 | void | ||
70 | send_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 | */ | ||
84 | void | ||
85 | send_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 | */ | ||
99 | void | ||
100 | send_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 | |||
28 | void | ||
29 | init_message_state (struct GNUNET_MESSENGER_MessageState *state) | ||
30 | { | ||
31 | GNUNET_assert (state); | ||
32 | |||
33 | init_list_messages (&(state->last_messages)); | ||
34 | } | ||
35 | |||
36 | |||
37 | void | ||
38 | clear_message_state (struct GNUNET_MESSENGER_MessageState *state) | ||
39 | { | ||
40 | GNUNET_assert (state); | ||
41 | |||
42 | clear_list_messages (&(state->last_messages)); | ||
43 | } | ||
44 | |||
45 | |||
46 | void | ||
47 | get_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 | |||
59 | const struct GNUNET_HashCode* | ||
60 | get_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 | |||
71 | void | ||
72 | update_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 | |||
94 | void | ||
95 | load_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 | |||
108 | void | ||
109 | save_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 | |||
33 | struct GNUNET_MESSENGER_MessageState | ||
34 | { | ||
35 | struct GNUNET_MESSENGER_ListMessages last_messages; | ||
36 | }; | ||
37 | |||
38 | void | ||
39 | init_message_state (struct GNUNET_MESSENGER_MessageState *state); | ||
40 | |||
41 | void | ||
42 | clear_message_state (struct GNUNET_MESSENGER_MessageState *state); | ||
43 | |||
44 | void | ||
45 | get_message_state_chain_hash (const struct GNUNET_MESSENGER_MessageState *state, | ||
46 | struct GNUNET_HashCode *hash); | ||
47 | |||
48 | const struct GNUNET_HashCode* | ||
49 | get_message_state_merge_hash (const struct | ||
50 | GNUNET_MESSENGER_MessageState *state); | ||
51 | |||
52 | void | ||
53 | update_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 | |||
58 | void | ||
59 | load_message_state (struct GNUNET_MESSENGER_MessageState *state, | ||
60 | const char *path); | ||
61 | |||
62 | void | ||
63 | save_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 | |||
29 | void | ||
30 | init_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 | |||
45 | static enum GNUNET_GenericReturnValue | ||
46 | iterate_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 | |||
58 | static enum GNUNET_GenericReturnValue | ||
59 | iterate_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 | |||
71 | static enum GNUNET_GenericReturnValue | ||
72 | iterate_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 | |||
84 | void | ||
85 | clear_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 | |||
109 | struct 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 | |||
123 | static void | ||
124 | load_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 | |||
174 | struct GNUNET_MESSENGER_MessageLinkStorage | ||
175 | { | ||
176 | struct GNUNET_HashCode hash; | ||
177 | struct GNUNET_MESSENGER_MessageLink link; | ||
178 | }; | ||
179 | |||
180 | static void | ||
181 | load_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 | |||
232 | void | ||
233 | load_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 | |||
276 | struct GNUNET_MESSENGER_ClosureMessageSave | ||
277 | { | ||
278 | struct GNUNET_MESSENGER_MessageStore *store; | ||
279 | |||
280 | struct GNUNET_DISK_FileHandle *storage; | ||
281 | }; | ||
282 | |||
283 | static enum GNUNET_GenericReturnValue | ||
284 | iterate_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 | |||
301 | static enum GNUNET_GenericReturnValue | ||
302 | iterate_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 | |||
344 | static enum GNUNET_GenericReturnValue | ||
345 | iterate_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 | |||
365 | void | ||
366 | save_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 | |||
401 | close_links: | ||
402 | GNUNET_DISK_file_close (save.storage); | ||
403 | |||
404 | save_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 | |||
451 | close_entries: | ||
452 | GNUNET_DISK_file_close (save.storage); | ||
453 | } | ||
454 | |||
455 | |||
456 | enum GNUNET_GenericReturnValue | ||
457 | contains_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 | |||
470 | const struct GNUNET_MESSENGER_Message* | ||
471 | get_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 | |||
538 | free_buffer: | ||
539 | GNUNET_free (buffer); | ||
540 | |||
541 | return message; | ||
542 | } | ||
543 | |||
544 | |||
545 | const struct GNUNET_MESSENGER_MessageLink* | ||
546 | get_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 | |||
576 | get_link: | ||
577 | return GNUNET_CONTAINER_multihashmap_get (store->links, hash); | ||
578 | } | ||
579 | |||
580 | |||
581 | enum GNUNET_GenericReturnValue | ||
582 | put_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 | |||
593 | static void | ||
594 | add_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 | |||
623 | enum GNUNET_GenericReturnValue | ||
624 | delete_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 | |||
669 | clear_entry: | ||
670 | if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (store->entries, hash, | ||
671 | entry)) | ||
672 | store->rewrite_entries = GNUNET_YES; | ||
673 | |||
674 | clear_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 | |||
31 | struct GNUNET_MESSENGER_MessageEntry | ||
32 | { | ||
33 | off_t offset; | ||
34 | uint16_t length; | ||
35 | }; | ||
36 | |||
37 | struct GNUNET_MESSENGER_Message; | ||
38 | |||
39 | struct GNUNET_MESSENGER_MessageLink | ||
40 | { | ||
41 | uint8_t multiple; | ||
42 | |||
43 | struct GNUNET_HashCode first; | ||
44 | struct GNUNET_HashCode second; | ||
45 | }; | ||
46 | |||
47 | struct 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 | */ | ||
64 | void | ||
65 | init_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 | */ | ||
72 | void | ||
73 | clear_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 | */ | ||
81 | void | ||
82 | load_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 | */ | ||
91 | void | ||
92 | save_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 | */ | ||
105 | enum GNUNET_GenericReturnValue | ||
106 | contains_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 | */ | ||
120 | const struct GNUNET_MESSENGER_Message* | ||
121 | get_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 | */ | ||
137 | const struct GNUNET_MESSENGER_MessageLink* | ||
138 | get_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 | */ | ||
150 | enum GNUNET_GenericReturnValue | ||
151 | put_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 | */ | ||
163 | enum GNUNET_GenericReturnValue | ||
164 | delete_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 | |||
30 | struct GNUNET_MESSENGER_Operation* | ||
31 | create_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 | |||
48 | void | ||
49 | destroy_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 | |||
60 | static void | ||
61 | callback_operation (void *cls); | ||
62 | |||
63 | struct GNUNET_MESSENGER_Operation* | ||
64 | load_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 | |||
127 | destroy_config: | ||
128 | GNUNET_CONFIGURATION_destroy (cfg); | ||
129 | |||
130 | return op; | ||
131 | } | ||
132 | |||
133 | |||
134 | void | ||
135 | save_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 | |||
175 | extern void | ||
176 | callback_store_operation (struct GNUNET_MESSENGER_OperationStore *store, | ||
177 | enum GNUNET_MESSENGER_OperationType type, | ||
178 | const struct GNUNET_HashCode *hash); | ||
179 | |||
180 | static void | ||
181 | callback_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 | |||
191 | enum GNUNET_GenericReturnValue | ||
192 | start_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 | |||
222 | enum GNUNET_GenericReturnValue | ||
223 | stop_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 | |||
33 | enum 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 | |||
42 | struct GNUNET_MESSENGER_OperationStore; | ||
43 | |||
44 | struct 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 | */ | ||
60 | struct GNUNET_MESSENGER_Operation* | ||
61 | create_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 | */ | ||
68 | void | ||
69 | destroy_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 | */ | ||
85 | struct GNUNET_MESSENGER_Operation* | ||
86 | load_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 | */ | ||
97 | void | ||
98 | save_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 | */ | ||
113 | enum GNUNET_GenericReturnValue | ||
114 | start_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 | */ | ||
125 | enum GNUNET_GenericReturnValue | ||
126 | stop_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 | |||
32 | void | ||
33 | init_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 | |||
43 | static enum GNUNET_GenericReturnValue | ||
44 | iterate_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 | |||
56 | void | ||
57 | clear_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 | |||
70 | static enum GNUNET_GenericReturnValue | ||
71 | callback_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 | |||
97 | void | ||
98 | load_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 | |||
117 | static enum GNUNET_GenericReturnValue | ||
118 | iterate_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 | |||
138 | void | ||
139 | save_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 | |||
160 | enum GNUNET_MESSENGER_OperationType | ||
161 | get_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 | |||
176 | enum GNUNET_GenericReturnValue | ||
177 | use_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 | |||
201 | use_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 | |||
210 | void | ||
211 | cancel_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 | |||
234 | extern void | ||
235 | callback_room_deletion (struct GNUNET_MESSENGER_SrvRoom *room, | ||
236 | const struct GNUNET_HashCode *hash); | ||
237 | |||
238 | extern void | ||
239 | callback_room_merge (struct GNUNET_MESSENGER_SrvRoom *room, | ||
240 | const struct GNUNET_HashCode *hash); | ||
241 | |||
242 | void | ||
243 | callback_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 | |||
32 | struct GNUNET_MESSENGER_SrvRoom; | ||
33 | |||
34 | struct 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 | */ | ||
47 | void | ||
48 | init_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 | */ | ||
56 | void | ||
57 | clear_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 | */ | ||
65 | void | ||
66 | load_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 | */ | ||
75 | void | ||
76 | save_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 | */ | ||
88 | enum GNUNET_MESSENGER_OperationType | ||
89 | get_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 | */ | ||
109 | enum GNUNET_GenericReturnValue | ||
110 | use_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 | */ | ||
125 | void | ||
126 | cancel_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 | |||
33 | struct GNUNET_MESSENGER_PeerStoreEntry | ||
34 | { | ||
35 | struct GNUNET_PeerIdentity peer; | ||
36 | enum GNUNET_GenericReturnValue active; | ||
37 | }; | ||
38 | |||
39 | void | ||
40 | init_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 | |||
50 | static enum GNUNET_GenericReturnValue | ||
51 | iterate_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 | |||
60 | void | ||
61 | clear_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 | |||
75 | void | ||
76 | load_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 | |||
134 | static enum GNUNET_GenericReturnValue | ||
135 | iterate_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 | |||
152 | void | ||
153 | save_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 | |||
181 | struct GNUNET_MESSENGER_ClosureVerifyPeer | ||
182 | { | ||
183 | const struct GNUNET_MESSENGER_Message *message; | ||
184 | const struct GNUNET_HashCode *hash; | ||
185 | struct GNUNET_PeerIdentity *sender; | ||
186 | }; | ||
187 | |||
188 | static enum GNUNET_GenericReturnValue | ||
189 | verify_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 | |||
209 | static struct GNUNET_MESSENGER_PeerStoreEntry* | ||
210 | add_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 | |||
238 | static const struct GNUNET_PeerIdentity* | ||
239 | get_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 | |||
250 | struct GNUNET_PeerIdentity* | ||
251 | get_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 | |||
329 | struct GNUNET_MESSENGER_ClosureFindPeer | ||
330 | { | ||
331 | const struct GNUNET_PeerIdentity *requested; | ||
332 | struct GNUNET_MESSENGER_PeerStoreEntry *match; | ||
333 | }; | ||
334 | |||
335 | static enum GNUNET_GenericReturnValue | ||
336 | find_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 | |||
354 | void | ||
355 | update_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 | |||
31 | struct GNUNET_MESSENGER_Message; | ||
32 | struct GNUNET_MESSENGER_Service; | ||
33 | |||
34 | struct 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 | */ | ||
46 | void | ||
47 | init_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 | */ | ||
55 | void | ||
56 | clear_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 | */ | ||
64 | void | ||
65 | load_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 | */ | ||
74 | void | ||
75 | save_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 | */ | ||
89 | struct GNUNET_PeerIdentity* | ||
90 | get_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 | */ | ||
103 | void | ||
104 | update_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 | |||
42 | static void | ||
43 | idle_request_room_messages (void *cls); | ||
44 | |||
45 | struct GNUNET_MESSENGER_SrvRoom* | ||
46 | create_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 | |||
85 | static enum GNUNET_GenericReturnValue | ||
86 | iterate_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 | |||
96 | static void | ||
97 | close_srv_room (struct GNUNET_MESSENGER_SrvRoom *room); | ||
98 | |||
99 | static void | ||
100 | handle_room_messages (struct GNUNET_MESSENGER_SrvRoom *room); | ||
101 | |||
102 | void | ||
103 | destroy_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 | |||
128 | skip_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 | |||
145 | struct GNUNET_MESSENGER_PeerStore* | ||
146 | get_srv_room_peer_store (struct GNUNET_MESSENGER_SrvRoom *room) | ||
147 | { | ||
148 | GNUNET_assert (room); | ||
149 | |||
150 | return &(room->peer_store); | ||
151 | } | ||
152 | |||
153 | |||
154 | struct GNUNET_MESSENGER_MemberStore* | ||
155 | get_srv_room_member_store (struct GNUNET_MESSENGER_SrvRoom *room) | ||
156 | { | ||
157 | GNUNET_assert (room); | ||
158 | |||
159 | return &(room->member_store); | ||
160 | } | ||
161 | |||
162 | |||
163 | struct GNUNET_MESSENGER_MessageStore* | ||
164 | get_srv_room_message_store (struct GNUNET_MESSENGER_SrvRoom *room) | ||
165 | { | ||
166 | GNUNET_assert (room); | ||
167 | |||
168 | return &(room->message_store); | ||
169 | } | ||
170 | |||
171 | |||
172 | struct GNUNET_MESSENGER_OperationStore* | ||
173 | get_srv_room_operation_store (struct GNUNET_MESSENGER_SrvRoom *room) | ||
174 | { | ||
175 | GNUNET_assert (room); | ||
176 | |||
177 | return &(room->operation_store); | ||
178 | } | ||
179 | |||
180 | |||
181 | static enum GNUNET_GenericReturnValue | ||
182 | send_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 | |||
194 | static void* | ||
195 | callback_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 | |||
237 | static enum GNUNET_GenericReturnValue | ||
238 | join_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 | |||
266 | static enum GNUNET_GenericReturnValue | ||
267 | join_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 | |||
285 | extern enum GNUNET_GenericReturnValue | ||
286 | check_tunnel_message (void *cls, | ||
287 | const struct GNUNET_MessageHeader *header); | ||
288 | |||
289 | extern void | ||
290 | handle_tunnel_message (void *cls, | ||
291 | const struct GNUNET_MessageHeader *header); | ||
292 | |||
293 | extern void | ||
294 | callback_tunnel_disconnect (void *cls, | ||
295 | const struct GNUNET_CADET_Channel *channel); | ||
296 | |||
297 | |||
298 | enum GNUNET_GenericReturnValue | ||
299 | open_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 | |||
360 | complete_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 | |||
369 | static void | ||
370 | close_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 | |||
387 | enum GNUNET_GenericReturnValue | ||
388 | enter_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 | |||
431 | static void | ||
432 | sign_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 | |||
446 | struct GNUNET_MQ_Envelope* | ||
447 | pack_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 | |||
478 | struct 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 | |||
488 | static enum GNUNET_GenericReturnValue | ||
489 | iterate_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 | |||
526 | enum GNUNET_GenericReturnValue | ||
527 | update_room_message (struct GNUNET_MESSENGER_SrvRoom *room, | ||
528 | struct GNUNET_MESSENGER_Message *message, | ||
529 | const struct GNUNET_HashCode *hash); | ||
530 | |||
531 | void | ||
532 | callback_room_handle_message (struct GNUNET_MESSENGER_SrvRoom *room, | ||
533 | const struct GNUNET_MESSENGER_Message *message, | ||
534 | const struct GNUNET_HashCode *hash); | ||
535 | |||
536 | enum GNUNET_GenericReturnValue | ||
537 | send_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 | |||
603 | void | ||
604 | forward_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 | |||
631 | void | ||
632 | check_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 | |||
656 | void | ||
657 | merge_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 | |||
671 | merge_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 | |||
682 | void | ||
683 | callback_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 | |||
696 | void | ||
697 | callback_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 | |||
707 | enum GNUNET_GenericReturnValue | ||
708 | delete_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 | |||
759 | struct GNUNET_CADET_Handle* | ||
760 | get_srv_room_cadet (struct GNUNET_MESSENGER_SrvRoom *room) | ||
761 | { | ||
762 | GNUNET_assert (room); | ||
763 | |||
764 | return room->service->cadet; | ||
765 | } | ||
766 | |||
767 | |||
768 | const struct GNUNET_HashCode* | ||
769 | get_srv_room_key (const struct GNUNET_MESSENGER_SrvRoom *room) | ||
770 | { | ||
771 | GNUNET_assert (room); | ||
772 | |||
773 | return &(room->key); | ||
774 | } | ||
775 | |||
776 | |||
777 | const struct GNUNET_MESSENGER_SrvTunnel* | ||
778 | get_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 | |||
787 | static enum GNUNET_GenericReturnValue | ||
788 | request_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 | |||
821 | forward: | ||
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 | |||
844 | enum GNUNET_GenericReturnValue | ||
845 | request_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 | |||
863 | void | ||
864 | callback_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 | |||
900 | enum GNUNET_GenericReturnValue | ||
901 | callback_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 | |||
934 | skip_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 | |||
942 | static void | ||
943 | idle_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 | |||
973 | void | ||
974 | solve_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 | |||
1027 | void | ||
1028 | rebuild_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 | |||
1087 | uint32_t | ||
1088 | get_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 | |||
1096 | uint32_t | ||
1097 | get_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 | |||
1110 | static void | ||
1111 | handle_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 | |||
1162 | finish_handling: | ||
1163 | GNUNET_CONTAINER_DLL_remove (room->handling.head, room->handling.tail, | ||
1164 | element); | ||
1165 | GNUNET_free (element); | ||
1166 | } | ||
1167 | } | ||
1168 | |||
1169 | |||
1170 | enum GNUNET_GenericReturnValue | ||
1171 | update_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 | |||
1229 | struct 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 | |||
1237 | struct 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 | |||
1246 | static enum GNUNET_GenericReturnValue | ||
1247 | iterate_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 | |||
1271 | static void | ||
1272 | remove_room_member_session (struct GNUNET_MESSENGER_SrvRoom *room, | ||
1273 | struct GNUNET_MESSENGER_MemberSession *session); | ||
1274 | |||
1275 | void | ||
1276 | callback_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 | |||
1384 | static void | ||
1385 | get_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 | |||
1396 | void | ||
1397 | load_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 | |||
1432 | void | ||
1433 | save_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 | |||
1469 | void | ||
1470 | remove_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 | |||
1487 | static void | ||
1488 | remove_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 | |||
53 | struct GNUNET_MESSENGER_SrvTunnel; | ||
54 | struct GNUNET_MESSENGER_MemberSession; | ||
55 | |||
56 | struct 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 | */ | ||
87 | struct GNUNET_MESSENGER_SrvRoom* | ||
88 | create_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 | */ | ||
100 | void | ||
101 | destroy_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 | */ | ||
110 | struct GNUNET_MESSENGER_PeerStore* | ||
111 | get_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 | */ | ||
119 | struct GNUNET_MESSENGER_MemberStore* | ||
120 | get_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 | */ | ||
128 | struct GNUNET_MESSENGER_MessageStore* | ||
129 | get_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 | */ | ||
137 | struct GNUNET_MESSENGER_OperationStore* | ||
138 | get_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 | */ | ||
152 | enum GNUNET_GenericReturnValue | ||
153 | open_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 | */ | ||
166 | enum GNUNET_GenericReturnValue | ||
167 | enter_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 | */ | ||
188 | struct GNUNET_MQ_Envelope* | ||
189 | pack_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 | */ | ||
210 | enum GNUNET_GenericReturnValue | ||
211 | send_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 | */ | ||
223 | void | ||
224 | forward_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 | */ | ||
237 | void | ||
238 | check_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 | */ | ||
248 | void | ||
249 | merge_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 | */ | ||
262 | enum GNUNET_GenericReturnValue | ||
263 | delete_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 | */ | ||
274 | struct GNUNET_CADET_Handle* | ||
275 | get_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 | */ | ||
283 | const struct GNUNET_HashCode* | ||
284 | get_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 | */ | ||
294 | const struct GNUNET_MESSENGER_SrvTunnel* | ||
295 | get_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 | */ | ||
306 | typedef 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 | */ | ||
328 | enum GNUNET_GenericReturnValue | ||
329 | request_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 | */ | ||
344 | void | ||
345 | solve_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 | */ | ||
357 | void | ||
358 | rebuild_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 | */ | ||
366 | uint32_t | ||
367 | get_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 | */ | ||
375 | uint32_t | ||
376 | get_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 | */ | ||
384 | void | ||
385 | load_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 | */ | ||
393 | void | ||
394 | save_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 | */ | ||
401 | void | ||
402 | remove_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 | |||
33 | struct 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 | |||
34 | static void | ||
35 | callback_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 | |||
48 | struct GNUNET_MESSENGER_Service* | ||
49 | create_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 | |||
116 | static enum GNUNET_GenericReturnValue | ||
117 | iterate_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 | |||
127 | void | ||
128 | destroy_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 | |||
174 | struct GNUNET_MESSENGER_ContactStore* | ||
175 | get_service_contact_store (struct GNUNET_MESSENGER_Service *service) | ||
176 | { | ||
177 | GNUNET_assert (service); | ||
178 | |||
179 | return &(service->contact_store); | ||
180 | } | ||
181 | |||
182 | |||
183 | struct GNUNET_MESSENGER_SrvHandle* | ||
184 | add_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 | |||
200 | void | ||
201 | remove_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 | |||
214 | enum GNUNET_GenericReturnValue | ||
215 | get_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 | |||
240 | struct GNUNET_MESSENGER_SrvRoom* | ||
241 | get_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 | |||
250 | struct HandleInitializationClosure | ||
251 | { | ||
252 | struct GNUNET_MESSENGER_SrvHandle *handle; | ||
253 | struct GNUNET_MESSENGER_SrvRoom *room; | ||
254 | const struct GNUNET_CRYPTO_PublicKey *pubkey; | ||
255 | }; | ||
256 | |||
257 | static enum GNUNET_GenericReturnValue | ||
258 | find_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 | |||
290 | static void | ||
291 | initialize_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 | |||
316 | enum GNUNET_GenericReturnValue | ||
317 | open_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 | |||
345 | enum GNUNET_GenericReturnValue | ||
346 | entry_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 | |||
384 | enum GNUNET_GenericReturnValue | ||
385 | close_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 | |||
439 | void | ||
440 | handle_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 | |||
38 | struct GNUNET_MESSENGER_SrvRoom; | ||
39 | |||
40 | struct 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 | */ | ||
70 | struct GNUNET_MESSENGER_Service* | ||
71 | create_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 | */ | ||
79 | void | ||
80 | destroy_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 | */ | ||
88 | struct GNUNET_MESSENGER_ContactStore* | ||
89 | get_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 | */ | ||
98 | struct GNUNET_MESSENGER_SrvHandle* | ||
99 | add_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 | */ | ||
108 | void | ||
109 | remove_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 | */ | ||
120 | enum GNUNET_GenericReturnValue | ||
121 | get_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 | */ | ||
132 | struct GNUNET_MESSENGER_SrvRoom* | ||
133 | get_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 | */ | ||
145 | enum GNUNET_GenericReturnValue | ||
146 | open_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 | */ | ||
163 | enum GNUNET_GenericReturnValue | ||
164 | entry_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 | */ | ||
182 | enum GNUNET_GenericReturnValue | ||
183 | close_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 | */ | ||
198 | void | ||
199 | handle_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 | |||
36 | struct GNUNET_MESSENGER_SrvTunnel* | ||
37 | create_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 | |||
60 | void | ||
61 | destroy_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 | |||
79 | void | ||
80 | bind_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 | |||
92 | extern void | ||
93 | callback_room_disconnect (struct GNUNET_MESSENGER_SrvRoom *room, | ||
94 | void *cls); | ||
95 | |||
96 | void | ||
97 | callback_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 | |||
111 | extern enum GNUNET_GenericReturnValue | ||
112 | callback_verify_room_message (struct GNUNET_MESSENGER_SrvRoom *room, | ||
113 | void *cls, | ||
114 | struct GNUNET_MESSENGER_Message *message, | ||
115 | struct GNUNET_HashCode *hash); | ||
116 | |||
117 | enum GNUNET_GenericReturnValue | ||
118 | check_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 | |||
155 | extern enum GNUNET_GenericReturnValue | ||
156 | update_room_message (struct GNUNET_MESSENGER_SrvRoom *room, | ||
157 | struct GNUNET_MESSENGER_Message *message, | ||
158 | const struct GNUNET_HashCode *hash); | ||
159 | |||
160 | extern void | ||
161 | callback_room_handle_message (struct GNUNET_MESSENGER_SrvRoom *room, | ||
162 | const struct GNUNET_MESSENGER_Message *message, | ||
163 | const struct GNUNET_HashCode *hash); | ||
164 | |||
165 | static void | ||
166 | update_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 | |||
188 | void | ||
189 | handle_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 | |||
247 | receive_done: | ||
248 | cleanup_message (&message); | ||
249 | |||
250 | GNUNET_CADET_receive_done (tunnel->channel); | ||
251 | } | ||
252 | |||
253 | |||
254 | enum GNUNET_GenericReturnValue | ||
255 | connect_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 | |||
285 | void | ||
286 | disconnect_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 | |||
299 | enum GNUNET_GenericReturnValue | ||
300 | is_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 | |||
308 | struct GNUNET_MESSENGER_MessageSent | ||
309 | { | ||
310 | struct GNUNET_MESSENGER_SrvTunnel *tunnel; | ||
311 | struct GNUNET_HashCode hash; | ||
312 | }; | ||
313 | |||
314 | static void | ||
315 | callback_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 | |||
326 | void | ||
327 | send_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 | |||
347 | enum GNUNET_GenericReturnValue | ||
348 | send_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 | |||
376 | void | ||
377 | forward_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 | |||
400 | const struct GNUNET_HashCode* | ||
401 | get_tunnel_peer_message (const struct GNUNET_MESSENGER_SrvTunnel *tunnel) | ||
402 | { | ||
403 | GNUNET_assert (tunnel); | ||
404 | |||
405 | return tunnel->peer_message; | ||
406 | } | ||
407 | |||
408 | |||
409 | void | ||
410 | get_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 | |||
419 | uint32_t | ||
420 | get_tunnel_messenger_version (const struct GNUNET_MESSENGER_SrvTunnel *tunnel) | ||
421 | { | ||
422 | GNUNET_assert (tunnel); | ||
423 | |||
424 | return tunnel->messenger_version; | ||
425 | } | ||
426 | |||
427 | |||
428 | enum GNUNET_GenericReturnValue | ||
429 | update_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 | |||
35 | struct 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 | */ | ||
55 | struct GNUNET_MESSENGER_SrvTunnel* | ||
56 | create_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 | */ | ||
64 | void | ||
65 | destroy_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 | */ | ||
74 | void | ||
75 | bind_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 | */ | ||
85 | enum GNUNET_GenericReturnValue | ||
86 | connect_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 | */ | ||
94 | void | ||
95 | disconnect_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 | */ | ||
103 | enum GNUNET_GenericReturnValue | ||
104 | is_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 | */ | ||
114 | void | ||
115 | send_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 | */ | ||
129 | enum GNUNET_GenericReturnValue | ||
130 | send_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 | */ | ||
141 | void | ||
142 | forward_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 | */ | ||
154 | const struct GNUNET_HashCode* | ||
155 | get_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 | */ | ||
164 | void | ||
165 | get_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 | */ | ||
177 | uint32_t | ||
178 | get_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 | */ | ||
189 | enum GNUNET_GenericReturnValue | ||
190 | update_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 @@ | |||
1 | libgnunetmessenger_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 | |||
13 | gnunetservicemessenger_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 | |||
34 | configure_file(input : 'messenger.conf.in', | ||
35 | output : 'messenger.conf', | ||
36 | configuration : cdata, | ||
37 | install: true, | ||
38 | install_dir: pkgcfgdir) | ||
39 | |||
40 | |||
41 | if get_option('monolith') | ||
42 | foreach p : libgnunetmessenger_src + gnunetservicemessenger_src | ||
43 | gnunet_src += 'messenger/' + p | ||
44 | endforeach | ||
45 | endif | ||
46 | |||
47 | libgnunetmessenger = 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')) | ||
57 | libgnunetmessenger_dep = declare_dependency(link_with : libgnunetmessenger) | ||
58 | pkg.generate(libgnunetmessenger, url: 'https://www.gnunet.org', | ||
59 | description : 'Provides API to access the GNUnet Messenger subsystem') | ||
60 | |||
61 | executable ('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 | |||
34 | struct GNUNET_TESTING_Command | ||
35 | GNUNET_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 | |||
43 | struct GNUNET_TESTING_Command | ||
44 | GNUNET_MESSENGER_cmd_stop_service (const char *label, | ||
45 | const char *service_label); | ||
46 | |||
47 | struct GNUNET_TESTING_Command | ||
48 | GNUNET_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 | |||
100 | GNUNET_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 | |||
31 | struct GNUNET_MESSENGER_TestStage | ||
32 | GNUNET_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 | |||
41 | struct GNUNET_MESSENGER_TestStage | ||
42 | GNUNET_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 | |||
51 | struct GNUNET_MESSENGER_TestStage | ||
52 | GNUNET_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 | |||
61 | struct GNUNET_MESSENGER_TestStageTopology * | ||
62 | GNUNET_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 | |||
84 | void | ||
85 | GNUNET_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 | |||
94 | struct GNUNET_MESSENGER_RoomState * | ||
95 | GNUNET_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 | |||
107 | void | ||
108 | GNUNET_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 | |||
30 | enum 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 | |||
37 | struct GNUNET_MESSENGER_TestStage | ||
38 | { | ||
39 | unsigned int door_id; | ||
40 | enum GNUNET_MESSENGER_TestStageJoin join; | ||
41 | }; | ||
42 | |||
43 | struct GNUNET_MESSENGER_TestStage | ||
44 | GNUNET_MESSENGER_create_stage_skip (); | ||
45 | |||
46 | struct GNUNET_MESSENGER_TestStage | ||
47 | GNUNET_MESSENGER_create_stage_open_room (); | ||
48 | |||
49 | struct GNUNET_MESSENGER_TestStage | ||
50 | GNUNET_MESSENGER_create_stage_enter_room (unsigned int door_id); | ||
51 | |||
52 | struct GNUNET_MESSENGER_TestStageTopology | ||
53 | { | ||
54 | unsigned int peer_amount; | ||
55 | unsigned int stage_amount; | ||
56 | |||
57 | struct GNUNET_MESSENGER_TestStage *peer_stages; | ||
58 | }; | ||
59 | |||
60 | struct GNUNET_MESSENGER_TestStageTopology * | ||
61 | GNUNET_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 | |||
66 | void | ||
67 | GNUNET_MESSENGER_destroy_topo (struct | ||
68 | GNUNET_MESSENGER_TestStageTopology *topology); | ||
69 | |||
70 | struct GNUNET_MESSENGER_RoomState | ||
71 | { | ||
72 | struct GNUNET_CONTAINER_MultiPeerMap *doors; | ||
73 | |||
74 | unsigned int required_doors; | ||
75 | }; | ||
76 | |||
77 | struct GNUNET_MESSENGER_RoomState * | ||
78 | GNUNET_MESSENGER_create_room_state (struct | ||
79 | GNUNET_MESSENGER_TestStageTopology *topology); | ||
80 | |||
81 | void | ||
82 | GNUNET_MESSENGER_destroy_room_state (struct | ||
83 | GNUNET_MESSENGER_RoomState *room_state); | ||
84 | |||
85 | struct 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] | ||
2 | START_ON_DEMAND = @START_ON_DEMAND@ | ||
3 | RUN_PER_USER = YES | ||
4 | @JAVAPORT@PORT = 2125 | ||
5 | HOSTNAME = localhost | ||
6 | BINARY = gnunet-service-messenger | ||
7 | ACCEPT_FROM = 127.0.0.1; | ||
8 | ACCEPT_FROM6 = ::1; | ||
9 | UNIXPATH = $GNUNET_USER_RUNTIME_DIR/gnunet-service-messenger.sock | ||
10 | UNIX_MATCH_UID = NO | ||
11 | UNIX_MATCH_GID = YES | ||
12 | |||
13 | # Directory to store messages and contacts | ||
14 | MESSENGER_DIR = $GNUNET_DATA_HOME/messenger/ | ||
15 | MESSENGER_AUTO_CONNECTING = YES | ||
16 | MESSENGER_AUTO_ROUTING = YES | ||
17 | MESSENGER_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 | |||
42 | const char* | ||
43 | GNUNET_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 | |||
91 | static enum GNUNET_GenericReturnValue | ||
92 | dequeue_messages_from_room (struct GNUNET_MESSENGER_Room *room); | ||
93 | |||
94 | static void | ||
95 | handle_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 | |||
118 | static void | ||
119 | handle_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 | |||
143 | static void | ||
144 | handle_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 | |||
163 | static void | ||
164 | handle_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 | |||
185 | static void | ||
186 | enqueue_message_to_room (struct GNUNET_MESSENGER_Room *room, | ||
187 | struct GNUNET_MESSENGER_Message *message, | ||
188 | struct GNUNET_MESSENGER_Message *transcript); | ||
189 | |||
190 | static void | ||
191 | handle_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 | |||
228 | static enum GNUNET_GenericReturnValue | ||
229 | check_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 | |||
266 | static void | ||
267 | handle_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 | |||
310 | skip_message: | ||
311 | cleanup_message (&message); | ||
312 | } | ||
313 | |||
314 | |||
315 | static void | ||
316 | handle_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 | |||
347 | static void | ||
348 | reconnect (struct GNUNET_MESSENGER_Handle *handle); | ||
349 | |||
350 | static void | ||
351 | send_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 | |||
381 | static void | ||
382 | send_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 | |||
414 | static void | ||
415 | send_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 | |||
434 | static void | ||
435 | send_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 | |||
456 | static enum GNUNET_GenericReturnValue | ||
457 | iterate_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 | |||
484 | static void | ||
485 | callback_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 | |||
501 | static enum GNUNET_GenericReturnValue | ||
502 | iterate_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 | |||
515 | static void | ||
516 | callback_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 | |||
538 | static void | ||
539 | reconnect (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 | |||
586 | struct GNUNET_MESSENGER_Handle* | ||
587 | GNUNET_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 | |||
622 | void | ||
623 | GNUNET_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 | |||
640 | static void | ||
641 | callback_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 | |||
652 | static void | ||
653 | send_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 | |||
700 | static void | ||
701 | enqueue_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 | |||
732 | static enum GNUNET_GenericReturnValue | ||
733 | dequeue_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 | |||
791 | const char* | ||
792 | GNUNET_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 | |||
801 | static enum GNUNET_GenericReturnValue | ||
802 | iterate_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 | |||
826 | enum GNUNET_GenericReturnValue | ||
827 | GNUNET_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 | |||
839 | static const struct GNUNET_CRYPTO_PublicKey* | ||
840 | get_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 | |||
849 | const struct GNUNET_CRYPTO_PublicKey* | ||
850 | GNUNET_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 | |||
859 | static enum GNUNET_GenericReturnValue | ||
860 | iterate_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 | |||
876 | enum GNUNET_GenericReturnValue | ||
877 | GNUNET_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 | |||
904 | struct GNUNET_MESSENGER_Room* | ||
905 | GNUNET_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 | |||
932 | struct GNUNET_MESSENGER_Room* | ||
933 | GNUNET_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 | |||
961 | void | ||
962 | GNUNET_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 | |||
976 | struct 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 | |||
984 | static enum GNUNET_GenericReturnValue | ||
985 | iterate_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 | |||
1010 | int | ||
1011 | GNUNET_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 | |||
1031 | const struct GNUNET_HashCode* | ||
1032 | GNUNET_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 | |||
1041 | const struct GNUNET_MESSENGER_Contact* | ||
1042 | GNUNET_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 | |||
1052 | const struct GNUNET_MESSENGER_Contact* | ||
1053 | GNUNET_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 | |||
1063 | const char* | ||
1064 | GNUNET_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 | |||
1074 | const struct GNUNET_CRYPTO_PublicKey* | ||
1075 | GNUNET_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 | |||
1085 | size_t | ||
1086 | GNUNET_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 | |||
1096 | static void | ||
1097 | send_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 | |||
1125 | skip_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 | |||
1146 | skip_encryption: | ||
1147 | enqueue_message_to_room (room, message, transcript); | ||
1148 | } | ||
1149 | |||
1150 | |||
1151 | void | ||
1152 | GNUNET_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 | |||
1195 | void | ||
1196 | delete_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 | |||
1214 | void | ||
1215 | GNUNET_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 | |||
1226 | const struct GNUNET_MESSENGER_Message* | ||
1227 | GNUNET_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 | |||
1254 | int | ||
1255 | GNUNET_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 | |||
33 | struct GNUNET_MESSENGER_JoinRoomState | ||
34 | { | ||
35 | char *service_label; | ||
36 | char *room_key; | ||
37 | |||
38 | struct GNUNET_MESSENGER_Room *room; | ||
39 | }; | ||
40 | |||
41 | static void | ||
42 | join_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 | |||
81 | skip_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; | ||
148 | TODO: sss->stage_index++; | ||
149 | |||
150 | GNUNET_free (door); | ||
151 | } | ||
152 | |||
153 | |||
154 | static void | ||
155 | join_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 | |||
165 | struct GNUNET_TESTING_Command | ||
166 | GNUNET_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 | |||
34 | static void | ||
35 | on_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 | |||
74 | static void | ||
75 | start_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 | |||
114 | static void | ||
115 | start_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 | |||
125 | static enum GNUNET_GenericReturnValue | ||
126 | start_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 | |||
145 | struct GNUNET_TESTING_Command | ||
146 | GNUNET_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 | |||
32 | struct GNUNET_MESSENGER_StopServiceState | ||
33 | { | ||
34 | char *service_label; | ||
35 | }; | ||
36 | |||
37 | static enum GNUNET_GenericReturnValue | ||
38 | cleanup_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 | |||
48 | static void | ||
49 | stop_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 | |||
71 | static void | ||
72 | stop_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 | |||
81 | struct GNUNET_TESTING_Command | ||
82 | GNUNET_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 | |||
28 | struct GNUNET_MESSENGER_Contact* | ||
29 | create_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 | |||
47 | void | ||
48 | destroy_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 | |||
59 | const char* | ||
60 | get_contact_name (const struct GNUNET_MESSENGER_Contact *contact) | ||
61 | { | ||
62 | GNUNET_assert (contact); | ||
63 | |||
64 | return contact->name; | ||
65 | } | ||
66 | |||
67 | |||
68 | void | ||
69 | set_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 | |||
81 | const struct GNUNET_CRYPTO_PublicKey* | ||
82 | get_contact_key (const struct GNUNET_MESSENGER_Contact *contact) | ||
83 | { | ||
84 | GNUNET_assert (contact); | ||
85 | |||
86 | return &(contact->public_key); | ||
87 | } | ||
88 | |||
89 | |||
90 | void | ||
91 | increase_contact_rc (struct GNUNET_MESSENGER_Contact *contact) | ||
92 | { | ||
93 | GNUNET_assert (contact); | ||
94 | |||
95 | contact->rc++; | ||
96 | } | ||
97 | |||
98 | |||
99 | enum GNUNET_GenericReturnValue | ||
100 | decrease_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 | |||
111 | size_t | ||
112 | get_contact_id (const struct GNUNET_MESSENGER_Contact *contact) | ||
113 | { | ||
114 | GNUNET_assert (contact); | ||
115 | |||
116 | return contact->id; | ||
117 | } | ||
118 | |||
119 | |||
120 | void | ||
121 | get_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 | |||
31 | struct 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 | */ | ||
47 | struct GNUNET_MESSENGER_Contact* | ||
48 | create_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 | */ | ||
56 | void | ||
57 | destroy_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 | */ | ||
65 | const char* | ||
66 | get_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 | */ | ||
74 | void | ||
75 | set_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 | */ | ||
84 | const struct GNUNET_CRYPTO_PublicKey* | ||
85 | get_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 | */ | ||
92 | void | ||
93 | increase_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 | */ | ||
102 | enum GNUNET_GenericReturnValue | ||
103 | decrease_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 | */ | ||
111 | size_t | ||
112 | get_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 | */ | ||
121 | void | ||
122 | get_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 | |||
32 | void | ||
33 | init_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 | |||
44 | static enum GNUNET_GenericReturnValue | ||
45 | iterate_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 | |||
55 | void | ||
56 | clear_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 | |||
72 | static struct GNUNET_CONTAINER_MultiHashMap* | ||
73 | select_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 | |||
93 | struct GNUNET_MESSENGER_Contact* | ||
94 | get_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 | |||
111 | struct GNUNET_MESSENGER_Contact* | ||
112 | get_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 | |||
154 | void | ||
155 | update_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 | |||
194 | void | ||
195 | remove_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 | |||
31 | struct GNUNET_MESSENGER_Contact; | ||
32 | |||
33 | struct 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 | */ | ||
46 | void | ||
47 | init_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 | */ | ||
54 | void | ||
55 | clear_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 | */ | ||
69 | struct GNUNET_MESSENGER_Contact* | ||
70 | get_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 | */ | ||
89 | struct GNUNET_MESSENGER_Contact* | ||
90 | get_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 | */ | ||
106 | void | ||
107 | update_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 | */ | ||
121 | void | ||
122 | remove_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 | |||
31 | struct GNUNET_MESSENGER_Handle* | ||
32 | create_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 | |||
62 | static enum GNUNET_GenericReturnValue | ||
63 | iterate_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 | |||
75 | void | ||
76 | destroy_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 | |||
109 | void | ||
110 | set_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 | |||
122 | const char* | ||
123 | get_handle_name (const struct GNUNET_MESSENGER_Handle *handle) | ||
124 | { | ||
125 | GNUNET_assert (handle); | ||
126 | |||
127 | return handle->name; | ||
128 | } | ||
129 | |||
130 | |||
131 | void | ||
132 | set_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 | |||
161 | const struct GNUNET_CRYPTO_PrivateKey* | ||
162 | get_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 | |||
173 | const struct GNUNET_CRYPTO_PublicKey* | ||
174 | get_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 | |||
185 | struct GNUNET_MESSENGER_ContactStore* | ||
186 | get_handle_contact_store (struct GNUNET_MESSENGER_Handle *handle) | ||
187 | { | ||
188 | GNUNET_assert (handle); | ||
189 | |||
190 | return &(handle->contact_store); | ||
191 | } | ||
192 | |||
193 | |||
194 | struct GNUNET_MESSENGER_Contact* | ||
195 | get_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 | |||
219 | void | ||
220 | open_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 | |||
233 | void | ||
234 | entry_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 | |||
248 | void | ||
249 | close_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 | |||
263 | struct GNUNET_MESSENGER_Room* | ||
264 | get_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 | |||
35 | struct 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 | */ | ||
65 | struct GNUNET_MESSENGER_Handle* | ||
66 | create_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 | */ | ||
75 | void | ||
76 | destroy_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 | */ | ||
84 | void | ||
85 | set_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 | */ | ||
94 | const char* | ||
95 | get_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 | */ | ||
103 | void | ||
104 | set_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 | */ | ||
113 | const struct GNUNET_CRYPTO_PrivateKey* | ||
114 | get_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 | */ | ||
122 | const struct GNUNET_CRYPTO_PublicKey* | ||
123 | get_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 | */ | ||
131 | struct GNUNET_MESSENGER_ContactStore* | ||
132 | get_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 | */ | ||
142 | struct GNUNET_MESSENGER_Contact* | ||
143 | get_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 | */ | ||
152 | void | ||
153 | open_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 | */ | ||
164 | void | ||
165 | entry_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 | */ | ||
175 | void | ||
176 | close_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 | */ | ||
186 | struct GNUNET_MESSENGER_Room* | ||
187 | get_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 | |||
28 | void | ||
29 | init_list_tunnels (struct GNUNET_MESSENGER_ListTunnels *tunnels) | ||
30 | { | ||
31 | GNUNET_assert (tunnels); | ||
32 | |||
33 | tunnels->head = NULL; | ||
34 | tunnels->tail = NULL; | ||
35 | } | ||
36 | |||
37 | |||
38 | void | ||
39 | clear_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 | |||
52 | static int | ||
53 | compare_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 | |||
66 | void | ||
67 | add_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 | |||
88 | struct GNUNET_MESSENGER_ListTunnel* | ||
89 | find_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 | |||
116 | struct GNUNET_MESSENGER_ListTunnel* | ||
117 | find_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 | |||
137 | enum GNUNET_GenericReturnValue | ||
138 | verify_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 | |||
163 | void | ||
164 | update_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 | |||
191 | enum GNUNET_GenericReturnValue | ||
192 | contains_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 | |||
202 | struct GNUNET_MESSENGER_ListTunnel* | ||
203 | remove_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 | |||
223 | void | ||
224 | load_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 | |||
264 | void | ||
265 | save_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 | |||
32 | struct 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 | |||
43 | struct 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 | */ | ||
54 | void | ||
55 | init_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 | */ | ||
62 | void | ||
63 | clear_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 | */ | ||
74 | void | ||
75 | add_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 | */ | ||
94 | struct GNUNET_MESSENGER_ListTunnel* | ||
95 | find_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 | */ | ||
108 | struct GNUNET_MESSENGER_ListTunnel* | ||
109 | find_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 | */ | ||
121 | enum GNUNET_GenericReturnValue | ||
122 | verify_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 | */ | ||
138 | void | ||
139 | update_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 | */ | ||
151 | enum GNUNET_GenericReturnValue | ||
152 | contains_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 | */ | ||
163 | struct GNUNET_MESSENGER_ListTunnel* | ||
164 | remove_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 | */ | ||
173 | void | ||
174 | load_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 | */ | ||
183 | void | ||
184 | save_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 | |||
32 | struct GNUNET_MESSENGER_MessageSignature | ||
33 | { | ||
34 | struct GNUNET_CRYPTO_EccSignaturePurpose purpose; | ||
35 | struct GNUNET_HashCode hash GNUNET_PACKED; | ||
36 | }; | ||
37 | |||
38 | struct GNUNET_MESSENGER_ShortMessage | ||
39 | { | ||
40 | enum GNUNET_MESSENGER_MessageKind kind; | ||
41 | struct GNUNET_MESSENGER_MessageBody body; | ||
42 | }; | ||
43 | |||
44 | struct GNUNET_MESSENGER_Message* | ||
45 | create_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 | |||
85 | struct GNUNET_MESSENGER_Message* | ||
86 | copy_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 | |||
144 | void | ||
145 | copy_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 | |||
159 | static void | ||
160 | destroy_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 | |||
197 | void | ||
198 | cleanup_message (struct GNUNET_MESSENGER_Message *message) | ||
199 | { | ||
200 | GNUNET_assert (message); | ||
201 | |||
202 | destroy_message_body (message->header.kind, &(message->body)); | ||
203 | } | ||
204 | |||
205 | |||
206 | void | ||
207 | destroy_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 | |||
217 | enum GNUNET_GenericReturnValue | ||
218 | is_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 | |||
233 | static void | ||
234 | fold_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 | |||
244 | static void | ||
245 | unfold_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 | |||
259 | static uint16_t | ||
260 | get_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 | |||
324 | typedef uint32_t kind_t; | ||
325 | |||
326 | uint16_t | ||
327 | get_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 | |||
345 | static uint16_t | ||
346 | get_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 | |||
389 | uint16_t | ||
390 | get_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 | |||
408 | static uint16_t | ||
409 | get_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 | |||
423 | static uint16_t | ||
424 | calc_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 | |||
444 | static uint16_t | ||
445 | calc_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 | |||
502 | static void | ||
503 | encode_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 | |||
626 | void | ||
627 | encode_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 | |||
656 | static void | ||
657 | encode_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 | |||
706 | static uint16_t | ||
707 | decode_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 | |||
831 | enum GNUNET_GenericReturnValue | ||
832 | decode_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 | |||
893 | static enum GNUNET_GenericReturnValue | ||
894 | decode_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 | |||
934 | void | ||
935 | hash_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 | |||
950 | void | ||
951 | sign_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 | |||
977 | void | ||
978 | sign_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 | |||
1006 | enum GNUNET_GenericReturnValue | ||
1007 | verify_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 | |||
1029 | enum GNUNET_GenericReturnValue | ||
1030 | verify_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 | |||
1053 | enum GNUNET_GenericReturnValue | ||
1054 | encrypt_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 | |||
1098 | enum GNUNET_GenericReturnValue | ||
1099 | decrypt_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 | |||
1146 | struct GNUNET_MESSENGER_Message* | ||
1147 | transcribe_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 | |||
1184 | enum GNUNET_GenericReturnValue | ||
1185 | read_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 | |||
1210 | struct GNUNET_MQ_Envelope* | ||
1211 | pack_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 | |||
1262 | enum GNUNET_GenericReturnValue | ||
1263 | is_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 | |||
1279 | enum GNUNET_GenericReturnValue | ||
1280 | is_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 | |||
1331 | enum GNUNET_GenericReturnValue | ||
1332 | filter_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 | */ | ||
47 | struct GNUNET_MESSENGER_Message* | ||
48 | create_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 | */ | ||
56 | struct GNUNET_MESSENGER_Message* | ||
57 | copy_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 | */ | ||
66 | void | ||
67 | copy_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 | */ | ||
75 | void | ||
76 | cleanup_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 | */ | ||
83 | void | ||
84 | destroy_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 | */ | ||
92 | enum GNUNET_GenericReturnValue | ||
93 | is_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 | */ | ||
102 | uint16_t | ||
103 | get_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 | */ | ||
113 | uint16_t | ||
114 | get_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 | */ | ||
125 | void | ||
126 | encode_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 | */ | ||
146 | enum GNUNET_GenericReturnValue | ||
147 | decode_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 | */ | ||
162 | void | ||
163 | hash_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 | */ | ||
178 | void | ||
179 | sign_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 | */ | ||
195 | void | ||
196 | sign_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 | */ | ||
212 | enum GNUNET_GenericReturnValue | ||
213 | verify_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 | */ | ||
227 | enum GNUNET_GenericReturnValue | ||
228 | verify_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 | */ | ||
241 | enum GNUNET_GenericReturnValue | ||
242 | encrypt_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 | */ | ||
254 | enum GNUNET_GenericReturnValue | ||
255 | decrypt_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 | */ | ||
266 | struct GNUNET_MESSENGER_Message* | ||
267 | transcribe_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 | */ | ||
278 | enum GNUNET_GenericReturnValue | ||
279 | read_transcript_message (struct GNUNET_MESSENGER_Message *message); | ||
280 | |||
281 | typedef 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 | |||
289 | enum 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 | */ | ||
308 | struct GNUNET_MQ_Envelope* | ||
309 | pack_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 | */ | ||
323 | enum GNUNET_GenericReturnValue | ||
324 | is_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 | */ | ||
337 | enum GNUNET_GenericReturnValue | ||
338 | is_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 | */ | ||
348 | enum GNUNET_GenericReturnValue | ||
349 | filter_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 | |||
37 | struct GNUNET_MESSENGER_MessageControl* | ||
38 | create_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 | |||
58 | void | ||
59 | destroy_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 | |||
84 | static void | ||
85 | enqueue_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 | |||
122 | static void | ||
123 | handle_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 | |||
140 | static void | ||
141 | task_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 | |||
181 | static enum GNUNET_GenericReturnValue | ||
182 | iterate_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 | |||
198 | void | ||
199 | process_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 | |||
33 | struct GNUNET_MESSENGER_Message; | ||
34 | struct GNUNET_MESSENGER_MessageControl; | ||
35 | |||
36 | struct 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 | |||
52 | struct GNUNET_MESSENGER_Room; | ||
53 | |||
54 | struct 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 | */ | ||
71 | struct GNUNET_MESSENGER_MessageControl* | ||
72 | create_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 | */ | ||
79 | void | ||
80 | destroy_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 | */ | ||
97 | void | ||
98 | process_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 | |||
30 | struct GNUNET_MESSENGER_Message* | ||
31 | create_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 | |||
47 | struct GNUNET_MESSENGER_Message* | ||
48 | create_message_leave () | ||
49 | { | ||
50 | return create_message (GNUNET_MESSENGER_KIND_LEAVE); | ||
51 | } | ||
52 | |||
53 | |||
54 | struct GNUNET_MESSENGER_Message* | ||
55 | create_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 | |||
71 | struct GNUNET_MESSENGER_Message* | ||
72 | create_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 | |||
88 | struct GNUNET_MESSENGER_Message* | ||
89 | create_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 | |||
108 | struct GNUNET_MESSENGER_Message* | ||
109 | create_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 | |||
133 | struct GNUNET_MESSENGER_Message* | ||
134 | create_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 | |||
156 | struct GNUNET_MESSENGER_Message* | ||
157 | create_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 | |||
173 | struct GNUNET_MESSENGER_Message* | ||
174 | create_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 | |||
194 | struct GNUNET_MESSENGER_Message* | ||
195 | create_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 | */ | ||
40 | struct GNUNET_MESSENGER_Message* | ||
41 | create_message_join (const struct GNUNET_CRYPTO_PrivateKey *key); | ||
42 | |||
43 | /** | ||
44 | * Creates and allocates a new leave message. | ||
45 | * | ||
46 | * @return New message | ||
47 | */ | ||
48 | struct GNUNET_MESSENGER_Message* | ||
49 | create_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 | */ | ||
58 | struct GNUNET_MESSENGER_Message* | ||
59 | create_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 | */ | ||
68 | struct GNUNET_MESSENGER_Message* | ||
69 | create_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 | */ | ||
78 | struct GNUNET_MESSENGER_Message* | ||
79 | create_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 | */ | ||
88 | struct GNUNET_MESSENGER_Message* | ||
89 | create_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 | */ | ||
100 | struct GNUNET_MESSENGER_Message* | ||
101 | create_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 | */ | ||
111 | struct GNUNET_MESSENGER_Message* | ||
112 | create_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 | */ | ||
123 | struct GNUNET_MESSENGER_Message* | ||
124 | create_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 | */ | ||
135 | struct GNUNET_MESSENGER_Message* | ||
136 | create_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 | |||
31 | void | ||
32 | init_queue_messages (struct GNUNET_MESSENGER_QueueMessages *messages) | ||
33 | { | ||
34 | GNUNET_assert (messages); | ||
35 | |||
36 | messages->head = NULL; | ||
37 | messages->tail = NULL; | ||
38 | } | ||
39 | |||
40 | |||
41 | void | ||
42 | clear_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 | |||
66 | void | ||
67 | enqueue_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 | |||
102 | struct GNUNET_MESSENGER_Message* | ||
103 | dequeue_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 | |||
31 | struct 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 | |||
42 | struct 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 | */ | ||
53 | void | ||
54 | init_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 | */ | ||
61 | void | ||
62 | clear_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 | */ | ||
74 | void | ||
75 | enqueue_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 | */ | ||
89 | struct GNUNET_MESSENGER_Message* | ||
90 | dequeue_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 | |||
36 | struct GNUNET_MESSENGER_Room* | ||
37 | create_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 | |||
70 | static enum GNUNET_GenericReturnValue | ||
71 | iterate_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 | |||
84 | static enum GNUNET_GenericReturnValue | ||
85 | iterate_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 | |||
95 | void | ||
96 | destroy_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 | |||
131 | enum GNUNET_GenericReturnValue | ||
132 | is_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 | |||
146 | struct GNUNET_MESSENGER_Handle* | ||
147 | get_room_handle (struct GNUNET_MESSENGER_Room *room) | ||
148 | { | ||
149 | GNUNET_assert (room); | ||
150 | |||
151 | return room->handle; | ||
152 | } | ||
153 | |||
154 | |||
155 | const struct GNUNET_ShortHashCode* | ||
156 | get_room_sender_id (const struct GNUNET_MESSENGER_Room *room) | ||
157 | { | ||
158 | GNUNET_assert (room); | ||
159 | |||
160 | return room->sender_id; | ||
161 | } | ||
162 | |||
163 | |||
164 | void | ||
165 | set_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 | |||
189 | const struct GNUNET_MESSENGER_Message* | ||
190 | get_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 | |||
206 | struct GNUNET_MESSENGER_Contact* | ||
207 | get_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 | |||
223 | struct GNUNET_MESSENGER_Contact* | ||
224 | get_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 | |||
240 | void | ||
241 | callback_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 | |||
270 | static void | ||
271 | handle_message (struct GNUNET_MESSENGER_Room *room, | ||
272 | const struct GNUNET_HashCode *hash, | ||
273 | struct GNUNET_MESSENGER_RoomMessageEntry *entry); | ||
274 | |||
275 | |||
276 | void | ||
277 | handle_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 | |||
308 | static void | ||
309 | handle_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 | |||
328 | static void | ||
329 | handle_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 | |||
355 | static void | ||
356 | handle_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 | |||
377 | static void | ||
378 | handle_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 | |||
414 | static void | ||
415 | handle_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 | |||
432 | static void | ||
433 | handle_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 | |||
467 | extern void | ||
468 | delete_message_in_room (struct GNUNET_MESSENGER_Room *room, | ||
469 | const struct GNUNET_HashCode *hash, | ||
470 | const struct GNUNET_TIME_Relative delay); | ||
471 | |||
472 | |||
473 | static void | ||
474 | handle_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 | |||
522 | static void | ||
523 | handle_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 | |||
565 | read_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 | |||
604 | static void | ||
605 | handle_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 | |||
649 | void | ||
650 | handle_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 | |||
684 | update_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 | |||
704 | void | ||
705 | update_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 | |||
714 | struct GNUNET_MESSENGER_MemberCall | ||
715 | { | ||
716 | struct GNUNET_MESSENGER_Room *room; | ||
717 | GNUNET_MESSENGER_MemberCallback callback; | ||
718 | void *cls; | ||
719 | }; | ||
720 | |||
721 | static enum GNUNET_GenericReturnValue | ||
722 | iterate_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 | |||
733 | int | ||
734 | iterate_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 | |||
757 | struct GNUNET_MESSENGER_MemberFind | ||
758 | { | ||
759 | const struct GNUNET_MESSENGER_Contact *contact; | ||
760 | enum GNUNET_GenericReturnValue result; | ||
761 | }; | ||
762 | |||
763 | static enum GNUNET_GenericReturnValue | ||
764 | iterate_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 | |||
781 | enum GNUNET_GenericReturnValue | ||
782 | find_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 | |||
799 | static enum GNUNET_GenericReturnValue | ||
800 | find_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 | |||
817 | void | ||
818 | link_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 | |||
844 | struct GNUNET_MESSENGER_RoomLinkDeletionInfo | ||
845 | { | ||
846 | struct GNUNET_MESSENGER_Room *room; | ||
847 | struct GNUNET_TIME_Relative delay; | ||
848 | GNUNET_MESSENGER_RoomLinkDeletion deletion; | ||
849 | }; | ||
850 | |||
851 | |||
852 | static enum GNUNET_GenericReturnValue | ||
853 | clear_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 | |||
868 | static enum GNUNET_GenericReturnValue | ||
869 | delete_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 | |||
897 | void | ||
898 | link_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 | |||
41 | struct 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 | |||
51 | struct 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 | |||
75 | typedef 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 | */ | ||
89 | struct GNUNET_MESSENGER_Room* | ||
90 | create_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 | */ | ||
98 | void | ||
99 | destroy_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 | */ | ||
107 | enum GNUNET_GenericReturnValue | ||
108 | is_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 | */ | ||
116 | struct GNUNET_MESSENGER_Handle* | ||
117 | get_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 | */ | ||
125 | const struct GNUNET_ShortHashCode* | ||
126 | get_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 | */ | ||
134 | void | ||
135 | set_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 | */ | ||
146 | const struct GNUNET_MESSENGER_Message* | ||
147 | get_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 | */ | ||
158 | struct GNUNET_MESSENGER_Contact* | ||
159 | get_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 | */ | ||
170 | struct GNUNET_MESSENGER_Contact* | ||
171 | get_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 | */ | ||
180 | void | ||
181 | callback_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 | */ | ||
197 | void | ||
198 | handle_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 | */ | ||
211 | void | ||
212 | update_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 | */ | ||
224 | int | ||
225 | iterate_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 | */ | ||
237 | enum GNUNET_GenericReturnValue | ||
238 | find_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 | */ | ||
250 | void | ||
251 | link_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 | */ | ||
264 | void | ||
265 | link_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 | |||
29 | GNUNET_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 | |||
31 | static void | ||
32 | callback_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 | |||
41 | void | ||
42 | delayed_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 | |||
52 | enum GNUNET_GenericReturnValue | ||
53 | generate_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 | |||
81 | const struct GNUNET_CRYPTO_PrivateKey* | ||
82 | get_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 | |||
89 | const struct GNUNET_CRYPTO_PublicKey* | ||
90 | get_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 | |||
105 | void | ||
106 | convert_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 | |||
124 | void | ||
125 | convert_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 | */ | ||
37 | void | ||
38 | delayed_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 | */ | ||
48 | enum GNUNET_GenericReturnValue | ||
49 | generate_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 | */ | ||
58 | const struct GNUNET_CRYPTO_PrivateKey* | ||
59 | get_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 | */ | ||
67 | const struct GNUNET_CRYPTO_PublicKey* | ||
68 | get_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 | */ | ||
80 | void | ||
81 | convert_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 | */ | ||
91 | void | ||
92 | convert_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 | |||
44 | static int status = 1; | ||
45 | |||
46 | static struct GNUNET_SCHEDULER_Task *die_task = NULL; | ||
47 | static struct GNUNET_SCHEDULER_Task *op_task = NULL; | ||
48 | static struct GNUNET_SCHEDULER_Task *it_task = NULL; | ||
49 | |||
50 | struct GNUNET_MESSENGER_Handle *messenger = NULL; | ||
51 | |||
52 | static struct GNUNET_CRYPTO_PrivateKey identity; | ||
53 | |||
54 | static void | ||
55 | end (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 | |||
82 | static void | ||
83 | end_badly (void *cls) | ||
84 | { | ||
85 | fprintf (stderr, "Testcase failed (timeout).\n"); | ||
86 | |||
87 | end (NULL); | ||
88 | status = 1; | ||
89 | } | ||
90 | |||
91 | |||
92 | static void | ||
93 | end_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 | |||
109 | static 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 | */ | ||
117 | static void | ||
118 | on_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 | */ | ||
181 | static void | ||
182 | run (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 | */ | ||
209 | int | ||
210 | main (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 | |||
42 | static int status = 1; | ||
43 | |||
44 | static struct GNUNET_SCHEDULER_Task *die_task = NULL; | ||
45 | static struct GNUNET_SCHEDULER_Task *op_task = NULL; | ||
46 | static struct GNUNET_SCHEDULER_Task *it_task = NULL; | ||
47 | |||
48 | struct GNUNET_MESSENGER_Handle *messenger = NULL; | ||
49 | |||
50 | static void | ||
51 | end (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 | |||
77 | static void | ||
78 | end_badly (void *cls) | ||
79 | { | ||
80 | fprintf (stderr, "Testcase failed (timeout).\n"); | ||
81 | |||
82 | end (NULL); | ||
83 | status = 1; | ||
84 | } | ||
85 | |||
86 | |||
87 | static void | ||
88 | end_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 | */ | ||
110 | static void | ||
111 | on_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 | */ | ||
158 | static void | ||
159 | run (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 | */ | ||
181 | int | ||
182 | main (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] | ||
5 | HOSTNAME = localhost | ||
6 | OVERLAY_TOPOLOGY = CLIQUE | ||
7 | |||
8 | [arm] | ||
9 | GLOBAL_POSTFIX = -l $GNUNET_CACHE_HOME/{}-logs -L verbose | ||
10 | |||
11 | [transport] | ||
12 | IMMEDIATE_START = YES | ||
13 | |||
14 | [core] | ||
15 | START_ON_DEMAND = YES | ||
16 | IMMEDIATE_START = YES | ||
17 | USE_EPHEMERAL_KEYS = NO | ||
18 | |||
19 | [PATHS] | ||
20 | GNUNET_TEST_HOME = $GNUNET_TMP/test-messenger-api/ | ||
21 | |||
22 | [peerinfo] | ||
23 | NO_IO = YES | ||
24 | |||
25 | [cadet] | ||
26 | START_ON_DEMAND = YES | ||
27 | REFRESH_CONNECTION_TIME = 1 s | ||
28 | ID_ANNOUNCE_TIME = 5 s | ||
29 | CONNECT_TIMEOUT = 30 s | ||
30 | DEFAULT_TTL = 16 | ||
31 | DHT_REPLICATION_LEVEL = 10 | ||
32 | MAX_TUNNELS = 10 | ||
33 | MAX_CONNECTIONS = 10 | ||
34 | MAX_MSGS_QUEUE = 20 | ||
35 | DISABLE_TRY_CONNECT = YES | ||
36 | REKEY_PERIOD = 2 s | ||
37 | |||
38 | [identity] | ||
39 | START_ON_DEMAND = YES | ||
40 | |||
41 | [messenger] | ||
42 | START_ON_DEMAND = YES | ||
43 | MESSENGER_AUTO_CONNECTING = NO | ||
44 | MESSENGER_AUTO_ROUTING = NO | ||
45 | |||
46 | [nat] | ||
47 | ENABLE_UPNP = NO | ||
48 | RETURN_LOCAL_ADDRESSES = YES | ||
49 | IMMEDIATE_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 | |||
52 | static struct GNUNET_TESTING_Command block_script; | ||
53 | |||
54 | static struct GNUNET_TESTING_Command connect_peers; | ||
55 | |||
56 | static struct GNUNET_TESTING_Command local_prepared; | ||
57 | |||
58 | static struct GNUNET_TESTING_Command start_peer; | ||
59 | |||
60 | static struct GNUNET_TESTING_Command start_service; | ||
61 | |||
62 | static struct GNUNET_TESTING_Interpreter *is; | ||
63 | |||
64 | struct 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 | |||
97 | struct 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 | |||
116 | struct GNUNET_TESTING_BarrierList* | ||
117 | get_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 | */ | ||
146 | static void | ||
147 | handle_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 | |||
165 | static void | ||
166 | child_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 | */ | ||
191 | static struct GNUNET_TESTING_Interpreter * | ||
192 | start_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 | */ | ||
368 | void * | ||
369 | libgnunet_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 | */ | ||
390 | void * | ||
391 | libgnunet_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 | ||
2 | read -p "Test case configuration to use:" conf | ||
3 | if ! [ -d "/run/netns" ]; then | ||
4 | echo You have to create the directory /run/netns. | ||
5 | fi | ||
6 | if [ -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 | ||
11 | fi | ||
12 | START_WITH_CONFIG=/usr/local/lib/gnunet/libexec/test_testing_start_with_config | ||
13 | if [ ! -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 | ||
15 | fi | ||
16 | exec unshare -r -nmU bash -c "mount -t tmpfs --make-rshared tmpfs /run/netns; $START_WITH_CONFIG $conf" \ No newline at end of file | ||