aboutsummaryrefslogtreecommitdiff
path: root/src/messenger/gnunet-service-messenger_member_session.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/messenger/gnunet-service-messenger_member_session.c')
-rw-r--r--src/messenger/gnunet-service-messenger_member_session.c743
1 files changed, 0 insertions, 743 deletions
diff --git a/src/messenger/gnunet-service-messenger_member_session.c b/src/messenger/gnunet-service-messenger_member_session.c
deleted file mode 100644
index 690c703b2..000000000
--- a/src/messenger/gnunet-service-messenger_member_session.c
+++ /dev/null
@@ -1,743 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2021 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_IDENTITY_PublicKey *pubkey)
36{
37 if ((!member) || (!pubkey) || (!(member->store)))
38 return NULL;
39
40 struct GNUNET_MESSENGER_MemberSession *session = GNUNET_new(struct GNUNET_MESSENGER_MemberSession);
41 session->member = member;
42
43 GNUNET_memcpy(&(session->public_key), pubkey, sizeof(session->public_key));
44
45 get_context_from_member (
46 get_member_session_key (session),
47 get_member_session_id (session),
48 &(session->context)
49 );
50
51 struct GNUNET_MESSENGER_ContactStore *store = get_member_contact_store(session->member->store);
52
53 session->contact = get_store_contact(
54 store,
55 get_member_session_context (session),
56 get_member_session_public_key (session)
57 );
58
59 if (!(session->contact))
60 {
61 GNUNET_free(session);
62 return NULL;
63 }
64
65 increase_contact_rc (session->contact);
66
67 session->history = GNUNET_CONTAINER_multihashmap_create(8, GNUNET_NO);
68
69 init_list_messages(&(session->messages));
70
71 session->prev = NULL;
72 session->next = NULL;
73
74 session->start = GNUNET_TIME_absolute_get();
75
76 session->closed = GNUNET_NO;
77 session->completed = GNUNET_NO;
78
79 return session;
80}
81
82static void
83check_member_session_completion (struct GNUNET_MESSENGER_MemberSession *session)
84{
85 GNUNET_assert (session);
86
87 if (!session->messages.tail)
88 {
89 session->completed = GNUNET_YES;
90 goto completion;
91 }
92
93 const struct GNUNET_HashCode* start = &(session->messages.head->hash);
94 const struct GNUNET_HashCode* end = &(session->messages.tail->hash);
95
96 struct GNUNET_MESSENGER_ListMessages level;
97 init_list_messages(&level);
98
99 add_to_list_messages(&level, end);
100
101 struct GNUNET_MESSENGER_MessageStore *store = get_room_message_store(session->member->store->room);
102
103 struct GNUNET_MESSENGER_ListMessages list;
104 init_list_messages(&list);
105
106 while (level.head)
107 {
108 struct GNUNET_MESSENGER_ListMessage *element;
109
110 for (element = level.head; element; element = element->next)
111 {
112 const struct GNUNET_MESSENGER_MessageLink *link = get_store_message_link(
113 store, &(element->hash), GNUNET_NO
114 );
115
116 if (!link)
117 continue;
118
119 add_to_list_messages(&list, &(link->first));
120
121 if (GNUNET_YES == link->multiple)
122 add_to_list_messages(&list, &(link->second));
123 }
124
125 clear_list_messages(&level);
126
127 for (element = list.head; element; element = element->next)
128 if (GNUNET_YES == check_member_session_history(session, &(element->hash), GNUNET_YES))
129 break;
130
131 if (element)
132 if (0 != GNUNET_CRYPTO_hash_cmp(&(element->hash), start))
133 add_to_list_messages(&level, &(element->hash));
134 else
135 session->completed = GNUNET_YES;
136 else
137 copy_list_messages(&level, &list);
138
139 clear_list_messages(&list);
140 }
141
142completion:
143 if (GNUNET_YES == is_member_session_completed(session))
144 {
145 GNUNET_CONTAINER_multihashmap_destroy (session->history);
146
147 struct GNUNET_MESSENGER_ContactStore *store = get_member_contact_store(session->member->store);
148
149 if ((session->contact) && (GNUNET_YES == decrease_contact_rc (session->contact)))
150 remove_store_contact (
151 store,
152 session->contact,
153 get_member_session_context(session)
154 );
155
156 session->contact = NULL;
157 }
158}
159
160static int
161iterate_copy_history (void *cls, const struct GNUNET_HashCode *key, void *value)
162{
163 struct GNUNET_MESSENGER_MemberSession *next = cls;
164
165 GNUNET_CONTAINER_multihashmap_put(next->history, key, (value? next : NULL),
166 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
167
168 return GNUNET_YES;
169}
170
171struct GNUNET_MESSENGER_MemberSession*
172switch_member_session (struct GNUNET_MESSENGER_MemberSession *session,
173 const struct GNUNET_MESSENGER_Message *message,
174 const struct GNUNET_HashCode *hash)
175{
176 if ((!session) || (!message) || (!hash))
177 return NULL;
178
179 GNUNET_assert((GNUNET_MESSENGER_KIND_ID == message->header.kind) ||
180 (GNUNET_MESSENGER_KIND_KEY == message->header.kind));
181
182 struct GNUNET_MESSENGER_MemberSession *next = GNUNET_new(struct GNUNET_MESSENGER_MemberSession);
183
184 if (GNUNET_MESSENGER_KIND_ID == message->header.kind)
185 next->member = add_store_member(session->member->store, &(message->body.id.id));
186 else
187 next->member = session->member;
188
189 if (GNUNET_MESSENGER_KIND_KEY == message->header.kind)
190 GNUNET_memcpy(&(next->public_key), &(message->body.key.key), sizeof(next->public_key));
191 else
192 GNUNET_memcpy(&(next->public_key), get_member_session_public_key(session), sizeof(next->public_key));
193
194 get_context_from_member (
195 get_member_session_key (next),
196 get_member_session_id (next),
197 &(next->context)
198 );
199
200 update_store_contact(
201 get_member_contact_store(next->member->store),
202 get_member_session_contact(session),
203 get_member_session_context(session),
204 get_member_session_context(next),
205 get_member_session_public_key(next)
206 );
207
208 next->contact = get_member_session_contact(session);
209
210 if (!(next->contact))
211 {
212 GNUNET_free(next);
213 return NULL;
214 }
215
216 increase_contact_rc (next->contact);
217
218 next->history = GNUNET_CONTAINER_multihashmap_create(
219 GNUNET_CONTAINER_multihashmap_size(session->history), GNUNET_NO
220 );
221
222 GNUNET_CONTAINER_multihashmap_iterate(session->history, iterate_copy_history, next);
223
224 init_list_messages(&(next->messages));
225 copy_list_messages(&(next->messages), &(session->messages));
226
227 session->next = next;
228 next->prev = session;
229 next->next = NULL;
230
231 next->start = GNUNET_TIME_absolute_get();
232
233 session->closed = GNUNET_YES;
234 next->closed = GNUNET_NO;
235 next->completed = GNUNET_NO;
236
237 check_member_session_completion (session);
238
239 return next;
240}
241
242void
243destroy_member_session(struct GNUNET_MESSENGER_MemberSession* session)
244{
245 GNUNET_assert (session);
246
247 GNUNET_CONTAINER_multihashmap_destroy (session->history);
248
249 clear_list_messages (&(session->messages));
250
251 struct GNUNET_MESSENGER_Contact *contact = get_member_session_contact (session);
252
253 if ((contact) && (GNUNET_YES == decrease_contact_rc (contact)))
254 remove_store_contact (
255 get_member_contact_store(session->member->store),
256 contact,
257 get_member_session_context(session)
258 );
259
260 GNUNET_free(session);
261}
262
263int
264reset_member_session (struct GNUNET_MESSENGER_MemberSession* session,
265 const struct GNUNET_HashCode *hash)
266{
267 GNUNET_assert ((session) && (hash));
268
269 struct GNUNET_MESSENGER_ContactStore *store = get_member_contact_store(session->member->store);
270 struct GNUNET_MESSENGER_Contact *contact = get_store_contact(
271 store,
272 get_member_session_context (session),
273 get_member_session_public_key (session)
274 );
275
276 if (!contact)
277 return GNUNET_SYSERR;
278
279 if (contact == session->contact)
280 goto clear_messages;
281
282 session->contact = contact;
283 increase_contact_rc (session->contact);
284
285clear_messages:
286 clear_list_messages(&(session->messages));
287 add_to_list_messages(&(session->messages), hash);
288
289 session->next = NULL;
290 session->closed = GNUNET_NO;
291 session->completed = GNUNET_NO;
292
293 return GNUNET_OK;
294}
295
296void
297close_member_session (struct GNUNET_MESSENGER_MemberSession* session)
298{
299 GNUNET_assert (session);
300
301 session->closed = GNUNET_YES;
302 check_member_session_completion (session);
303}
304
305int
306is_member_session_closed (const struct GNUNET_MESSENGER_MemberSession* session)
307{
308 GNUNET_assert(session);
309
310 return session->closed;
311}
312
313int
314is_member_session_completed (const struct GNUNET_MESSENGER_MemberSession* session)
315{
316 GNUNET_assert(session);
317
318 return session->completed;
319}
320
321struct GNUNET_TIME_Absolute
322get_member_session_start (const struct GNUNET_MESSENGER_MemberSession* session)
323{
324 GNUNET_assert(session);
325
326 if (session->prev)
327 return get_member_session_start(session->prev);
328
329 return session->start;
330}
331
332const struct GNUNET_HashCode*
333get_member_session_key (const struct GNUNET_MESSENGER_MemberSession* session)
334{
335 GNUNET_assert((session) && (session->member));
336
337 return get_member_store_key(session->member->store);
338}
339
340const struct GNUNET_ShortHashCode*
341get_member_session_id (const struct GNUNET_MESSENGER_MemberSession* session)
342{
343 GNUNET_assert(session);
344
345 return get_member_id(session->member);
346}
347
348const struct GNUNET_IDENTITY_PublicKey*
349get_member_session_public_key (const struct GNUNET_MESSENGER_MemberSession* session)
350{
351 GNUNET_assert(session);
352
353 return &(session->public_key);
354}
355
356const struct GNUNET_HashCode*
357get_member_session_context (const struct GNUNET_MESSENGER_MemberSession* session)
358{
359 GNUNET_assert(session);
360
361 return &(session->context);
362}
363
364struct GNUNET_MESSENGER_Contact*
365get_member_session_contact (struct GNUNET_MESSENGER_MemberSession* session)
366{
367 GNUNET_assert (session);
368
369 return session->contact;
370}
371
372int verify_member_session_as_sender (const struct GNUNET_MESSENGER_MemberSession *session,
373 const struct GNUNET_MESSENGER_Message *message,
374 const struct GNUNET_HashCode *hash)
375{
376 GNUNET_assert((session) && (message) && (hash));
377
378 if (GNUNET_YES == is_member_session_completed(session))
379 return GNUNET_SYSERR;
380
381 if (0 != GNUNET_memcmp(get_member_session_id(session), &(message->header.sender_id)))
382 return GNUNET_SYSERR;
383
384 return verify_message(message, hash, get_member_session_public_key(session));
385}
386
387int
388check_member_session_history (const struct GNUNET_MESSENGER_MemberSession *session,
389 const struct GNUNET_HashCode *hash, int ownership)
390{
391 GNUNET_assert((session) && (hash));
392
393 if (GNUNET_YES == ownership)
394 return (NULL != GNUNET_CONTAINER_multihashmap_get(session->history, hash)? GNUNET_YES : GNUNET_NO);
395 else
396 return GNUNET_CONTAINER_multihashmap_contains(session->history, hash);
397}
398
399static void
400update_member_chain_history (struct GNUNET_MESSENGER_MemberSession *session,
401 const struct GNUNET_HashCode *hash, int ownership)
402{
403 GNUNET_assert ((session) && (hash));
404
405 if ((GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(session->history, hash, (GNUNET_YES == ownership? session : NULL),
406 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) && (session->next))
407 update_member_chain_history (session->next, hash, ownership);
408}
409
410void
411update_member_session_history (struct GNUNET_MESSENGER_MemberSession *session,
412 const struct GNUNET_MESSENGER_Message *message,
413 const struct GNUNET_HashCode *hash)
414{
415 GNUNET_assert((session) && (message) && (hash));
416
417 if (GNUNET_YES == is_member_session_completed(session))
418 return;
419
420 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Updating sessions history (%s) += (%s)\n",
421 GNUNET_sh2s(get_member_session_id(session)), GNUNET_h2s(hash));
422
423 if (GNUNET_OK == verify_member_session_as_sender (session, message, hash))
424 {
425 if (GNUNET_YES == is_message_session_bound (message))
426 add_to_list_messages(&(session->messages), hash);
427
428 update_member_chain_history (session, hash, GNUNET_YES);
429 }
430 else
431 update_member_chain_history (session, hash, GNUNET_NO);
432
433 if (GNUNET_YES == session->closed)
434 check_member_session_completion(session);
435}
436
437static void
438clear_member_chain_history (struct GNUNET_MESSENGER_MemberSession *session,
439 const struct GNUNET_HashCode *hash)
440{
441 GNUNET_assert ((session) && (hash));
442
443 if ((0 < GNUNET_CONTAINER_multihashmap_remove_all(session->history, hash)) && (session->next))
444 clear_member_session_history(session->next, hash);
445}
446
447void
448clear_member_session_history (struct GNUNET_MESSENGER_MemberSession *session,
449 const struct GNUNET_HashCode *hash)
450{
451 GNUNET_assert((session) && (hash));
452
453 clear_member_chain_history (session, hash);
454}
455
456struct GNUNET_MESSENGER_MemberSessionHistoryEntry
457{
458 struct GNUNET_HashCode hash;
459 unsigned char ownership;
460};
461
462static void
463load_member_session_history (struct GNUNET_MESSENGER_MemberSession *session, const char *path)
464{
465 GNUNET_assert((session) && (path));
466
467 if (GNUNET_YES != GNUNET_DISK_file_test (path))
468 return;
469
470 enum GNUNET_DISK_AccessPermissions permission = (GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE);
471
472 struct GNUNET_DISK_FileHandle *handle = GNUNET_DISK_file_open(
473 path, GNUNET_DISK_OPEN_READ, permission
474 );
475
476 if (!handle)
477 return;
478
479 GNUNET_DISK_file_seek(handle, 0, GNUNET_DISK_SEEK_SET);
480
481 struct GNUNET_MESSENGER_MemberSessionHistoryEntry entry;
482 ssize_t len;
483
484 int status;
485
486 do {
487 len = GNUNET_DISK_file_read(handle, &(entry.hash), sizeof(entry.hash));
488
489 if (len != sizeof(entry.hash))
490 break;
491
492 len = GNUNET_DISK_file_read(handle, &(entry.ownership), sizeof(entry.ownership));
493
494 if (len != sizeof(entry.ownership))
495 break;
496
497 status = GNUNET_CONTAINER_multihashmap_put(session->history, &(entry.hash), (entry.ownership? session : NULL),
498 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
499 } while (status == GNUNET_OK);
500
501 GNUNET_DISK_file_close(handle);
502}
503
504void
505load_member_session (struct GNUNET_MESSENGER_Member *member, const char *directory)
506{
507 GNUNET_assert ((member) && (directory));
508
509 char *config_file;
510 GNUNET_asprintf (&config_file, "%s%s", directory, "session.cfg");
511
512 struct GNUNET_MESSENGER_MemberSession *session = NULL;
513
514 if (GNUNET_YES != GNUNET_DISK_file_test (config_file))
515 goto free_config;
516
517 struct GNUNET_CONFIGURATION_Handle *cfg = GNUNET_CONFIGURATION_create ();
518
519 if (GNUNET_OK == GNUNET_CONFIGURATION_parse (cfg, config_file))
520 {
521 char *key_data;
522
523 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string(cfg, "session", "key", &key_data))
524 goto destroy_config;
525
526 struct GNUNET_IDENTITY_PublicKey key;
527
528 enum GNUNET_GenericReturnValue key_return = GNUNET_IDENTITY_public_key_from_string(key_data, &key);
529
530 GNUNET_free(key_data);
531
532 if (GNUNET_OK != key_return)
533 goto destroy_config;
534
535 session = create_member_session(member, &key);
536
537 unsigned long long numeric_value;
538
539 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg, "session", "start", &numeric_value))
540 session->start.abs_value_us = numeric_value;
541
542 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg, "session", "closed", &numeric_value))
543 session->closed = (GNUNET_YES == numeric_value? GNUNET_YES : GNUNET_NO);
544
545 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg, "session", "completed", &numeric_value))
546 session->completed = (GNUNET_YES == numeric_value? GNUNET_YES : GNUNET_NO);
547 }
548
549destroy_config:
550 GNUNET_CONFIGURATION_destroy (cfg);
551
552free_config:
553 GNUNET_free(config_file);
554
555 if (!session)
556 return;
557
558 char *history_file;
559 GNUNET_asprintf (&history_file, "%s%s", directory, "history.map");
560
561 load_member_session_history (session, history_file);
562 GNUNET_free(history_file);
563
564 char *messages_file;
565 GNUNET_asprintf (&messages_file, "%s%s", directory, "messages.list");
566
567 load_list_messages(&(session->messages), messages_file);
568 GNUNET_free(messages_file);
569
570 add_member_session(member, session);
571}
572
573static struct GNUNET_MESSENGER_MemberSession*
574get_cycle_safe_next_session (struct GNUNET_MESSENGER_MemberSession *session, struct GNUNET_MESSENGER_MemberSession *next)
575{
576 if (!next)
577 return NULL;
578
579 struct GNUNET_MESSENGER_MemberSession *check = next;
580
581 do {
582 if (check == session)
583 return NULL;
584
585 check = check->next;
586 } while (check);
587
588 return next;
589}
590
591void
592load_member_session_next (struct GNUNET_MESSENGER_MemberSession *session, const char *directory)
593{
594 GNUNET_assert ((session) && (directory));
595
596 char *config_file;
597 GNUNET_asprintf (&config_file, "%s%s", directory, "session.cfg");
598
599 if (GNUNET_YES != GNUNET_DISK_file_test (config_file))
600 goto free_config;
601
602 struct GNUNET_CONFIGURATION_Handle *cfg = GNUNET_CONFIGURATION_create ();
603
604 if (GNUNET_OK == GNUNET_CONFIGURATION_parse (cfg, config_file))
605 {
606 char *key_data;
607
608 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string(cfg, "session", "next_key", &key_data))
609 goto destroy_config;
610
611 struct GNUNET_IDENTITY_PublicKey next_key;
612
613 enum GNUNET_GenericReturnValue key_return = GNUNET_IDENTITY_public_key_from_string(key_data, &next_key);
614
615 GNUNET_free(key_data);
616
617 if (GNUNET_OK != key_return)
618 goto destroy_config;
619
620 struct GNUNET_ShortHashCode next_id;
621
622 if (GNUNET_OK != GNUNET_CONFIGURATION_get_data (cfg, "session", "next_id", &next_id, sizeof(next_id)))
623 goto destroy_config;
624
625 struct GNUNET_MESSENGER_Member *member = get_store_member(session->member->store, &next_id);
626
627 session->next = get_cycle_safe_next_session(
628 session, member? get_member_session (member, &next_key) : NULL
629 );
630
631 if (session->next)
632 session->next->prev = session;
633 }
634
635destroy_config:
636 GNUNET_CONFIGURATION_destroy (cfg);
637
638free_config:
639 GNUNET_free(config_file);
640}
641
642static int
643iterate_save_member_session_history_hentries (void *cls, const struct GNUNET_HashCode *key, void *value)
644{
645 struct GNUNET_DISK_FileHandle *handle = cls;
646 unsigned char ownership = value? GNUNET_YES : GNUNET_NO;
647
648 GNUNET_DISK_file_write(handle, key, sizeof(*key));
649 GNUNET_DISK_file_write(handle, &ownership, sizeof(ownership));
650
651 return GNUNET_YES;
652}
653
654static void
655save_member_session_history (struct GNUNET_MESSENGER_MemberSession *session, const char *path)
656{
657 GNUNET_assert((session) && (path));
658
659 enum GNUNET_DISK_AccessPermissions permission = (GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE);
660
661 struct GNUNET_DISK_FileHandle *handle = GNUNET_DISK_file_open(
662 path, GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_WRITE, permission
663 );
664
665 if (!handle)
666 return;
667
668 GNUNET_DISK_file_seek(handle, 0, GNUNET_DISK_SEEK_SET);
669
670 GNUNET_CONTAINER_multihashmap_iterate(
671 session->history,
672 iterate_save_member_session_history_hentries,
673 handle
674 );
675
676 GNUNET_DISK_file_sync(handle);
677 GNUNET_DISK_file_close(handle);
678}
679
680void
681save_member_session (struct GNUNET_MESSENGER_MemberSession *session, const char *directory)
682{
683 GNUNET_assert ((session) && (directory));
684
685 char *config_file;
686 GNUNET_asprintf (&config_file, "%s%s", directory, "session.cfg");
687
688 struct GNUNET_CONFIGURATION_Handle *cfg = GNUNET_CONFIGURATION_create ();
689
690 char *key_data = GNUNET_IDENTITY_public_key_to_string(get_member_session_public_key(session));
691
692 if (key_data)
693 {
694 GNUNET_CONFIGURATION_set_value_string (cfg, "session", "key", key_data);
695
696 GNUNET_free(key_data);
697 }
698
699 if (session->next)
700 {
701 const struct GNUNET_ShortHashCode *next_id = get_member_session_id(session->next);
702
703 char *next_id_data = GNUNET_STRINGS_data_to_string_alloc (next_id, sizeof(*next_id));
704
705 if (next_id_data)
706 {
707 GNUNET_CONFIGURATION_set_value_string (cfg, "session", "next_id", next_id_data);
708
709 GNUNET_free(next_id_data);
710 }
711
712 key_data = GNUNET_IDENTITY_public_key_to_string(get_member_session_public_key(session->next));
713
714 if (key_data)
715 {
716 GNUNET_CONFIGURATION_set_value_string (cfg, "session", "next_key", key_data);
717
718 GNUNET_free(key_data);
719 }
720 }
721
722 GNUNET_CONFIGURATION_set_value_number(cfg, "session", "start", session->start.abs_value_us);
723
724 GNUNET_CONFIGURATION_set_value_number (cfg, "session", "closed", session->closed);
725 GNUNET_CONFIGURATION_set_value_number (cfg, "session", "completed", session->completed);
726
727 GNUNET_CONFIGURATION_write (cfg, config_file);
728 GNUNET_CONFIGURATION_destroy (cfg);
729
730 GNUNET_free(config_file);
731
732 char *history_file;
733 GNUNET_asprintf (&history_file, "%s%s", directory, "history.map");
734
735 save_member_session_history (session, history_file);
736 GNUNET_free(history_file);
737
738 char *messages_file;
739 GNUNET_asprintf (&messages_file, "%s%s", directory, "messages.list");
740
741 save_list_messages(&(session->messages), messages_file);
742 GNUNET_free(messages_file);
743}