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