aboutsummaryrefslogtreecommitdiff
path: root/src/service/messenger/gnunet-service-messenger_member_session.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/service/messenger/gnunet-service-messenger_member_session.c')
-rw-r--r--src/service/messenger/gnunet-service-messenger_member_session.c866
1 files changed, 866 insertions, 0 deletions
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
33struct GNUNET_MESSENGER_MemberSession*
34create_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
85static void
86check_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
151completion:
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
173static enum GNUNET_GenericReturnValue
174iterate_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
187struct GNUNET_MESSENGER_MemberSession*
188switch_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
264void
265destroy_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
287enum GNUNET_GenericReturnValue
288reset_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
310clear_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
322void
323close_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
332enum GNUNET_GenericReturnValue
333is_member_session_closed (const struct GNUNET_MESSENGER_MemberSession *session)
334{
335 GNUNET_assert (session);
336
337 return session->closed;
338}
339
340
341enum GNUNET_GenericReturnValue
342is_member_session_completed (const struct
343 GNUNET_MESSENGER_MemberSession *session)
344{
345 GNUNET_assert (session);
346
347 return session->completed;
348}
349
350
351struct GNUNET_TIME_Absolute
352get_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
363const struct GNUNET_HashCode*
364get_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
372const struct GNUNET_ShortHashCode*
373get_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
381const struct GNUNET_CRYPTO_PublicKey*
382get_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
391const struct GNUNET_HashCode*
392get_member_session_context (const struct
393 GNUNET_MESSENGER_MemberSession *session)
394{
395 GNUNET_assert (session);
396
397 return &(session->context);
398}
399
400
401struct GNUNET_MESSENGER_Contact*
402get_member_session_contact (struct GNUNET_MESSENGER_MemberSession *session)
403{
404 GNUNET_assert (session);
405
406 return session->contact;
407}
408
409
410enum GNUNET_GenericReturnValue
411verify_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
443enum GNUNET_GenericReturnValue
444check_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
459static void
460update_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
475void
476update_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
504static void
505clear_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
516void
517clear_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
526struct GNUNET_MESSENGER_MemberSessionHistoryEntry
527{
528 struct GNUNET_HashCode hash;
529 unsigned char ownership;
530};
531
532static void
533load_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
581void
582load_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
639destroy_config:
640 GNUNET_CONFIGURATION_destroy (cfg);
641
642free_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
664static struct GNUNET_MESSENGER_MemberSession*
665get_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
684void
685load_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
737destroy_config:
738 GNUNET_CONFIGURATION_destroy (cfg);
739
740free_config:
741 GNUNET_free (config_file);
742}
743
744
745static enum GNUNET_GenericReturnValue
746iterate_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
760static void
761save_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
790void
791save_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}