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