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