aboutsummaryrefslogtreecommitdiff
path: root/src/service/messenger/gnunet-service-messenger_member.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/service/messenger/gnunet-service-messenger_member.c')
-rw-r--r--src/service/messenger/gnunet-service-messenger_member.c460
1 files changed, 460 insertions, 0 deletions
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..c57daa062
--- /dev/null
+++ b/src/service/messenger/gnunet-service-messenger_member.c
@@ -0,0 +1,460 @@
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_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
31struct GNUNET_MESSENGER_Member*
32create_member (struct GNUNET_MESSENGER_MemberStore *store,
33 const struct GNUNET_ShortHashCode *id)
34{
35 GNUNET_assert (store);
36
37 struct GNUNET_MESSENGER_Member *member = GNUNET_new (struct
38 GNUNET_MESSENGER_Member);
39
40 member->store = store;
41
42 if (id)
43 GNUNET_memcpy (&(member->id), id, sizeof(member->id));
44 else if (GNUNET_YES != generate_free_member_id (&(member->id),
45 store->members))
46 {
47 GNUNET_free (member);
48 return NULL;
49 }
50
51 member->sessions = GNUNET_CONTAINER_multihashmap_create (2, GNUNET_NO);
52
53 return member;
54}
55
56
57static int
58iterate_destroy_session (void *cls,
59 const struct GNUNET_HashCode *key,
60 void *value)
61{
62 struct GNUNET_MESSENGER_MemberSession *session = value;
63 destroy_member_session (session);
64 return GNUNET_YES;
65}
66
67
68void
69destroy_member (struct GNUNET_MESSENGER_Member *member)
70{
71 GNUNET_assert ((member) && (member->sessions));
72
73 GNUNET_CONTAINER_multihashmap_iterate (member->sessions,
74 iterate_destroy_session, NULL);
75 GNUNET_CONTAINER_multihashmap_destroy (member->sessions);
76
77 GNUNET_free (member);
78}
79
80
81const struct GNUNET_ShortHashCode*
82get_member_id (const struct GNUNET_MESSENGER_Member *member)
83{
84 GNUNET_assert (member);
85
86 return &(member->id);
87}
88
89
90static int
91callback_scan_for_sessions (void *cls,
92 const char *filename)
93{
94 struct GNUNET_MESSENGER_Member *member = cls;
95
96 if (GNUNET_YES == GNUNET_DISK_directory_test (filename, GNUNET_YES))
97 {
98 char *directory;
99
100 GNUNET_asprintf (&directory, "%s%c", filename, DIR_SEPARATOR);
101
102 load_member_session (member, directory);
103 GNUNET_free (directory);
104 }
105
106 return GNUNET_OK;
107}
108
109
110void
111load_member (struct GNUNET_MESSENGER_MemberStore *store,
112 const char *directory)
113{
114 GNUNET_assert ((store) && (directory));
115
116 char *config_file;
117 GNUNET_asprintf (&config_file, "%s%s", directory, "member.cfg");
118
119 struct GNUNET_MESSENGER_Member *member = NULL;
120
121 if (GNUNET_YES != GNUNET_DISK_file_test (config_file))
122 goto free_config;
123
124 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Load member configuration: %s\n",
125 config_file);
126
127 struct GNUNET_CONFIGURATION_Handle *cfg = GNUNET_CONFIGURATION_create ();
128
129 if (GNUNET_OK == GNUNET_CONFIGURATION_parse (cfg, config_file))
130 {
131 struct GNUNET_ShortHashCode id;
132
133 if (GNUNET_OK != GNUNET_CONFIGURATION_get_data (cfg, "member", "id", &id,
134 sizeof(id)))
135 goto destroy_config;
136
137 member = add_store_member (store, &id);
138 }
139
140destroy_config:
141
142 GNUNET_CONFIGURATION_destroy (cfg);
143
144free_config:
145 GNUNET_free (config_file);
146
147 if (! member)
148 return;
149
150 char *scan_dir;
151 GNUNET_asprintf (&scan_dir, "%s%s%c", directory, "sessions", DIR_SEPARATOR);
152
153 if (GNUNET_OK == GNUNET_DISK_directory_test (scan_dir, GNUNET_YES))
154 GNUNET_DISK_directory_scan (scan_dir, callback_scan_for_sessions, member);
155
156 GNUNET_free (scan_dir);
157}
158
159
160static int
161iterate_load_next_session (void *cls,
162 const struct GNUNET_HashCode *key,
163 void *value)
164{
165 const char *sessions_directory = cls;
166
167 char *load_dir;
168 GNUNET_asprintf (&load_dir, "%s%s%c", sessions_directory, GNUNET_h2s (key),
169 DIR_SEPARATOR);
170
171 struct GNUNET_MESSENGER_MemberSession *session = value;
172
173 if (GNUNET_YES == GNUNET_DISK_directory_test (load_dir, GNUNET_YES))
174 load_member_session_next (session, load_dir);
175
176 GNUNET_free (load_dir);
177 return GNUNET_YES;
178}
179
180
181void
182load_member_next_sessions (const struct GNUNET_MESSENGER_Member *member,
183 const char *directory)
184{
185 GNUNET_assert ((member) && (directory));
186
187 char *load_dir;
188 GNUNET_asprintf (&load_dir, "%s%s%c", directory, "sessions", DIR_SEPARATOR);
189
190 GNUNET_CONTAINER_multihashmap_iterate (member->sessions,
191 iterate_load_next_session, load_dir);
192
193 GNUNET_free (load_dir);
194}
195
196
197static int
198iterate_save_session (void *cls,
199 const struct GNUNET_HashCode *key,
200 void *value)
201{
202 const char *sessions_directory = cls;
203
204 char *save_dir;
205 GNUNET_asprintf (&save_dir, "%s%s%c", sessions_directory, GNUNET_h2s (key),
206 DIR_SEPARATOR);
207
208 struct GNUNET_MESSENGER_MemberSession *session = value;
209
210 if ((GNUNET_YES == GNUNET_DISK_directory_test (save_dir, GNUNET_NO)) ||
211 (GNUNET_OK == GNUNET_DISK_directory_create (save_dir)))
212 save_member_session (session, save_dir);
213
214 GNUNET_free (save_dir);
215 return GNUNET_YES;
216}
217
218
219void
220save_member (struct GNUNET_MESSENGER_Member *member,
221 const char *directory)
222{
223 GNUNET_assert ((member) && (directory));
224
225 char *config_file;
226 GNUNET_asprintf (&config_file, "%s%s", directory, "member.cfg");
227
228 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Save member configuration: %s\n",
229 config_file);
230
231 struct GNUNET_CONFIGURATION_Handle *cfg = GNUNET_CONFIGURATION_create ();
232
233 char *id_data = GNUNET_STRINGS_data_to_string_alloc (&(member->id),
234 sizeof(member->id));
235
236 if (id_data)
237 {
238 GNUNET_CONFIGURATION_set_value_string (cfg, "member", "id", id_data);
239
240 GNUNET_free (id_data);
241 }
242
243 GNUNET_CONFIGURATION_write (cfg, config_file);
244 GNUNET_CONFIGURATION_destroy (cfg);
245
246 GNUNET_free (config_file);
247
248 char *save_dir;
249 GNUNET_asprintf (&save_dir, "%s%s%c", directory, "sessions", DIR_SEPARATOR);
250
251 if ((GNUNET_YES == GNUNET_DISK_directory_test (save_dir, GNUNET_NO)) ||
252 (GNUNET_OK == GNUNET_DISK_directory_create (save_dir)))
253 GNUNET_CONTAINER_multihashmap_iterate (member->sessions,
254 iterate_save_session, save_dir);
255
256 GNUNET_free (save_dir);
257}
258
259
260static void
261sync_session_contact_from_next (struct GNUNET_MESSENGER_MemberSession *session,
262 struct GNUNET_MESSENGER_MemberSession *next)
263{
264 GNUNET_assert ((session) && (next));
265
266 if (session == next)
267 return;
268
269 if (next->next)
270 sync_session_contact_from_next (session, next->next);
271 else
272 session->contact = next->contact;
273}
274
275
276static int
277iterate_sync_session_contact (void *cls,
278 const struct GNUNET_HashCode *key,
279 void *value)
280{
281 struct GNUNET_MESSENGER_MemberSession *session = value;
282
283 if (session->next)
284 sync_session_contact_from_next (session, session->next);
285
286 return GNUNET_YES;
287}
288
289
290void
291sync_member_contacts (struct GNUNET_MESSENGER_Member *member)
292{
293 GNUNET_assert ((member) && (member->sessions));
294
295 GNUNET_CONTAINER_multihashmap_iterate (member->sessions,
296 iterate_sync_session_contact, NULL);
297}
298
299
300struct GNUNET_MESSENGER_MemberSession*
301get_member_session (const struct GNUNET_MESSENGER_Member *member,
302 const struct GNUNET_CRYPTO_PublicKey *public_key)
303{
304 GNUNET_assert ((member) && (public_key));
305
306 struct GNUNET_HashCode hash;
307 GNUNET_CRYPTO_hash (public_key, sizeof(*public_key), &hash);
308
309 return GNUNET_CONTAINER_multihashmap_get (member->sessions, &hash);
310}
311
312
313struct GNUNET_MESSENGER_ClosureSearchSession
314{
315 const struct GNUNET_MESSENGER_Message *message;
316 const struct GNUNET_HashCode *hash;
317
318 struct GNUNET_MESSENGER_MemberSession *match;
319};
320
321static int
322iterate_search_session (void *cls,
323 const struct GNUNET_HashCode *key,
324 void *value)
325{
326 struct GNUNET_MESSENGER_ClosureSearchSession *search = cls;
327 struct GNUNET_MESSENGER_MemberSession *session = value;
328
329 if (GNUNET_OK != verify_member_session_as_sender (session, search->message,
330 search->hash))
331 return GNUNET_YES;
332
333 search->match = session;
334 return GNUNET_NO;
335}
336
337
338static struct GNUNET_MESSENGER_MemberSession*
339try_member_session (struct GNUNET_MESSENGER_Member *member,
340 const struct GNUNET_CRYPTO_PublicKey *public_key)
341{
342 struct GNUNET_MESSENGER_MemberSession *session = get_member_session (member,
343 public_key);
344
345 if (session)
346 return session;
347
348 session = create_member_session (member, public_key);
349
350 if (session)
351 add_member_session (member, session);
352
353 return session;
354}
355
356
357struct GNUNET_MESSENGER_MemberSession*
358get_member_session_of (struct GNUNET_MESSENGER_Member *member,
359 const struct GNUNET_MESSENGER_Message *message,
360 const struct GNUNET_HashCode *hash)
361{
362 GNUNET_assert ((member) && (message) && (hash) &&
363 (0 == GNUNET_memcmp (&(member->id),
364 &(message->header.sender_id))));
365
366 if (GNUNET_MESSENGER_KIND_JOIN == message->header.kind)
367 return try_member_session (member, &(message->body.join.key));
368
369 struct GNUNET_MESSENGER_ClosureSearchSession search;
370
371 search.message = message;
372 search.hash = hash;
373
374 search.match = NULL;
375 GNUNET_CONTAINER_multihashmap_iterate (member->sessions,
376 iterate_search_session, &search);
377
378 return search.match;
379}
380
381
382void
383add_member_session (struct GNUNET_MESSENGER_Member *member,
384 struct GNUNET_MESSENGER_MemberSession *session)
385{
386 if (! session)
387 return;
388
389 GNUNET_assert ((member) && (session->member == member));
390
391 const struct GNUNET_CRYPTO_PublicKey *public_key =
392 get_member_session_public_key (session);
393
394 struct GNUNET_HashCode hash;
395 GNUNET_CRYPTO_hash (public_key, sizeof(*public_key), &hash);
396
397 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (
398 member->sessions, &hash, session,
399 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
400 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
401 "Adding a member session failed: %s\n",
402 GNUNET_h2s (&hash));
403}
404
405
406void
407remove_member_session (struct GNUNET_MESSENGER_Member *member,
408 struct GNUNET_MESSENGER_MemberSession *session)
409{
410 GNUNET_assert ((member) && (session) && (session->member == member));
411
412 const struct GNUNET_CRYPTO_PublicKey *public_key =
413 get_member_session_public_key (session);
414
415 struct GNUNET_HashCode hash;
416 GNUNET_CRYPTO_hash (public_key, sizeof(*public_key), &hash);
417
418 if (GNUNET_YES != GNUNET_CONTAINER_multihashmap_remove (member->sessions,
419 &hash, session))
420 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
421 "Removing a member session failed: %s\n",
422 GNUNET_h2s (&hash));
423}
424
425
426struct GNUNET_MESSENGER_ClosureIterateSessions
427{
428 GNUNET_MESSENGER_MemberIteratorCallback it;
429 void *cls;
430};
431
432static int
433iterate_member_sessions_it (void *cls,
434 const struct GNUNET_HashCode *key,
435 void *value)
436{
437 struct GNUNET_MESSENGER_ClosureIterateSessions *iterate = cls;
438 struct GNUNET_MESSENGER_MemberSession *session = value;
439
440 return iterate->it (iterate->cls, get_member_session_public_key (session),
441 session);
442}
443
444
445int
446iterate_member_sessions (struct GNUNET_MESSENGER_Member *member,
447 GNUNET_MESSENGER_MemberIteratorCallback it,
448 void *cls)
449{
450 GNUNET_assert ((member) && (member->sessions) && (it));
451
452 struct GNUNET_MESSENGER_ClosureIterateSessions iterate;
453
454 iterate.it = it;
455 iterate.cls = cls;
456
457 return GNUNET_CONTAINER_multihashmap_iterate (member->sessions,
458 iterate_member_sessions_it,
459 &iterate);
460}