aboutsummaryrefslogtreecommitdiff
path: root/src/service/messenger/gnunet-service-messenger_service.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/service/messenger/gnunet-service-messenger_service.c')
-rw-r--r--src/service/messenger/gnunet-service-messenger_service.c461
1 files changed, 461 insertions, 0 deletions
diff --git a/src/service/messenger/gnunet-service-messenger_service.c b/src/service/messenger/gnunet-service-messenger_service.c
new file mode 100644
index 000000000..11656d6b7
--- /dev/null
+++ b/src/service/messenger/gnunet-service-messenger_service.c
@@ -0,0 +1,461 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2024 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Tobias Frisch
22 * @file src/messenger/gnunet-service-messenger_service.c
23 * @brief GNUnet MESSENGER service
24 */
25
26#include "gnunet-service-messenger_service.h"
27
28#include "gnunet-service-messenger_message_kind.h"
29#include "gnunet-service-messenger_room.h"
30
31#include "gnunet_common.h"
32#include "messenger_api_util.h"
33
34static void
35callback_shutdown_service (void *cls)
36{
37 struct GNUNET_MESSENGER_Service *service = cls;
38
39 if (service)
40 {
41 service->shutdown = NULL;
42
43 destroy_service (service);
44 }
45}
46
47
48struct GNUNET_MESSENGER_Service*
49create_service (const struct GNUNET_CONFIGURATION_Handle *config,
50 struct GNUNET_SERVICE_Handle *service_handle)
51{
52 GNUNET_assert ((config) && (service_handle));
53
54 struct GNUNET_MESSENGER_Service *service = GNUNET_new (struct
55 GNUNET_MESSENGER_Service);
56
57 service->config = config;
58 service->service = service_handle;
59
60 service->shutdown = GNUNET_SCHEDULER_add_shutdown (&callback_shutdown_service,
61 service);
62
63 service->peer = NULL;
64 service->dir = NULL;
65
66 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (service->config,
67 GNUNET_MESSENGER_SERVICE_NAME,
68 "MESSENGER_DIR",
69 &(service->dir)))
70 {
71 if (service->dir)
72 GNUNET_free (service->dir);
73
74 service->dir = NULL;
75 }
76 else
77 {
78 if ((GNUNET_YES != GNUNET_DISK_directory_test (service->dir, GNUNET_YES)) &&
79 (GNUNET_OK
80 !=
81 GNUNET_DISK_directory_create (service->dir)))
82 {
83 GNUNET_free (service->dir);
84
85 service->dir = NULL;
86 }
87 }
88
89 service->auto_connecting = GNUNET_CONFIGURATION_get_value_yesno (
90 service->config,
91 GNUNET_MESSENGER_SERVICE_NAME,
92 "MESSENGER_AUTO_CONNECTING");
93
94 service->auto_routing = GNUNET_CONFIGURATION_get_value_yesno (service->config,
95 GNUNET_MESSENGER_SERVICE_NAME,
96 "MESSENGER_AUTO_ROUTING");
97
98 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (service->config,
99 GNUNET_MESSENGER_SERVICE_NAME,
100 "MESSENGER_MIN_ROUTERS",
101 &(service->min_routers)))
102 service->min_routers = 0;
103
104 service->cadet = GNUNET_CADET_connect (service->config);
105
106 init_list_handles (&(service->handles));
107
108 service->rooms = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
109
110 init_contact_store (get_service_contact_store (service));
111
112 return service;
113}
114
115
116static enum GNUNET_GenericReturnValue
117iterate_destroy_rooms (void *cls,
118 const struct GNUNET_HashCode *key,
119 void *value)
120{
121 struct GNUNET_MESSENGER_SrvRoom *room = value;
122 destroy_srv_room (room, GNUNET_NO);
123 return GNUNET_YES;
124}
125
126
127void
128destroy_service (struct GNUNET_MESSENGER_Service *service)
129{
130 GNUNET_assert (service);
131
132 if (service->shutdown)
133 {
134 GNUNET_SCHEDULER_cancel (service->shutdown);
135
136 service->shutdown = NULL;
137 }
138
139 clear_list_handles (&(service->handles));
140
141 GNUNET_CONTAINER_multihashmap_iterate (service->rooms, iterate_destroy_rooms,
142 NULL);
143 GNUNET_CONTAINER_multihashmap_destroy (service->rooms);
144
145 clear_contact_store (get_service_contact_store (service));
146
147 if (service->cadet)
148 {
149 GNUNET_CADET_disconnect (service->cadet);
150
151 service->cadet = NULL;
152 }
153
154 if (service->dir)
155 {
156 GNUNET_free (service->dir);
157
158 service->dir = NULL;
159 }
160
161 if (service->peer)
162 {
163 GNUNET_free (service->peer);
164
165 service->peer = NULL;
166 }
167
168 GNUNET_SERVICE_shutdown (service->service);
169
170 GNUNET_free (service);
171}
172
173
174struct GNUNET_MESSENGER_ContactStore*
175get_service_contact_store (struct GNUNET_MESSENGER_Service *service)
176{
177 GNUNET_assert (service);
178
179 return &(service->contact_store);
180}
181
182
183struct GNUNET_MESSENGER_SrvHandle*
184add_service_handle (struct GNUNET_MESSENGER_Service *service,
185 struct GNUNET_MQ_Handle *mq)
186{
187 GNUNET_assert ((service) && (mq));
188
189 struct GNUNET_MESSENGER_SrvHandle *handle = create_srv_handle (service, mq);
190
191 if (handle)
192 {
193 add_list_handle (&(service->handles), handle);
194 }
195
196 return handle;
197}
198
199
200void
201remove_service_handle (struct GNUNET_MESSENGER_Service *service,
202 struct GNUNET_MESSENGER_SrvHandle *handle)
203{
204 GNUNET_assert ((service) && (handle));
205
206 if (! handle)
207 return;
208
209 if (GNUNET_YES == remove_list_handle (&(service->handles), handle))
210 destroy_srv_handle (handle);
211}
212
213
214enum GNUNET_GenericReturnValue
215get_service_peer_identity (struct GNUNET_MESSENGER_Service *service,
216 struct GNUNET_PeerIdentity *peer)
217{
218 GNUNET_assert ((service) && (peer));
219
220 if (service->peer)
221 {
222 GNUNET_memcpy (peer, service->peer, sizeof(struct GNUNET_PeerIdentity));
223 return GNUNET_OK;
224 }
225
226 enum GNUNET_GenericReturnValue result;
227 result = GNUNET_CRYPTO_get_peer_identity (service->config, peer);
228
229 if (GNUNET_OK != result)
230 return result;
231
232 if (! service->peer)
233 service->peer = GNUNET_new (struct GNUNET_PeerIdentity);
234
235 GNUNET_memcpy (service->peer, peer, sizeof(struct GNUNET_PeerIdentity));
236 return result;
237}
238
239
240struct GNUNET_MESSENGER_SrvRoom*
241get_service_room (const struct GNUNET_MESSENGER_Service *service,
242 const struct GNUNET_HashCode *key)
243{
244 GNUNET_assert ((service) && (key));
245
246 return GNUNET_CONTAINER_multihashmap_get (service->rooms, key);
247}
248
249
250struct HandleInitializationClosure
251{
252 struct GNUNET_MESSENGER_SrvHandle *handle;
253 struct GNUNET_MESSENGER_SrvRoom *room;
254 const struct GNUNET_CRYPTO_PublicKey *pubkey;
255};
256
257static enum GNUNET_GenericReturnValue
258find_member_session_in_room (void *cls,
259 const struct GNUNET_CRYPTO_PublicKey *public_key,
260 struct GNUNET_MESSENGER_MemberSession *session)
261{
262 struct HandleInitializationClosure *init = cls;
263
264 if (! public_key)
265 return GNUNET_YES;
266
267 const struct GNUNET_CRYPTO_PublicKey *pubkey = get_srv_handle_key (
268 init->handle);
269
270 if (0 != GNUNET_memcmp (pubkey, public_key))
271 return GNUNET_YES;
272
273 const struct GNUNET_ShortHashCode *id = get_member_session_id (session);
274
275 if (! id)
276 {
277 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Initialitation: Missing member id!");
278 return GNUNET_NO;
279 }
280
281 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
282 "Initialitation: Matching member found (%s)!\n",
283 GNUNET_sh2s (id));
284
285 change_srv_handle_member_id (init->handle, get_srv_room_key (init->room), id);
286 return GNUNET_NO;
287}
288
289
290static void
291initialize_service_handle (struct GNUNET_MESSENGER_SrvHandle *handle,
292 struct GNUNET_MESSENGER_SrvRoom *room)
293{
294 GNUNET_assert ((handle) && (room));
295
296 struct GNUNET_MESSENGER_MemberStore *store = get_srv_room_member_store (room);
297 if (! store)
298 return;
299
300 const struct GNUNET_CRYPTO_PublicKey *pubkey = get_srv_handle_key (handle);
301 if ((! pubkey) || (0 == GNUNET_memcmp (pubkey, get_anonymous_public_key ())))
302 return;
303
304 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
305 "Initialize member id of handle via matching member in room!\n");
306
307 struct HandleInitializationClosure init;
308 init.handle = handle;
309 init.room = room;
310 init.pubkey = pubkey;
311
312 iterate_store_members (store, find_member_session_in_room, &init);
313}
314
315
316enum GNUNET_GenericReturnValue
317open_service_room (struct GNUNET_MESSENGER_Service *service,
318 struct GNUNET_MESSENGER_SrvHandle *handle,
319 const struct GNUNET_HashCode *key)
320{
321 GNUNET_assert ((service) && (handle) && (key));
322
323 struct GNUNET_MESSENGER_SrvRoom *room = get_service_room (service, key);
324
325 if (room)
326 {
327 initialize_service_handle (handle, room);
328 return open_srv_room (room, handle);
329 }
330
331 room = create_srv_room (handle, key);
332 initialize_service_handle (handle, room);
333
334 if ((GNUNET_YES == open_srv_room (room, handle)) &&
335 (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (service->rooms,
336 key, room,
337 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)))
338 return GNUNET_YES;
339
340 destroy_srv_room (room, GNUNET_YES);
341 return GNUNET_NO;
342}
343
344
345enum GNUNET_GenericReturnValue
346entry_service_room (struct GNUNET_MESSENGER_Service *service,
347 struct GNUNET_MESSENGER_SrvHandle *handle,
348 const struct GNUNET_PeerIdentity *door,
349 const struct GNUNET_HashCode *key)
350{
351 GNUNET_assert ((service) && (handle) && (door) && (key));
352
353 struct GNUNET_MESSENGER_SrvRoom *room = get_service_room (service, key);
354
355 if (room)
356 {
357 initialize_service_handle (handle, room);
358
359 if (GNUNET_YES == enter_srv_room_at (room, handle, door))
360 return GNUNET_YES;
361 else
362 return GNUNET_NO;
363 }
364
365 room = create_srv_room (handle, key);
366 initialize_service_handle (handle, room);
367
368 if ((GNUNET_YES == enter_srv_room_at (room, handle, door)) &&
369 (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (service->rooms,
370 key, room,
371 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)))
372 {
373 return GNUNET_YES;
374 }
375 else
376 {
377 destroy_srv_room (room, GNUNET_YES);
378 return GNUNET_NO;
379 }
380
381}
382
383
384enum GNUNET_GenericReturnValue
385close_service_room (struct GNUNET_MESSENGER_Service *service,
386 struct GNUNET_MESSENGER_SrvHandle *handle,
387 const struct GNUNET_HashCode *key,
388 enum GNUNET_GenericReturnValue deletion)
389{
390 GNUNET_assert ((service) && (handle) && (key));
391
392 struct GNUNET_MESSENGER_SrvRoom *room = get_service_room (service, key);
393
394 if (! room)
395 return GNUNET_NO;
396
397 struct GNUNET_ShortHashCode *id = (struct GNUNET_ShortHashCode*) (
398 GNUNET_CONTAINER_multihashmap_get (handle->member_ids, key));
399
400 GNUNET_assert (id);
401
402 if (GNUNET_YES != GNUNET_CONTAINER_multihashmap_remove (handle->member_ids,
403 key, id))
404 return GNUNET_NO;
405
406 GNUNET_free (id);
407
408 struct GNUNET_MESSENGER_SrvHandle *member_handle = (struct
409 GNUNET_MESSENGER_SrvHandle
410 *)
411 find_list_handle_by_member (
412 &(service->handles), key);
413
414 if (! member_handle)
415 {
416 if (GNUNET_OK == GNUNET_CONTAINER_multihashmap_remove (service->rooms, key,
417 room))
418 {
419 destroy_srv_room (room, deletion);
420 return GNUNET_YES;
421 }
422 else
423 return GNUNET_NO;
424 }
425
426 if (room->host == handle)
427 {
428 room->host = member_handle;
429
430 if (room->peer_message)
431 send_srv_room_message (room, room->host, create_message_connection (
432 room));
433 }
434
435 return GNUNET_YES;
436}
437
438
439void
440handle_service_message (struct GNUNET_MESSENGER_Service *service,
441 struct GNUNET_MESSENGER_SrvRoom *room,
442 const struct GNUNET_MESSENGER_SenderSession *session,
443 const struct GNUNET_MESSENGER_Message *message,
444 const struct GNUNET_HashCode *hash)
445{
446 GNUNET_assert ((service) && (room) && (session) && (message) && (hash));
447
448 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
449 "Notify active clients about message: %s (%s)\n",
450 GNUNET_h2s (hash), GNUNET_MESSENGER_name_of_kind (
451 message->header.kind));
452
453 struct GNUNET_MESSENGER_ListHandle *element = service->handles.head;
454
455 while (element)
456 {
457 notify_srv_handle_message (element->handle, room, session, message, hash,
458 GNUNET_YES);
459 element = element->next;
460 }
461}