aboutsummaryrefslogtreecommitdiff
path: root/src/messenger/gnunet-service-messenger_service.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/messenger/gnunet-service-messenger_service.c')
-rw-r--r--src/messenger/gnunet-service-messenger_service.c516
1 files changed, 516 insertions, 0 deletions
diff --git a/src/messenger/gnunet-service-messenger_service.c b/src/messenger/gnunet-service-messenger_service.c
new file mode 100644
index 000000000..963314fd8
--- /dev/null
+++ b/src/messenger/gnunet-service-messenger_service.c
@@ -0,0 +1,516 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 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
30#include "gnunet-service-messenger.h"
31#include "gnunet-service-messenger_util.h"
32
33static void
34callback_shutdown_service (void *cls)
35{
36 struct GNUNET_MESSENGER_Service *service = cls;
37
38 if (service)
39 {
40 service->shutdown = NULL;
41
42 destroy_service (service);
43 }
44}
45
46static void
47callback_update_ego (void *cls,
48 struct GNUNET_IDENTITY_Ego *ego,
49 void **ctx,
50 const char *identifier)
51{
52 if ((!ego) || (!identifier))
53 return;
54
55 struct GNUNET_MESSENGER_Service *service = cls;
56
57 update_service_ego(service, identifier, GNUNET_IDENTITY_ego_get_private_key(ego));
58}
59
60struct GNUNET_MESSENGER_Service*
61create_service (const struct GNUNET_CONFIGURATION_Handle *config, struct GNUNET_SERVICE_Handle *service_handle)
62{
63 struct GNUNET_MESSENGER_Service *service = GNUNET_new(struct GNUNET_MESSENGER_Service);
64
65 service->config = config;
66 service->service = service_handle;
67
68 service->shutdown = GNUNET_SCHEDULER_add_shutdown (&callback_shutdown_service, service);
69
70 service->dir = NULL;
71
72 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (service->config,
73 GNUNET_MESSENGER_SERVICE_NAME,
74 "MESSENGER_DIR", &(service->dir)))
75 {
76 if (service->dir)
77 GNUNET_free(service->dir);
78
79 service->dir = NULL;
80 }
81 else
82 {
83 if ((GNUNET_YES != GNUNET_DISK_directory_test (service->dir, GNUNET_YES)) && (GNUNET_OK
84 != GNUNET_DISK_directory_create (service->dir)))
85 {
86 GNUNET_free(service->dir);
87
88 service->dir = NULL;
89 }
90 }
91
92 service->cadet = GNUNET_CADET_connect (service->config);
93 service->identity = GNUNET_IDENTITY_connect (service->config, &callback_update_ego, service);
94
95 service->egos = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
96
97 init_list_handles (&(service->handles));
98
99 service->contacts = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
100 service->rooms = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
101
102 return service;
103}
104
105static int
106iterate_destroy_egos (void *cls, const struct GNUNET_HashCode *key, void *value)
107{
108 struct GNUNET_MESSENGER_Ego *ego = value;
109 GNUNET_free(ego);
110 return GNUNET_YES;
111}
112
113static int
114iterate_destroy_rooms (void *cls, const struct GNUNET_HashCode *key, void *value)
115{
116 struct GNUNET_MESSENGER_SrvRoom *room = value;
117 destroy_room (room);
118 return GNUNET_YES;
119}
120
121static int
122iterate_destroy_contacts (void *cls, const struct GNUNET_HashCode *key, void *value)
123{
124 struct GNUNET_MESSENGER_SrvContact *contact = value;
125 destroy_contact (contact);
126 return GNUNET_YES;
127}
128
129void
130destroy_service (struct GNUNET_MESSENGER_Service *service)
131{
132 if (service->shutdown)
133 {
134 GNUNET_SCHEDULER_cancel (service->shutdown);
135
136 service->shutdown = NULL;
137 }
138
139 GNUNET_CONTAINER_multihashmap_iterate (service->egos, iterate_destroy_egos, NULL);
140
141 clear_list_handles (&(service->handles));
142
143 GNUNET_CONTAINER_multihashmap_iterate (service->rooms, iterate_destroy_rooms, NULL);
144 GNUNET_CONTAINER_multihashmap_iterate (service->contacts, iterate_destroy_contacts, NULL);
145
146 GNUNET_CONTAINER_multihashmap_destroy (service->egos);
147 GNUNET_CONTAINER_multihashmap_destroy (service->rooms);
148 GNUNET_CONTAINER_multihashmap_destroy (service->contacts);
149
150 if (service->cadet)
151 {
152 GNUNET_CADET_disconnect (service->cadet);
153
154 service->cadet = NULL;
155 }
156
157 if (service->identity)
158 {
159 GNUNET_IDENTITY_disconnect (service->identity);
160
161 service->identity = NULL;
162 }
163
164 if (service->dir)
165 {
166 GNUNET_free(service->dir);
167
168 service->dir = NULL;
169 }
170
171 GNUNET_SERVICE_shutdown (service->service);
172
173 GNUNET_free(service);
174}
175
176struct GNUNET_MESSENGER_Ego*
177lookup_service_ego (struct GNUNET_MESSENGER_Service *service, const char *identifier)
178{
179 GNUNET_assert(identifier);
180
181 struct GNUNET_HashCode hash;
182
183 GNUNET_CRYPTO_hash(identifier, strlen(identifier), &hash);
184 return GNUNET_CONTAINER_multihashmap_get(service->egos, &hash);
185}
186
187void
188update_service_ego (struct GNUNET_MESSENGER_Service *service, const char *identifier,
189 const struct GNUNET_IDENTITY_PrivateKey* key)
190{
191 GNUNET_assert((identifier) && (key));
192
193 struct GNUNET_HashCode hash;
194
195 GNUNET_CRYPTO_hash(identifier, strlen(identifier), &hash);
196
197 struct GNUNET_MESSENGER_Ego* ego = GNUNET_CONTAINER_multihashmap_get(service->egos, &hash);
198
199 if (!ego)
200 {
201 ego = GNUNET_new(struct GNUNET_MESSENGER_Ego);
202 GNUNET_CONTAINER_multihashmap_put(service->egos, &hash, ego, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
203 }
204
205 GNUNET_memcpy(&(ego->priv), key, sizeof(*key));
206
207 if (GNUNET_OK != GNUNET_IDENTITY_key_get_public(key, &(ego->pub)))
208 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Updating invalid ego key failed!\n");
209}
210
211struct GNUNET_MESSENGER_SrvHandle*
212add_service_handle (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MQ_Handle *mq)
213{
214 struct GNUNET_MESSENGER_SrvHandle *handle = create_handle (service, mq);
215
216 if (handle)
217 {
218 add_list_handle (&(service->handles), handle);
219 }
220
221 return handle;
222}
223
224void
225remove_service_handle (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvHandle *handle)
226{
227 if (!handle)
228 return;
229
230 if (GNUNET_YES == remove_list_handle (&(service->handles), handle))
231 destroy_handle (handle);
232}
233
234int
235get_service_peer_identity (const struct GNUNET_MESSENGER_Service *service, struct GNUNET_PeerIdentity *peer)
236{
237 return GNUNET_CRYPTO_get_peer_identity (service->config, peer);
238}
239
240struct GNUNET_MESSENGER_SrvContact*
241get_service_contact_by_pubkey (struct GNUNET_MESSENGER_Service *service, const struct GNUNET_IDENTITY_PublicKey *pubkey)
242{
243 struct GNUNET_HashCode hash;
244
245 GNUNET_CRYPTO_hash (pubkey, sizeof(*pubkey), &hash);
246
247 struct GNUNET_MESSENGER_SrvContact *contact = GNUNET_CONTAINER_multihashmap_get (service->contacts, &hash);
248
249 if (contact)
250 return contact;
251
252 contact = create_contact (pubkey);
253
254 if (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (service->contacts, &hash, contact,
255 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
256 return contact;
257
258 destroy_contact (contact);
259 return NULL;
260}
261
262void
263swap_service_contact_by_pubkey (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvContact *contact,
264 const struct GNUNET_IDENTITY_PublicKey *pubkey)
265{
266 const struct GNUNET_HashCode *hash = get_contact_id_from_key (contact);
267
268 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (service->contacts, hash, contact))
269 {
270 GNUNET_memcpy(&(contact->public_key), pubkey, sizeof(*pubkey));
271
272 hash = get_contact_id_from_key (contact);
273
274 GNUNET_CONTAINER_multihashmap_put (service->contacts, hash, contact,
275 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
276 }
277}
278
279struct GNUNET_ShortHashCode*
280generate_service_new_member_id (struct GNUNET_MESSENGER_Service *service, const struct GNUNET_HashCode *key)
281{
282 struct GNUNET_MESSENGER_SrvRoom *room = get_service_room (service, key);
283
284 if (room)
285 {
286 return generate_room_member_id (room);
287 }
288 else
289 {
290 struct GNUNET_ShortHashCode *random_id = GNUNET_new(struct GNUNET_ShortHashCode);
291 generate_free_member_id (random_id, NULL);
292 return random_id;
293 }
294}
295
296struct GNUNET_MESSENGER_SrvRoom*
297get_service_room (struct GNUNET_MESSENGER_Service *service, const struct GNUNET_HashCode *key)
298{
299 return GNUNET_CONTAINER_multihashmap_get (service->rooms, key);
300}
301
302int
303open_service_room (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvHandle *handle,
304 const struct GNUNET_HashCode *key)
305{
306 struct GNUNET_MESSENGER_SrvRoom *room = get_service_room (service, key);
307
308 if (room)
309 return open_room (room, handle);
310
311 room = create_room (handle, key);
312
313 if ((GNUNET_YES == open_room (room, handle)) && (GNUNET_OK
314 == GNUNET_CONTAINER_multihashmap_put (service->rooms, key, room, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)))
315 return GNUNET_YES;
316
317 destroy_room (room);
318 return GNUNET_NO;
319}
320
321int
322entry_service_room (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvHandle *handle,
323 const struct GNUNET_PeerIdentity *door, const struct GNUNET_HashCode *key)
324{
325 struct GNUNET_MESSENGER_SrvRoom *room = get_service_room (service, key);
326
327 if (room)
328 {
329 if (GNUNET_YES == entry_room_at (room, handle, door))
330 return GNUNET_YES;
331 else
332 return GNUNET_NO;
333 }
334
335 room = create_room (handle, key);
336
337 if ((GNUNET_YES == entry_room_at (room, handle, door)) && (GNUNET_OK
338 == GNUNET_CONTAINER_multihashmap_put (service->rooms, key, room, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)))
339 {
340 return GNUNET_YES;
341 }
342 else
343 {
344 destroy_room (room);
345 return GNUNET_NO;
346 }
347
348}
349
350int
351close_service_room (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvHandle *handle,
352 const struct GNUNET_HashCode *key)
353{
354 struct GNUNET_MESSENGER_SrvRoom *room = get_service_room (service, key);
355
356 if (!room)
357 return GNUNET_NO;
358
359 struct GNUNET_MESSENGER_Message *message = create_message_leave ();
360
361 if (message)
362 {
363 struct GNUNET_HashCode hash;
364
365 send_room_message (room, handle, message, &hash);
366 destroy_message (message);
367 }
368
369 const struct GNUNET_ShortHashCode *id = get_handle_member_id (handle, key);
370
371 GNUNET_assert(id);
372
373 if (GNUNET_YES != GNUNET_CONTAINER_multihashmap_remove (handle->member_ids, key, id))
374 return GNUNET_NO;
375
376 struct GNUNET_MESSENGER_SrvHandle *member_handle = (struct GNUNET_MESSENGER_SrvHandle*) find_list_handle_by_member (
377 &(service->handles), key);
378
379 if (!member_handle)
380 {
381 if (GNUNET_OK == GNUNET_CONTAINER_multihashmap_remove (service->rooms, key, room))
382 {
383 destroy_room (room);
384 return GNUNET_YES;
385 }
386 else
387 return GNUNET_NO;
388 }
389
390 if (room->host == handle)
391 room->host = member_handle;
392
393 return GNUNET_YES;
394}
395
396static void
397get_room_data_subdir (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvRoom *room, char **dir)
398{
399 GNUNET_asprintf (dir, "%s%s%c%s%c", service->dir, "rooms", DIR_SEPARATOR, GNUNET_h2s (&(room->key)), DIR_SEPARATOR);
400}
401
402void
403load_service_room_and_messages (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvRoom *room)
404{
405 char *room_dir;
406 get_room_data_subdir (service, room, &room_dir);
407
408 if (GNUNET_YES == GNUNET_DISK_directory_test (room_dir, GNUNET_YES))
409 {
410 load_message_store (&room->store, room_dir);
411
412 char *config_file;
413 GNUNET_asprintf (&config_file, "%s%s", room_dir, "room.cfg");
414
415 struct GNUNET_CONFIGURATION_Handle *cfg = GNUNET_CONFIGURATION_create ();
416
417 if ((GNUNET_YES == GNUNET_DISK_file_test (config_file)) && (GNUNET_OK
418 == GNUNET_CONFIGURATION_parse (cfg, config_file)))
419 {
420 unsigned long long access;
421
422 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (cfg, "room", "access-rule", &access))
423 room->strict_access = (int) (access);
424
425 char *message_string;
426
427 if ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, "room", "last-message", &message_string)) && (message_string))
428 {
429 struct GNUNET_HashCode hash;
430
431 GNUNET_CRYPTO_hash_from_string(message_string, &hash);
432
433 const struct GNUNET_MESSENGER_Message *message = get_room_message (room, room->host, &hash, GNUNET_NO);
434
435 if (message)
436 update_room_last_messages (room, message, &hash);
437
438 GNUNET_free(message_string);
439 }
440 }
441
442 GNUNET_CONFIGURATION_destroy (cfg);
443
444 GNUNET_free(config_file);
445 }
446
447 GNUNET_free(room_dir);
448}
449
450void
451save_service_room_and_messages (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvRoom *room)
452{
453 if (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains (service->rooms, &(room->key)))
454 {
455 return;
456 }
457
458 char *room_dir;
459 get_room_data_subdir (service, room, &room_dir);
460
461 if ((GNUNET_YES == GNUNET_DISK_directory_test (room_dir, GNUNET_NO)) || (GNUNET_OK
462 == GNUNET_DISK_directory_create (room_dir)))
463 {
464 save_message_store (&room->store, room_dir);
465
466 char *config_file;
467 GNUNET_asprintf (&config_file, "%s%s", room_dir, "room.cfg");
468
469 struct GNUNET_CONFIGURATION_Handle *cfg = GNUNET_CONFIGURATION_create ();
470
471 GNUNET_CONFIGURATION_set_value_number (cfg, "room", "access-rule", room->strict_access);
472
473 if (room->last_messages.head)
474 GNUNET_CONFIGURATION_set_value_string (cfg, "room", "last-message",
475 GNUNET_h2s_full (&(room->last_messages.head->hash)));
476
477 GNUNET_CONFIGURATION_write (cfg, config_file);
478 GNUNET_CONFIGURATION_destroy (cfg);
479
480 GNUNET_free(config_file);
481 }
482
483 GNUNET_free(room_dir);
484}
485
486void
487handle_service_message (struct GNUNET_MESSENGER_Service *service, struct GNUNET_MESSENGER_SrvRoom *room,
488 const struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash)
489{
490 struct GNUNET_MESSENGER_ListHandle *element = service->handles.head;
491
492 const uint16_t length = get_message_size (message);
493
494 while (element)
495 {
496 struct GNUNET_MESSENGER_SrvHandle *handle = (struct GNUNET_MESSENGER_SrvHandle*) element->handle;
497
498 if ((handle->mq) && (get_handle_member_id (handle, &(room->key))))
499 {
500 struct GNUNET_MESSENGER_RecvMessage *msg;
501 struct GNUNET_MQ_Envelope *env;
502
503 env = GNUNET_MQ_msg_extra(msg, length, GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_RECV_MESSAGE);
504
505 GNUNET_memcpy(&(msg->key), &(room->key), sizeof(room->key));
506 GNUNET_memcpy(&(msg->hash), hash, sizeof(*hash));
507
508 char *buffer = ((char*) msg) + sizeof(*msg);
509 encode_message (message, length, buffer);
510
511 GNUNET_MQ_send (handle->mq, env);
512 }
513
514 element = element->next;
515 }
516}