gnunet-service-messenger_member_session.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2021 GNUnet e.V.
  4. GNUnet is free software: you can redistribute it and/or modify it
  5. under the terms of the GNU Affero General Public License as published
  6. by the Free Software Foundation, either version 3 of the License,
  7. or (at your option) any later version.
  8. GNUnet is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Affero General Public License for more details.
  12. You should have received a copy of the GNU Affero General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. SPDX-License-Identifier: AGPL3.0-or-later
  15. */
  16. /**
  17. * @author Tobias Frisch
  18. * @file src/messenger/gnunet-service-messenger_member_session.c
  19. * @brief GNUnet MESSENGER service
  20. */
  21. #include "gnunet-service-messenger_member_session.h"
  22. #include "gnunet-service-messenger_room.h"
  23. #include "gnunet-service-messenger_message_store.h"
  24. #include "messenger_api_contact_store.h"
  25. struct GNUNET_MESSENGER_MemberSession*
  26. create_member_session (struct GNUNET_MESSENGER_Member *member,
  27. const struct GNUNET_IDENTITY_PublicKey *pubkey)
  28. {
  29. if ((!member) || (!pubkey) || (!(member->store)))
  30. return NULL;
  31. struct GNUNET_MESSENGER_MemberSession *session = GNUNET_new(struct GNUNET_MESSENGER_MemberSession);
  32. session->member = member;
  33. GNUNET_memcpy(&(session->public_key), pubkey, sizeof(session->public_key));
  34. get_context_from_member (
  35. get_member_session_key (session),
  36. get_member_session_id (session),
  37. &(session->context)
  38. );
  39. struct GNUNET_MESSENGER_ContactStore *store = get_member_contact_store(session->member->store);
  40. session->contact = get_store_contact(
  41. store,
  42. get_member_session_context (session),
  43. get_member_session_public_key (session)
  44. );
  45. if (!(session->contact))
  46. {
  47. GNUNET_free(session);
  48. return NULL;
  49. }
  50. increase_contact_rc (session->contact);
  51. session->history = GNUNET_CONTAINER_multihashmap_create(8, GNUNET_NO);
  52. init_list_messages(&(session->messages));
  53. session->prev = NULL;
  54. session->next = NULL;
  55. session->start = GNUNET_TIME_absolute_get();
  56. session->closed = GNUNET_NO;
  57. session->completed = GNUNET_NO;
  58. return session;
  59. }
  60. static void
  61. check_member_session_completion (struct GNUNET_MESSENGER_MemberSession *session)
  62. {
  63. GNUNET_assert (session);
  64. if (!session->messages.tail)
  65. {
  66. session->completed = GNUNET_YES;
  67. goto completion;
  68. }
  69. const struct GNUNET_HashCode* start = &(session->messages.head->hash);
  70. const struct GNUNET_HashCode* end = &(session->messages.tail->hash);
  71. struct GNUNET_MESSENGER_ListMessages level;
  72. init_list_messages(&level);
  73. add_to_list_messages(&level, end);
  74. struct GNUNET_MESSENGER_MessageStore *store = get_room_message_store(session->member->store->room);
  75. struct GNUNET_MESSENGER_ListMessages list;
  76. init_list_messages(&list);
  77. while (level.head)
  78. {
  79. struct GNUNET_MESSENGER_ListMessage *element;
  80. for (element = level.head; element; element = element->next)
  81. {
  82. const struct GNUNET_MESSENGER_MessageLink *link = get_store_message_link(
  83. store, &(element->hash), GNUNET_NO
  84. );
  85. if (!link)
  86. continue;
  87. add_to_list_messages(&list, &(link->first));
  88. if (GNUNET_YES == link->multiple)
  89. add_to_list_messages(&list, &(link->second));
  90. }
  91. clear_list_messages(&level);
  92. for (element = list.head; element; element = element->next)
  93. if (GNUNET_YES == check_member_session_history(session, &(element->hash), GNUNET_YES))
  94. break;
  95. if (element)
  96. if (0 != GNUNET_CRYPTO_hash_cmp(&(element->hash), start))
  97. add_to_list_messages(&level, &(element->hash));
  98. else
  99. session->completed = GNUNET_YES;
  100. else
  101. copy_list_messages(&level, &list);
  102. clear_list_messages(&list);
  103. }
  104. completion:
  105. if (GNUNET_YES == is_member_session_completed(session))
  106. {
  107. GNUNET_CONTAINER_multihashmap_destroy (session->history);
  108. struct GNUNET_MESSENGER_ContactStore *store = get_member_contact_store(session->member->store);
  109. if ((session->contact) && (GNUNET_YES == decrease_contact_rc (session->contact)))
  110. remove_store_contact (
  111. store,
  112. session->contact,
  113. get_member_session_context(session)
  114. );
  115. session->contact = NULL;
  116. }
  117. }
  118. static int
  119. iterate_copy_history (void *cls,
  120. const struct GNUNET_HashCode *key,
  121. void *value)
  122. {
  123. struct GNUNET_MESSENGER_MemberSession *next = cls;
  124. GNUNET_CONTAINER_multihashmap_put(next->history, key, (value? next : NULL),
  125. GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
  126. return GNUNET_YES;
  127. }
  128. struct GNUNET_MESSENGER_MemberSession*
  129. switch_member_session (struct GNUNET_MESSENGER_MemberSession *session,
  130. const struct GNUNET_MESSENGER_Message *message,
  131. const struct GNUNET_HashCode *hash)
  132. {
  133. if ((!session) || (!message) || (!hash))
  134. return NULL;
  135. GNUNET_assert((GNUNET_MESSENGER_KIND_ID == message->header.kind) ||
  136. (GNUNET_MESSENGER_KIND_KEY == message->header.kind));
  137. struct GNUNET_MESSENGER_MemberSession *next = GNUNET_new(struct GNUNET_MESSENGER_MemberSession);
  138. if (GNUNET_MESSENGER_KIND_ID == message->header.kind)
  139. next->member = add_store_member(session->member->store, &(message->body.id.id));
  140. else
  141. next->member = session->member;
  142. if (GNUNET_MESSENGER_KIND_KEY == message->header.kind)
  143. GNUNET_memcpy(&(next->public_key), &(message->body.key.key), sizeof(next->public_key));
  144. else
  145. GNUNET_memcpy(&(next->public_key), get_member_session_public_key(session), sizeof(next->public_key));
  146. get_context_from_member (
  147. get_member_session_key (next),
  148. get_member_session_id (next),
  149. &(next->context)
  150. );
  151. update_store_contact(
  152. get_member_contact_store(next->member->store),
  153. get_member_session_contact(session),
  154. get_member_session_context(session),
  155. get_member_session_context(next),
  156. get_member_session_public_key(next)
  157. );
  158. next->contact = get_member_session_contact(session);
  159. if (!(next->contact))
  160. {
  161. GNUNET_free(next);
  162. return NULL;
  163. }
  164. increase_contact_rc (next->contact);
  165. next->history = GNUNET_CONTAINER_multihashmap_create(
  166. GNUNET_CONTAINER_multihashmap_size(session->history), GNUNET_NO
  167. );
  168. GNUNET_CONTAINER_multihashmap_iterate(session->history, iterate_copy_history, next);
  169. init_list_messages(&(next->messages));
  170. copy_list_messages(&(next->messages), &(session->messages));
  171. session->next = next;
  172. next->prev = session;
  173. next->next = NULL;
  174. next->start = GNUNET_TIME_absolute_get();
  175. session->closed = GNUNET_YES;
  176. next->closed = GNUNET_NO;
  177. next->completed = GNUNET_NO;
  178. check_member_session_completion (session);
  179. return next;
  180. }
  181. void
  182. destroy_member_session(struct GNUNET_MESSENGER_MemberSession* session)
  183. {
  184. GNUNET_assert (session);
  185. GNUNET_CONTAINER_multihashmap_destroy (session->history);
  186. clear_list_messages (&(session->messages));
  187. struct GNUNET_MESSENGER_Contact *contact = get_member_session_contact (session);
  188. if ((contact) && (GNUNET_YES == decrease_contact_rc (contact)))
  189. remove_store_contact (
  190. get_member_contact_store(session->member->store),
  191. contact,
  192. get_member_session_context(session)
  193. );
  194. GNUNET_free(session);
  195. }
  196. int
  197. reset_member_session (struct GNUNET_MESSENGER_MemberSession* session,
  198. const struct GNUNET_HashCode *hash)
  199. {
  200. GNUNET_assert ((session) && (hash));
  201. struct GNUNET_MESSENGER_ContactStore *store = get_member_contact_store(session->member->store);
  202. struct GNUNET_MESSENGER_Contact *contact = get_store_contact(
  203. store,
  204. get_member_session_context (session),
  205. get_member_session_public_key (session)
  206. );
  207. if (!contact)
  208. return GNUNET_SYSERR;
  209. if (contact == session->contact)
  210. goto clear_messages;
  211. session->contact = contact;
  212. increase_contact_rc (session->contact);
  213. clear_messages:
  214. clear_list_messages(&(session->messages));
  215. add_to_list_messages(&(session->messages), hash);
  216. session->next = NULL;
  217. session->closed = GNUNET_NO;
  218. session->completed = GNUNET_NO;
  219. return GNUNET_OK;
  220. }
  221. void
  222. close_member_session (struct GNUNET_MESSENGER_MemberSession* session)
  223. {
  224. GNUNET_assert (session);
  225. session->closed = GNUNET_YES;
  226. check_member_session_completion (session);
  227. }
  228. int
  229. is_member_session_closed (const struct GNUNET_MESSENGER_MemberSession* session)
  230. {
  231. GNUNET_assert(session);
  232. return session->closed;
  233. }
  234. int
  235. is_member_session_completed (const struct GNUNET_MESSENGER_MemberSession* session)
  236. {
  237. GNUNET_assert(session);
  238. return session->completed;
  239. }
  240. struct GNUNET_TIME_Absolute
  241. get_member_session_start (const struct GNUNET_MESSENGER_MemberSession* session)
  242. {
  243. GNUNET_assert(session);
  244. if (session->prev)
  245. return get_member_session_start(session->prev);
  246. return session->start;
  247. }
  248. const struct GNUNET_HashCode*
  249. get_member_session_key (const struct GNUNET_MESSENGER_MemberSession* session)
  250. {
  251. GNUNET_assert((session) && (session->member));
  252. return get_member_store_key(session->member->store);
  253. }
  254. const struct GNUNET_ShortHashCode*
  255. get_member_session_id (const struct GNUNET_MESSENGER_MemberSession* session)
  256. {
  257. GNUNET_assert(session);
  258. return get_member_id(session->member);
  259. }
  260. const struct GNUNET_IDENTITY_PublicKey*
  261. get_member_session_public_key (const struct GNUNET_MESSENGER_MemberSession* session)
  262. {
  263. GNUNET_assert(session);
  264. return &(session->public_key);
  265. }
  266. const struct GNUNET_HashCode*
  267. get_member_session_context (const struct GNUNET_MESSENGER_MemberSession* session)
  268. {
  269. GNUNET_assert(session);
  270. return &(session->context);
  271. }
  272. struct GNUNET_MESSENGER_Contact*
  273. get_member_session_contact (struct GNUNET_MESSENGER_MemberSession* session)
  274. {
  275. GNUNET_assert (session);
  276. return session->contact;
  277. }
  278. int verify_member_session_as_sender (const struct GNUNET_MESSENGER_MemberSession *session,
  279. const struct GNUNET_MESSENGER_Message *message,
  280. const struct GNUNET_HashCode *hash)
  281. {
  282. GNUNET_assert((session) && (message) && (hash));
  283. if (GNUNET_YES == is_member_session_completed(session))
  284. return GNUNET_SYSERR;
  285. if (0 != GNUNET_memcmp(get_member_session_id(session), &(message->header.sender_id)))
  286. return GNUNET_SYSERR;
  287. return verify_message(message, hash, get_member_session_public_key(session));
  288. }
  289. int
  290. check_member_session_history (const struct GNUNET_MESSENGER_MemberSession *session,
  291. const struct GNUNET_HashCode *hash, int ownership)
  292. {
  293. GNUNET_assert((session) && (hash));
  294. if (GNUNET_YES == ownership)
  295. return (NULL != GNUNET_CONTAINER_multihashmap_get(session->history, hash)? GNUNET_YES : GNUNET_NO);
  296. else
  297. return GNUNET_CONTAINER_multihashmap_contains(session->history, hash);
  298. }
  299. static void
  300. update_member_chain_history (struct GNUNET_MESSENGER_MemberSession *session,
  301. const struct GNUNET_HashCode *hash, int ownership)
  302. {
  303. GNUNET_assert ((session) && (hash));
  304. if ((GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(session->history, hash, (GNUNET_YES == ownership? session : NULL),
  305. GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) && (session->next))
  306. update_member_chain_history (session->next, hash, ownership);
  307. }
  308. void
  309. update_member_session_history (struct GNUNET_MESSENGER_MemberSession *session,
  310. const struct GNUNET_MESSENGER_Message *message,
  311. const struct GNUNET_HashCode *hash)
  312. {
  313. GNUNET_assert((session) && (message) && (hash));
  314. if (GNUNET_YES == is_member_session_completed(session))
  315. return;
  316. GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Updating sessions history (%s) += (%s)\n",
  317. GNUNET_sh2s(get_member_session_id(session)), GNUNET_h2s(hash));
  318. if (GNUNET_OK == verify_member_session_as_sender (session, message, hash))
  319. {
  320. if (GNUNET_YES == is_message_session_bound (message))
  321. add_to_list_messages(&(session->messages), hash);
  322. update_member_chain_history (session, hash, GNUNET_YES);
  323. }
  324. else
  325. update_member_chain_history (session, hash, GNUNET_NO);
  326. if (GNUNET_YES == session->closed)
  327. check_member_session_completion(session);
  328. }
  329. static void
  330. clear_member_chain_history (struct GNUNET_MESSENGER_MemberSession *session,
  331. const struct GNUNET_HashCode *hash)
  332. {
  333. GNUNET_assert ((session) && (hash));
  334. if ((0 < GNUNET_CONTAINER_multihashmap_remove_all(session->history, hash)) && (session->next))
  335. clear_member_session_history(session->next, hash);
  336. }
  337. void
  338. clear_member_session_history (struct GNUNET_MESSENGER_MemberSession *session,
  339. const struct GNUNET_HashCode *hash)
  340. {
  341. GNUNET_assert((session) && (hash));
  342. clear_member_chain_history (session, hash);
  343. }
  344. struct GNUNET_MESSENGER_MemberSessionHistoryEntry
  345. {
  346. struct GNUNET_HashCode hash;
  347. unsigned char ownership;
  348. };
  349. static void
  350. load_member_session_history (struct GNUNET_MESSENGER_MemberSession *session,
  351. const char *path)
  352. {
  353. GNUNET_assert((session) && (path));
  354. if (GNUNET_YES != GNUNET_DISK_file_test (path))
  355. return;
  356. enum GNUNET_DISK_AccessPermissions permission = (GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE);
  357. struct GNUNET_DISK_FileHandle *handle = GNUNET_DISK_file_open(
  358. path, GNUNET_DISK_OPEN_READ, permission
  359. );
  360. if (!handle)
  361. return;
  362. GNUNET_DISK_file_seek(handle, 0, GNUNET_DISK_SEEK_SET);
  363. struct GNUNET_MESSENGER_MemberSessionHistoryEntry entry;
  364. ssize_t len;
  365. int status;
  366. do {
  367. len = GNUNET_DISK_file_read(handle, &(entry.hash), sizeof(entry.hash));
  368. if (len != sizeof(entry.hash))
  369. break;
  370. len = GNUNET_DISK_file_read(handle, &(entry.ownership), sizeof(entry.ownership));
  371. if (len != sizeof(entry.ownership))
  372. break;
  373. status = GNUNET_CONTAINER_multihashmap_put(session->history, &(entry.hash), (entry.ownership? session : NULL),
  374. GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
  375. } while (status == GNUNET_OK);
  376. GNUNET_DISK_file_close(handle);
  377. }
  378. void
  379. load_member_session (struct GNUNET_MESSENGER_Member *member,
  380. const char *directory)
  381. {
  382. GNUNET_assert ((member) && (directory));
  383. char *config_file;
  384. GNUNET_asprintf (&config_file, "%s%s", directory, "session.cfg");
  385. struct GNUNET_MESSENGER_MemberSession *session = NULL;
  386. if (GNUNET_YES != GNUNET_DISK_file_test (config_file))
  387. goto free_config;
  388. struct GNUNET_CONFIGURATION_Handle *cfg = GNUNET_CONFIGURATION_create ();
  389. if (GNUNET_OK == GNUNET_CONFIGURATION_parse (cfg, config_file))
  390. {
  391. char *key_data;
  392. if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string(cfg, "session", "key", &key_data))
  393. goto destroy_config;
  394. struct GNUNET_IDENTITY_PublicKey key;
  395. enum GNUNET_GenericReturnValue key_return = GNUNET_IDENTITY_public_key_from_string(key_data, &key);
  396. GNUNET_free(key_data);
  397. if (GNUNET_OK != key_return)
  398. goto destroy_config;
  399. session = create_member_session(member, &key);
  400. unsigned long long numeric_value;
  401. if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg, "session", "start", &numeric_value))
  402. session->start.abs_value_us = numeric_value;
  403. if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg, "session", "closed", &numeric_value))
  404. session->closed = (GNUNET_YES == numeric_value? GNUNET_YES : GNUNET_NO);
  405. if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg, "session", "completed", &numeric_value))
  406. session->completed = (GNUNET_YES == numeric_value? GNUNET_YES : GNUNET_NO);
  407. }
  408. destroy_config:
  409. GNUNET_CONFIGURATION_destroy (cfg);
  410. free_config:
  411. GNUNET_free(config_file);
  412. if (!session)
  413. return;
  414. char *history_file;
  415. GNUNET_asprintf (&history_file, "%s%s", directory, "history.map");
  416. load_member_session_history (session, history_file);
  417. GNUNET_free(history_file);
  418. char *messages_file;
  419. GNUNET_asprintf (&messages_file, "%s%s", directory, "messages.list");
  420. load_list_messages(&(session->messages), messages_file);
  421. GNUNET_free(messages_file);
  422. add_member_session(member, session);
  423. }
  424. static struct GNUNET_MESSENGER_MemberSession*
  425. get_cycle_safe_next_session (struct GNUNET_MESSENGER_MemberSession *session,
  426. struct GNUNET_MESSENGER_MemberSession *next)
  427. {
  428. if (!next)
  429. return NULL;
  430. struct GNUNET_MESSENGER_MemberSession *check = next;
  431. do {
  432. if (check == session)
  433. return NULL;
  434. check = check->next;
  435. } while (check);
  436. return next;
  437. }
  438. void
  439. load_member_session_next (struct GNUNET_MESSENGER_MemberSession *session,
  440. const char *directory)
  441. {
  442. GNUNET_assert ((session) && (directory));
  443. char *config_file;
  444. GNUNET_asprintf (&config_file, "%s%s", directory, "session.cfg");
  445. if (GNUNET_YES != GNUNET_DISK_file_test (config_file))
  446. goto free_config;
  447. struct GNUNET_CONFIGURATION_Handle *cfg = GNUNET_CONFIGURATION_create ();
  448. if (GNUNET_OK == GNUNET_CONFIGURATION_parse (cfg, config_file))
  449. {
  450. char *key_data;
  451. if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string(cfg, "session", "next_key", &key_data))
  452. goto destroy_config;
  453. struct GNUNET_IDENTITY_PublicKey next_key;
  454. enum GNUNET_GenericReturnValue key_return = GNUNET_IDENTITY_public_key_from_string(key_data, &next_key);
  455. GNUNET_free(key_data);
  456. if (GNUNET_OK != key_return)
  457. goto destroy_config;
  458. struct GNUNET_ShortHashCode next_id;
  459. if (GNUNET_OK != GNUNET_CONFIGURATION_get_data (cfg, "session", "next_id", &next_id, sizeof(next_id)))
  460. goto destroy_config;
  461. struct GNUNET_MESSENGER_Member *member = get_store_member(session->member->store, &next_id);
  462. session->next = get_cycle_safe_next_session(
  463. session, member? get_member_session (member, &next_key) : NULL
  464. );
  465. if (session->next)
  466. session->next->prev = session;
  467. }
  468. destroy_config:
  469. GNUNET_CONFIGURATION_destroy (cfg);
  470. free_config:
  471. GNUNET_free(config_file);
  472. }
  473. static int
  474. iterate_save_member_session_history_hentries (void *cls,
  475. const struct GNUNET_HashCode *key,
  476. void *value)
  477. {
  478. struct GNUNET_DISK_FileHandle *handle = cls;
  479. unsigned char ownership = value? GNUNET_YES : GNUNET_NO;
  480. GNUNET_DISK_file_write(handle, key, sizeof(*key));
  481. GNUNET_DISK_file_write(handle, &ownership, sizeof(ownership));
  482. return GNUNET_YES;
  483. }
  484. static void
  485. save_member_session_history (struct GNUNET_MESSENGER_MemberSession *session,
  486. const char *path)
  487. {
  488. GNUNET_assert((session) && (path));
  489. enum GNUNET_DISK_AccessPermissions permission = (GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE);
  490. struct GNUNET_DISK_FileHandle *handle = GNUNET_DISK_file_open(
  491. path, GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_WRITE, permission
  492. );
  493. if (!handle)
  494. return;
  495. GNUNET_DISK_file_seek(handle, 0, GNUNET_DISK_SEEK_SET);
  496. GNUNET_CONTAINER_multihashmap_iterate(
  497. session->history,
  498. iterate_save_member_session_history_hentries,
  499. handle
  500. );
  501. GNUNET_DISK_file_sync(handle);
  502. GNUNET_DISK_file_close(handle);
  503. }
  504. void
  505. save_member_session (struct GNUNET_MESSENGER_MemberSession *session,
  506. const char *directory)
  507. {
  508. GNUNET_assert ((session) && (directory));
  509. char *config_file;
  510. GNUNET_asprintf (&config_file, "%s%s", directory, "session.cfg");
  511. struct GNUNET_CONFIGURATION_Handle *cfg = GNUNET_CONFIGURATION_create ();
  512. char *key_data = GNUNET_IDENTITY_public_key_to_string(get_member_session_public_key(session));
  513. if (key_data)
  514. {
  515. GNUNET_CONFIGURATION_set_value_string (cfg, "session", "key", key_data);
  516. GNUNET_free(key_data);
  517. }
  518. if (session->next)
  519. {
  520. const struct GNUNET_ShortHashCode *next_id = get_member_session_id(session->next);
  521. char *next_id_data = GNUNET_STRINGS_data_to_string_alloc (next_id, sizeof(*next_id));
  522. if (next_id_data)
  523. {
  524. GNUNET_CONFIGURATION_set_value_string (cfg, "session", "next_id", next_id_data);
  525. GNUNET_free(next_id_data);
  526. }
  527. key_data = GNUNET_IDENTITY_public_key_to_string(get_member_session_public_key(session->next));
  528. if (key_data)
  529. {
  530. GNUNET_CONFIGURATION_set_value_string (cfg, "session", "next_key", key_data);
  531. GNUNET_free(key_data);
  532. }
  533. }
  534. GNUNET_CONFIGURATION_set_value_number(cfg, "session", "start", session->start.abs_value_us);
  535. GNUNET_CONFIGURATION_set_value_number (cfg, "session", "closed", session->closed);
  536. GNUNET_CONFIGURATION_set_value_number (cfg, "session", "completed", session->completed);
  537. GNUNET_CONFIGURATION_write (cfg, config_file);
  538. GNUNET_CONFIGURATION_destroy (cfg);
  539. GNUNET_free(config_file);
  540. char *history_file;
  541. GNUNET_asprintf (&history_file, "%s%s", directory, "history.map");
  542. save_member_session_history (session, history_file);
  543. GNUNET_free(history_file);
  544. char *messages_file;
  545. GNUNET_asprintf (&messages_file, "%s%s", directory, "messages.list");
  546. save_list_messages(&(session->messages), messages_file);
  547. GNUNET_free(messages_file);
  548. }