aboutsummaryrefslogtreecommitdiff
path: root/src/messenger/gnunet-service-messenger_message_store.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/messenger/gnunet-service-messenger_message_store.c')
-rw-r--r--src/messenger/gnunet-service-messenger_message_store.c582
1 files changed, 0 insertions, 582 deletions
diff --git a/src/messenger/gnunet-service-messenger_message_store.c b/src/messenger/gnunet-service-messenger_message_store.c
deleted file mode 100644
index ddad266ad..000000000
--- a/src/messenger/gnunet-service-messenger_message_store.c
+++ /dev/null
@@ -1,582 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--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_message_store.c
23 * @brief GNUnet MESSENGER service
24 */
25
26#include "gnunet-service-messenger_message_store.h"
27#include "messenger_api_message.h"
28
29void
30init_message_store (struct GNUNET_MESSENGER_MessageStore *store)
31{
32 GNUNET_assert(store);
33
34 store->storage_messages = NULL;
35
36 store->entries = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
37 store->messages = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
38 store->links = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
39
40 store->rewrite_entries = GNUNET_NO;
41 store->write_links = GNUNET_NO;
42}
43
44static int
45iterate_destroy_entries (void *cls,
46 const struct GNUNET_HashCode *key,
47 void *value)
48{
49 struct GNUNET_MESSENGER_MessageEntry *entry = value;
50
51 GNUNET_free(entry);
52
53 return GNUNET_YES;
54}
55
56static int
57iterate_destroy_messages (void *cls,
58 const struct GNUNET_HashCode *key,
59 void *value)
60{
61 struct GNUNET_MESSENGER_Message *message = value;
62
63 destroy_message (message);
64
65 return GNUNET_YES;
66}
67
68static int
69iterate_destroy_links (void *cls,
70 const struct GNUNET_HashCode *key,
71 void *value)
72{
73 struct GNUNET_HashCode *previous = value;
74
75 GNUNET_free(previous);
76
77 return GNUNET_YES;
78}
79
80void
81clear_message_store (struct GNUNET_MESSENGER_MessageStore *store)
82{
83 GNUNET_assert(store);
84
85 if (store->storage_messages)
86 {
87 GNUNET_DISK_file_close (store->storage_messages);
88
89 store->storage_messages = NULL;
90 }
91
92 GNUNET_CONTAINER_multihashmap_iterate (store->entries, iterate_destroy_entries, NULL);
93 GNUNET_CONTAINER_multihashmap_iterate (store->messages, iterate_destroy_messages, NULL);
94 GNUNET_CONTAINER_multihashmap_iterate (store->links, iterate_destroy_links, NULL);
95
96 GNUNET_CONTAINER_multihashmap_destroy (store->entries);
97 GNUNET_CONTAINER_multihashmap_destroy (store->messages);
98 GNUNET_CONTAINER_multihashmap_destroy (store->links);
99}
100
101struct GNUNET_MESSENGER_MessageEntryStorage
102{
103 struct GNUNET_HashCode hash;
104 struct GNUNET_MESSENGER_MessageEntry entry;
105};
106
107#define load_message_store_attribute_failed(file, attribute) \
108 sizeof(attribute) != GNUNET_DISK_file_read(file, &(attribute), sizeof(attribute))
109
110#define save_message_store_attribute_failed(file, attribute) \
111 sizeof(attribute) != GNUNET_DISK_file_write(file, &(attribute), sizeof(attribute))
112
113static void
114load_message_store_entries (struct GNUNET_MESSENGER_MessageStore *store,
115 const char *filename)
116{
117 enum GNUNET_DISK_AccessPermissions permission = (GNUNET_DISK_PERM_USER_READ);
118
119 struct GNUNET_DISK_FileHandle *entries = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ, permission);
120
121 if (!entries)
122 return;
123
124 struct GNUNET_MESSENGER_MessageEntryStorage storage;
125 struct GNUNET_MESSENGER_MessageEntry *entry;
126
127 memset(&storage, 0, sizeof(storage));
128
129 do
130 {
131 entry = NULL;
132
133 if ((load_message_store_attribute_failed(entries, storage.hash)) ||
134 (load_message_store_attribute_failed(entries, storage.entry.offset)) ||
135 (load_message_store_attribute_failed(entries, storage.entry.length)))
136 break;
137
138 entry = GNUNET_new(struct GNUNET_MESSENGER_MessageEntry);
139
140 GNUNET_memcpy(entry, &(storage.entry), sizeof(*entry));
141
142 if ((GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (store->entries, &(storage.hash))) ||
143 (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (store->entries, &(storage.hash), entry,
144 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)))
145 {
146 store->rewrite_entries = GNUNET_YES;
147 break;
148 }
149 }
150 while (entry);
151
152 if (entry)
153 GNUNET_free(entry);
154
155 GNUNET_DISK_file_close (entries);
156}
157
158struct GNUNET_MESSENGER_MessageLinkStorage
159{
160 struct GNUNET_HashCode hash;
161 struct GNUNET_MESSENGER_MessageLink link;
162};
163
164static void
165load_message_store_links (struct GNUNET_MESSENGER_MessageStore *store,
166 const char *filename)
167{
168 enum GNUNET_DISK_AccessPermissions permission = (GNUNET_DISK_PERM_USER_READ);
169
170 struct GNUNET_DISK_FileHandle *entries = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ, permission);
171
172 if (!entries)
173 return;
174
175 struct GNUNET_MESSENGER_MessageLinkStorage storage;
176 struct GNUNET_MESSENGER_MessageLink *link;
177
178 memset(&storage, 0, sizeof(storage));
179
180 do
181 {
182 link = NULL;
183
184 if ((load_message_store_attribute_failed(entries, storage.hash)) ||
185 (load_message_store_attribute_failed(entries, storage.link.multiple)) ||
186 (load_message_store_attribute_failed(entries, storage.link.first)) ||
187 ((GNUNET_YES == storage.link.multiple) &&
188 (load_message_store_attribute_failed(entries, storage.link.second))))
189 break;
190
191 link = GNUNET_new(struct GNUNET_MESSENGER_MessageLink);
192
193 GNUNET_memcpy(link, &(storage.link), sizeof(*link));
194
195 if ((GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (store->links, &(storage.hash))) ||
196 (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (store->links, &(storage.hash), link,
197 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)))
198 break;
199 }
200 while (link);
201
202 if (link)
203 GNUNET_free(link);
204
205 GNUNET_DISK_file_close (entries);
206}
207
208void
209load_message_store (struct GNUNET_MESSENGER_MessageStore *store,
210 const char *directory)
211{
212 GNUNET_assert((store) && (directory));
213
214 enum GNUNET_DISK_AccessPermissions permission = (GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE);
215
216 if (store->storage_messages)
217 GNUNET_DISK_file_close (store->storage_messages);
218
219 char *filename;
220 GNUNET_asprintf (&filename, "%s%s", directory, "messages.store");
221
222 if (GNUNET_YES == GNUNET_DISK_file_test (filename))
223 store->storage_messages = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READWRITE, permission);
224 else
225 store->storage_messages = NULL;
226
227 GNUNET_free(filename);
228
229 if (!store->storage_messages)
230 return;
231
232 GNUNET_asprintf (&filename, "%s%s", directory, "entries.store");
233
234 if (GNUNET_YES == GNUNET_DISK_file_test (filename))
235 load_message_store_entries(store, filename);
236
237 GNUNET_free(filename);
238
239 GNUNET_asprintf (&filename, "%s%s", directory, "links.store");
240
241 if (GNUNET_YES == GNUNET_DISK_file_test (filename))
242 load_message_store_links(store, filename);
243
244 GNUNET_free(filename);
245}
246
247struct GNUNET_MESSENGER_ClosureMessageSave
248{
249 struct GNUNET_MESSENGER_MessageStore *store;
250
251 struct GNUNET_DISK_FileHandle *storage;
252};
253
254static int
255iterate_save_entries (void *cls,
256 const struct GNUNET_HashCode *key,
257 void *value)
258{
259 struct GNUNET_MESSENGER_ClosureMessageSave *save = cls;
260 struct GNUNET_MESSENGER_MessageEntry *entry = value;
261
262 struct GNUNET_MESSENGER_MessageEntryStorage storage;
263
264 GNUNET_DISK_file_write (save->storage, key, sizeof(*key));
265 GNUNET_DISK_file_write (save->storage, &(entry->offset), sizeof(entry->offset));
266 GNUNET_DISK_file_write (save->storage, &(entry->length), sizeof(entry->length));
267
268 return GNUNET_YES;
269}
270
271static int
272iterate_save_messages (void *cls,
273 const struct GNUNET_HashCode *key,
274 void *value)
275{
276 struct GNUNET_MESSENGER_ClosureMessageSave *save = cls;
277
278 if (GNUNET_NO != GNUNET_CONTAINER_multihashmap_contains (save->store->entries, key))
279 return GNUNET_YES;
280
281 struct GNUNET_MESSENGER_Message *message = value;
282 struct GNUNET_MESSENGER_MessageEntryStorage storage;
283
284 GNUNET_memcpy(&(storage.hash), key, sizeof(storage.hash));
285
286 storage.entry.length = get_message_size (message, GNUNET_YES);
287 storage.entry.offset = GNUNET_DISK_file_seek (save->store->storage_messages, 0, GNUNET_DISK_SEEK_END);
288
289 if ((GNUNET_SYSERR == storage.entry.offset) ||
290 (save_message_store_attribute_failed(save->storage, storage.hash)) ||
291 (save_message_store_attribute_failed(save->storage, storage.entry.offset)) ||
292 (save_message_store_attribute_failed(save->storage, storage.entry.length)))
293 return GNUNET_YES;
294
295 char *buffer = GNUNET_malloc(storage.entry.length);
296
297 encode_message (message, storage.entry.length, buffer, GNUNET_YES);
298
299 GNUNET_DISK_file_write (save->store->storage_messages, buffer, storage.entry.length);
300
301 GNUNET_free(buffer);
302 return GNUNET_YES;
303}
304
305static int
306iterate_save_links (void *cls,
307 const struct GNUNET_HashCode *key,
308 void *value)
309{
310 struct GNUNET_MESSENGER_ClosureMessageSave *save = cls;
311 struct GNUNET_MESSENGER_MessageLink *link = value;
312
313 GNUNET_DISK_file_write (save->storage, key, sizeof(*key));
314 GNUNET_DISK_file_write (save->storage, &(link->multiple), sizeof(link->multiple));
315 GNUNET_DISK_file_write (save->storage, &(link->first), sizeof(link->first));
316
317 if (GNUNET_YES == link->multiple)
318 GNUNET_DISK_file_write (save->storage, &(link->second), sizeof(link->second));
319
320 return GNUNET_YES;
321}
322
323void
324save_message_store (struct GNUNET_MESSENGER_MessageStore *store,
325 const char *directory)
326{
327 GNUNET_assert((store) && (directory));
328
329 struct GNUNET_MESSENGER_ClosureMessageSave save;
330
331 enum GNUNET_DISK_AccessPermissions permission = (GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE);
332
333 char *filename;
334
335 if (GNUNET_YES != store->write_links)
336 goto save_entries;
337
338 GNUNET_asprintf (&filename, "%s%s", directory, "links.store");
339
340 save.store = store;
341 save.storage = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE, permission);
342
343 GNUNET_free(filename);
344
345 if (!save.storage)
346 goto save_entries;
347
348 if (GNUNET_SYSERR == GNUNET_DISK_file_seek (save.storage, 0, GNUNET_DISK_SEEK_SET))
349 goto close_links;
350
351 GNUNET_CONTAINER_multihashmap_iterate (store->links, iterate_save_links, &save);
352 store->write_links = GNUNET_NO;
353
354close_links:
355 GNUNET_DISK_file_close (save.storage);
356
357save_entries:
358 GNUNET_asprintf (&filename, "%s%s", directory, "entries.store");
359
360 save.store = store;
361 save.storage = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE, permission);
362
363 GNUNET_free(filename);
364
365 if (!save.storage)
366 return;
367
368 if (GNUNET_YES == store->rewrite_entries)
369 {
370 if (GNUNET_SYSERR == GNUNET_DISK_file_seek (save.storage, 0, GNUNET_DISK_SEEK_SET))
371 goto close_entries;
372
373 GNUNET_CONTAINER_multihashmap_iterate (store->entries, iterate_save_entries, &save);
374 store->rewrite_entries = GNUNET_NO;
375 }
376 else if (GNUNET_SYSERR == GNUNET_DISK_file_seek (save.storage, 0, GNUNET_DISK_SEEK_END))
377 goto close_entries;
378
379 if (store->storage_messages)
380 GNUNET_DISK_file_close (store->storage_messages);
381
382 GNUNET_asprintf (&filename, "%s%s", directory, "messages.store");
383
384 store->storage_messages = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READWRITE | GNUNET_DISK_OPEN_CREATE,
385 permission);
386
387 GNUNET_free(filename);
388
389 if (store->storage_messages)
390 {
391 GNUNET_CONTAINER_multihashmap_iterate (store->messages, iterate_save_messages, &save);
392
393 GNUNET_DISK_file_sync (store->storage_messages);
394 GNUNET_DISK_file_sync (save.storage);
395 }
396
397close_entries:
398 GNUNET_DISK_file_close (save.storage);
399}
400
401int
402contains_store_message (const struct GNUNET_MESSENGER_MessageStore *store,
403 const struct GNUNET_HashCode *hash)
404{
405 GNUNET_assert((store) && (hash));
406
407 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (store->messages, hash))
408 return GNUNET_YES;
409
410 return GNUNET_CONTAINER_multihashmap_contains (store->entries, hash);
411}
412
413const struct GNUNET_MESSENGER_Message*
414get_store_message (struct GNUNET_MESSENGER_MessageStore *store,
415 const struct GNUNET_HashCode *hash)
416{
417 GNUNET_assert((store) && (hash));
418
419 struct GNUNET_MESSENGER_Message *message = GNUNET_CONTAINER_multihashmap_get (store->messages, hash);
420
421 if (message)
422 return message;
423
424 if (!store->storage_messages)
425 return NULL;
426
427 const struct GNUNET_MESSENGER_MessageEntry *entry = GNUNET_CONTAINER_multihashmap_get (store->entries, hash);
428
429 if (!entry)
430 return NULL;
431
432 if (entry->offset != GNUNET_DISK_file_seek (store->storage_messages, entry->offset, GNUNET_DISK_SEEK_SET))
433 return message;
434
435 char *buffer = GNUNET_malloc(entry->length);
436
437 if (!buffer)
438 return NULL;
439
440 if ((GNUNET_DISK_file_read (store->storage_messages, buffer, entry->length) != entry->length) ||
441 (entry->length < get_message_kind_size(GNUNET_MESSENGER_KIND_UNKNOWN, GNUNET_YES)))
442 goto free_buffer;
443
444 message = create_message (GNUNET_MESSENGER_KIND_UNKNOWN);
445
446 const int decoding = decode_message (message, entry->length, buffer, GNUNET_YES, NULL);
447
448 struct GNUNET_HashCode check;
449 hash_message (message, entry->length, buffer, &check);
450
451 if ((GNUNET_YES != decoding) || (GNUNET_CRYPTO_hash_cmp (hash, &check) != 0))
452 {
453 if (GNUNET_YES != GNUNET_CONTAINER_multihashmap_remove (store->entries, hash, entry))
454 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Corrupted entry could not be removed from store: %s\n",
455 GNUNET_h2s(hash));
456
457 store->rewrite_entries = GNUNET_YES;
458
459 goto free_message;
460 }
461
462 if (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (store->messages, hash, message,
463 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
464 goto free_buffer;
465
466free_message: destroy_message (message);
467 message = NULL;
468
469free_buffer:
470 GNUNET_free(buffer);
471
472 return message;
473}
474
475const struct GNUNET_MESSENGER_MessageLink*
476get_store_message_link (struct GNUNET_MESSENGER_MessageStore *store,
477 const struct GNUNET_HashCode *hash,
478 int deleted_only)
479{
480 if (deleted_only)
481 goto get_link;
482
483 const struct GNUNET_MESSENGER_Message *message = get_store_message(store, hash);
484
485 if (!message)
486 goto get_link;
487
488 static struct GNUNET_MESSENGER_MessageLink link;
489
490 GNUNET_memcpy(&(link.first), &(message->header.previous), sizeof(link.first));
491
492 link.multiple = GNUNET_MESSENGER_KIND_MERGE == message->header.kind? GNUNET_YES : GNUNET_NO;
493
494 if (GNUNET_YES == link.multiple)
495 GNUNET_memcpy(&(link.second), &(message->body.merge.previous), sizeof(link.second));
496 else
497 GNUNET_memcpy(&(link.second), &(message->header.previous), sizeof(link.second));
498
499 return &link;
500
501get_link:
502 return GNUNET_CONTAINER_multihashmap_get (store->links, hash);
503}
504
505int
506put_store_message (struct GNUNET_MESSENGER_MessageStore *store,
507 const struct GNUNET_HashCode *hash,
508 struct GNUNET_MESSENGER_Message *message)
509{
510 GNUNET_assert((store) && (hash) && (message));
511
512 return GNUNET_CONTAINER_multihashmap_put (store->messages, hash, message,
513 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
514}
515
516static void
517add_link (struct GNUNET_MESSENGER_MessageStore *store,
518 const struct GNUNET_HashCode *hash,
519 const struct GNUNET_MESSENGER_Message *message)
520{
521 struct GNUNET_MESSENGER_MessageLink *link = GNUNET_new(struct GNUNET_MESSENGER_MessageLink);
522
523 GNUNET_memcpy(&(link->first), &(message->header.previous), sizeof(link->first));
524
525 link->multiple = GNUNET_MESSENGER_KIND_MERGE == message->header.kind? GNUNET_YES : GNUNET_NO;
526
527 if (GNUNET_YES == link->multiple)
528 GNUNET_memcpy(&(link->second), &(message->body.merge.previous), sizeof(link->second));
529 else
530 GNUNET_memcpy(&(link->second), &(message->header.previous), sizeof(link->second));
531
532 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put(store->links, hash, link,
533 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
534 GNUNET_free(link);
535}
536
537int
538delete_store_message (struct GNUNET_MESSENGER_MessageStore *store,
539 const struct GNUNET_HashCode *hash)
540{
541 GNUNET_assert((store) && (hash));
542
543 const struct GNUNET_MESSENGER_MessageEntry *entry = GNUNET_CONTAINER_multihashmap_get (store->entries, hash);
544
545 if (!entry)
546 goto clear_memory;
547
548 const struct GNUNET_MESSENGER_Message *message = get_store_message(store, hash);
549
550 if (message)
551 add_link (store, hash, message);
552
553 if (!store->storage_messages)
554 goto clear_entry;
555
556 if (entry->offset != GNUNET_DISK_file_seek (store->storage_messages, entry->offset, GNUNET_DISK_SEEK_SET))
557 return GNUNET_SYSERR;
558
559 char *clear_buffer = GNUNET_malloc(entry->length);
560
561 if (!clear_buffer)
562 return GNUNET_SYSERR;
563
564 GNUNET_CRYPTO_zero_keys (clear_buffer, entry->length);
565
566 if ((entry->length != GNUNET_DISK_file_write (store->storage_messages, clear_buffer, entry->length)) || (GNUNET_OK
567 != GNUNET_DISK_file_sync (store->storage_messages)))
568 {
569 GNUNET_free(clear_buffer);
570 return GNUNET_SYSERR;
571 }
572
573 GNUNET_free(clear_buffer);
574
575clear_entry:
576 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (store->entries, hash, entry))
577 store->rewrite_entries = GNUNET_YES;
578
579clear_memory:
580 GNUNET_CONTAINER_multihashmap_remove_all (store->messages, hash);
581 return GNUNET_OK;
582}