GNUnet 0.21.1
gnunet-service-messenger_message_store.c
Go to the documentation of this file.
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020--2023 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 */
28
29void
31{
32 GNUNET_assert (store);
33
34 store->storage_messages = NULL;
35
39
41 store->write_links = GNUNET_NO;
42}
43
44
47 const struct GNUNET_HashCode *key,
48 void *value)
49{
51
52 GNUNET_free (entry);
53
54 return GNUNET_YES;
55}
56
57
60 const struct GNUNET_HashCode *key,
61 void *value)
62{
63 struct GNUNET_MESSENGER_Message *message = value;
64
65 destroy_message (message);
66
67 return GNUNET_YES;
68}
69
70
73 const struct GNUNET_HashCode *key,
74 void *value)
75{
76 struct GNUNET_HashCode *previous = value;
77
78 GNUNET_free (previous);
79
80 return GNUNET_YES;
81}
82
83
84void
86{
87 GNUNET_assert (store);
88
89 if (store->storage_messages)
90 {
92
93 store->storage_messages = NULL;
94 }
95
101 NULL);
102
106}
107
108
110{
113};
114
115#define load_message_store_attribute_failed(file, attribute) \
116 sizeof(attribute) != GNUNET_DISK_file_read (file, &(attribute), \
117 sizeof(attribute))
118
119#define save_message_store_attribute_failed(file, attribute) \
120 sizeof(attribute) != GNUNET_DISK_file_write (file, &(attribute), \
121 sizeof(attribute))
122
123static void
125 const char *filename)
126{
128
131 permission);
132
133 if (! entries)
134 return;
135
137 struct GNUNET_MESSENGER_MessageEntry *entry;
138
139 memset (&storage, 0, sizeof(storage));
140
141 do
142 {
143 entry = NULL;
144
145 if ((load_message_store_attribute_failed (entries, storage.hash)) ||
146 (load_message_store_attribute_failed (entries, storage.entry.offset)) ||
148 break;
149
151
152 GNUNET_memcpy (entry, &(storage.entry), sizeof(*entry));
153
155 &(storage.hash)))
156 ||
158 &(storage.hash), entry,
160 {
162 break;
163 }
164 }
165 while (entry);
166
167 if (entry)
168 GNUNET_free (entry);
169
170 GNUNET_DISK_file_close (entries);
171}
172
173
175{
178};
179
180static void
182 const char *filename)
183{
185
188 permission);
189
190 if (! entries)
191 return;
192
194 struct GNUNET_MESSENGER_MessageLink *link;
195
196 memset (&storage, 0, sizeof(storage));
197
198 do
199 {
200 link = NULL;
201
202 if ((load_message_store_attribute_failed (entries, storage.hash)) ||
204 storage.link.multiple)) ||
205 (load_message_store_attribute_failed (entries, storage.link.first)) ||
206 ((GNUNET_YES == storage.link.multiple) &&
207 (load_message_store_attribute_failed (entries, storage.link.second))))
208 break;
209
211
212 GNUNET_memcpy (link, &(storage.link), sizeof(*link));
213
215 &(storage.hash)))
216 ||
218 &(storage.hash), link,
220 break;
221 }
222 while (link);
223
224 if (link)
225 GNUNET_free (link);
226
227 GNUNET_DISK_file_close (entries);
228}
229
230
231void
233 const char *directory)
234{
235 GNUNET_assert ((store) && (directory));
236
239
240 if (store->storage_messages)
242
243 char *filename;
244 GNUNET_asprintf (&filename, "%s%s", directory, "messages.store");
245
249 permission);
250 else
251 store->storage_messages = NULL;
252
254
255 if (! store->storage_messages)
256 return;
257
258 GNUNET_asprintf (&filename, "%s%s", directory, "entries.store");
259
262
264
265 GNUNET_asprintf (&filename, "%s%s", directory, "links.store");
266
269
271}
272
273
275{
277
279};
280
283 const struct GNUNET_HashCode *key,
284 void *value)
285{
287 struct GNUNET_MESSENGER_MessageEntry *entry = value;
288
289 GNUNET_DISK_file_write (save->storage, key, sizeof(*key));
290 GNUNET_DISK_file_write (save->storage, &(entry->offset),
291 sizeof(entry->offset));
292 GNUNET_DISK_file_write (save->storage, &(entry->length),
293 sizeof(entry->length));
294
295 return GNUNET_YES;
296}
297
298
301 const struct GNUNET_HashCode *key,
302 void *value)
303{
305
307 key))
308 return GNUNET_YES;
309
310 struct GNUNET_MESSENGER_Message *message = value;
312
313 GNUNET_memcpy (&(storage.hash), key, sizeof(storage.hash));
314
315 storage.entry.length = get_message_size (message, GNUNET_YES);
316 storage.entry.offset = GNUNET_DISK_file_seek (save->store->storage_messages,
318
319 if ((GNUNET_SYSERR == storage.entry.offset) ||
320 (save_message_store_attribute_failed (save->storage, storage.hash)) ||
322 storage.entry.offset)) ||
324 storage.entry.length)))
325 return GNUNET_YES;
326
327 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Storing message with hash: %s\n",
328 GNUNET_h2s (&(storage.hash)));
329
330 char *buffer = GNUNET_malloc (storage.entry.length);
331
332 encode_message (message, storage.entry.length, buffer, GNUNET_YES);
333
334 GNUNET_DISK_file_write (save->store->storage_messages, buffer,
335 storage.entry.length);
336
337 GNUNET_free (buffer);
338 return GNUNET_YES;
339}
340
341
344 const struct GNUNET_HashCode *key,
345 void *value)
346{
348 struct GNUNET_MESSENGER_MessageLink *link = value;
349
350 GNUNET_DISK_file_write (save->storage, key, sizeof(*key));
351 GNUNET_DISK_file_write (save->storage, &(link->multiple),
352 sizeof(link->multiple));
353 GNUNET_DISK_file_write (save->storage, &(link->first), sizeof(link->first));
354
355 if (GNUNET_YES == link->multiple)
356 GNUNET_DISK_file_write (save->storage, &(link->second),
357 sizeof(link->second));
358
359 return GNUNET_YES;
360}
361
362
363void
365 const char *directory)
366{
367 GNUNET_assert ((store) && (directory));
368
370
373
374 char *filename;
375
377 goto save_entries;
378
379 GNUNET_asprintf (&filename, "%s%s", directory, "links.store");
380
381 save.store = store;
383 | GNUNET_DISK_OPEN_CREATE, permission);
384
386
387 if (! save.storage)
388 goto save_entries;
389
390 if (GNUNET_SYSERR == GNUNET_DISK_file_seek (save.storage, 0,
392 goto close_links;
393
395 &save);
397
398close_links:
400
401save_entries:
402 GNUNET_asprintf (&filename, "%s%s", directory, "entries.store");
403
404 save.store = store;
406 | GNUNET_DISK_OPEN_CREATE, permission);
407
409
410 if (! save.storage)
411 return;
412
414 {
415 if (GNUNET_SYSERR == GNUNET_DISK_file_seek (save.storage, 0,
417 goto close_entries;
418
420 &save);
422 }
423 else if (GNUNET_SYSERR == GNUNET_DISK_file_seek (save.storage, 0,
425 goto close_entries;
426
429
430 GNUNET_asprintf (&filename, "%s%s", directory, "messages.store");
431
435 permission);
436
438
440 {
443
445 GNUNET_DISK_file_sync (save.storage);
446 }
447
448close_entries:
450}
451
452
455 const struct GNUNET_HashCode *hash)
456{
457 GNUNET_assert ((store) && (hash));
458
460 hash))
461 return GNUNET_YES;
462
464}
465
466
467const struct GNUNET_MESSENGER_Message*
469 const struct GNUNET_HashCode *hash)
470{
471 GNUNET_assert ((store) && (hash));
472
474 store->messages, hash);
475
476 if (message)
477 return message;
478
479 if (! store->storage_messages)
480 return NULL;
481
482 const struct GNUNET_MESSENGER_MessageEntry *entry =
484
485 if (! entry)
486 return NULL;
487
488 if (entry->offset != GNUNET_DISK_file_seek (store->storage_messages,
489 entry->offset,
491 return message;
492
493 char *buffer = GNUNET_malloc (entry->length);
494
495 if (! buffer)
496 return NULL;
497
498 if ((GNUNET_DISK_file_read (store->storage_messages, buffer, entry->length) !=
499 entry->length) ||
501 GNUNET_YES)))
502 goto free_buffer;
503
505
506 enum GNUNET_GenericReturnValue decoding;
507 decoding = decode_message (message, entry->length, buffer,
508 GNUNET_YES, NULL);
509
510 struct GNUNET_HashCode check;
511 hash_message (message, entry->length, buffer, &check);
512
513 if ((GNUNET_YES != decoding) || (GNUNET_CRYPTO_hash_cmp (hash, &check) != 0))
514 {
516 hash, entry))
518 "Corrupted entry could not be removed from store: %s\n",
519 GNUNET_h2s (hash));
520
522
523 goto free_message;
524 }
525
527 message,
529 goto free_buffer;
530
531 free_message : destroy_message (message);
532 message = NULL;
533
534free_buffer:
535 GNUNET_free (buffer);
536
537 return message;
538}
539
540
543 const struct GNUNET_HashCode *hash,
544 enum GNUNET_GenericReturnValue deleted_only)
545{
546 if (deleted_only)
547 goto get_link;
548
549 const struct GNUNET_MESSENGER_Message *message = get_store_message (store,
550 hash);
551
552 if (! message)
553 goto get_link;
554
555 static struct GNUNET_MESSENGER_MessageLink link;
556
557 GNUNET_memcpy (&(link.first), &(message->header.previous),
558 sizeof(link.first));
559
562
563 if (GNUNET_YES == link.multiple)
564 GNUNET_memcpy (&(link.second), &(message->body.merge.previous),
565 sizeof(link.second));
566 else
567 GNUNET_memcpy (&(link.second), &(message->header.previous),
568 sizeof(link.second));
569
570 return &link;
571
572get_link:
573 return GNUNET_CONTAINER_multihashmap_get (store->links, hash);
574}
575
576
579 const struct GNUNET_HashCode *hash,
580 struct GNUNET_MESSENGER_Message *message)
581{
582 GNUNET_assert ((store) && (hash) && (message));
583
584 return GNUNET_CONTAINER_multihashmap_put (store->messages, hash, message,
586}
587
588
589static void
591 const struct GNUNET_HashCode *hash,
592 const struct GNUNET_MESSENGER_Message *message)
593{
594 struct GNUNET_MESSENGER_MessageLink *link = GNUNET_new (struct
596
597 GNUNET_memcpy (&(link->first), &(message->header.previous),
598 sizeof(link->first));
599
602
603 if (GNUNET_YES == link->multiple)
604 GNUNET_memcpy (&(link->second), &(message->body.merge.previous),
605 sizeof(link->second));
606 else
607 GNUNET_memcpy (&(link->second), &(message->header.previous),
608 sizeof(link->second));
609
610 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (store->links, hash, link,
612 GNUNET_free (link);
613 else
614 store->write_links = GNUNET_YES;
615}
616
617
620 const struct GNUNET_HashCode *hash)
621{
622 GNUNET_assert ((store) && (hash));
623
624 const struct GNUNET_MESSENGER_MessageEntry *entry =
626
627 if (! entry)
628 goto clear_memory;
629
630 const struct GNUNET_MESSENGER_Message *message = get_store_message (store,
631 hash);
632
633 if (message)
634 add_link (store, hash, message);
635
636 if (! store->storage_messages)
637 goto clear_entry;
638
639 if (entry->offset != GNUNET_DISK_file_seek (store->storage_messages,
640 entry->offset,
642 return GNUNET_SYSERR;
643
644 char *clear_buffer = GNUNET_malloc (entry->length);
645
646 if (! clear_buffer)
647 return GNUNET_SYSERR;
648
649 GNUNET_CRYPTO_zero_keys (clear_buffer, entry->length);
650
651 if ((entry->length != GNUNET_DISK_file_write (store->storage_messages,
652 clear_buffer, entry->length)) ||
653 (GNUNET_OK
654 !=
656 store->storage_messages)))
657 {
658 GNUNET_free (clear_buffer);
659 return GNUNET_SYSERR;
660 }
661
662 GNUNET_free (clear_buffer);
663
664clear_entry:
666 entry))
668
669clear_memory:
671 return GNUNET_OK;
672}
struct GNUNET_HashCode key
The key used in the DHT.
static char * filename
static char * value
Value of the record to add/remove.
static enum GNUNET_GenericReturnValue iterate_save_entries(void *cls, const struct GNUNET_HashCode *key, void *value)
static enum GNUNET_GenericReturnValue iterate_destroy_entries(void *cls, const struct GNUNET_HashCode *key, void *value)
static enum GNUNET_GenericReturnValue iterate_destroy_messages(void *cls, const struct GNUNET_HashCode *key, void *value)
enum GNUNET_GenericReturnValue contains_store_message(const struct GNUNET_MESSENGER_MessageStore *store, const struct GNUNET_HashCode *hash)
Checks if a message matching a given hash is stored in a message store.
void save_message_store(struct GNUNET_MESSENGER_MessageStore *store, const char *directory)
Saves messages from a message store into a directory.
enum GNUNET_GenericReturnValue put_store_message(struct GNUNET_MESSENGER_MessageStore *store, const struct GNUNET_HashCode *hash, struct GNUNET_MESSENGER_Message *message)
Stores a message into the message store.
static void load_message_store_entries(struct GNUNET_MESSENGER_MessageStore *store, const char *filename)
void clear_message_store(struct GNUNET_MESSENGER_MessageStore *store)
Clears a message store, wipes its content and deallocates its memory.
#define load_message_store_attribute_failed(file, attribute)
enum GNUNET_GenericReturnValue delete_store_message(struct GNUNET_MESSENGER_MessageStore *store, const struct GNUNET_HashCode *hash)
Deletes a message in the message store.
void init_message_store(struct GNUNET_MESSENGER_MessageStore *store)
Initializes a message store as fully empty.
static enum GNUNET_GenericReturnValue iterate_save_links(void *cls, const struct GNUNET_HashCode *key, void *value)
#define save_message_store_attribute_failed(file, attribute)
static void load_message_store_links(struct GNUNET_MESSENGER_MessageStore *store, const char *filename)
void load_message_store(struct GNUNET_MESSENGER_MessageStore *store, const char *directory)
Loads messages from a directory into a message store.
static enum GNUNET_GenericReturnValue iterate_destroy_links(void *cls, const struct GNUNET_HashCode *key, void *value)
const struct GNUNET_MESSENGER_MessageLink * get_store_message_link(struct GNUNET_MESSENGER_MessageStore *store, const struct GNUNET_HashCode *hash, enum GNUNET_GenericReturnValue deleted_only)
Returns the message link from a message store matching a given hash.
static enum GNUNET_GenericReturnValue iterate_save_messages(void *cls, const struct GNUNET_HashCode *key, void *value)
const struct GNUNET_MESSENGER_Message * get_store_message(struct GNUNET_MESSENGER_MessageStore *store, const struct GNUNET_HashCode *hash)
Returns the message from a message store matching a given hash.
static void add_link(struct GNUNET_MESSENGER_MessageStore *store, const struct GNUNET_HashCode *hash, const struct GNUNET_MESSENGER_Message *message)
static void save()
Write persistent statistics to disk.
void GNUNET_CRYPTO_zero_keys(void *buffer, size_t length)
Zero out buffer, securely against compiler optimizations.
struct GNUNET_DISK_FileHandle * GNUNET_DISK_file_open(const char *fn, enum GNUNET_DISK_OpenFlags flags, enum GNUNET_DISK_AccessPermissions perm)
Open a file.
Definition: disk.c:1237
enum GNUNET_GenericReturnValue GNUNET_DISK_file_test(const char *fil)
Check that fil corresponds to a filename (of a file that exists and that is not a directory).
Definition: disk.c:482
ssize_t GNUNET_DISK_file_write(const struct GNUNET_DISK_FileHandle *h, const void *buffer, size_t n)
Write a buffer to a file.
Definition: disk.c:686
off_t GNUNET_DISK_file_seek(const struct GNUNET_DISK_FileHandle *h, off_t offset, enum GNUNET_DISK_Seek whence)
Move the read/write pointer in a file.
Definition: disk.c:205
GNUNET_DISK_AccessPermissions
File access permissions, UNIX-style.
enum GNUNET_GenericReturnValue GNUNET_DISK_file_sync(const struct GNUNET_DISK_FileHandle *h)
Write file changes to disk.
Definition: disk.c:1427
enum GNUNET_GenericReturnValue GNUNET_DISK_file_close(struct GNUNET_DISK_FileHandle *h)
Close an open file.
Definition: disk.c:1308
ssize_t GNUNET_DISK_file_read(const struct GNUNET_DISK_FileHandle *h, void *result, size_t len)
Read the contents of a binary file into a buffer.
Definition: disk.c:622
@ GNUNET_DISK_OPEN_READ
Open the file for reading.
@ GNUNET_DISK_OPEN_WRITE
Open the file for writing.
@ GNUNET_DISK_OPEN_CREATE
Create file if it doesn't exist.
@ GNUNET_DISK_OPEN_READWRITE
Open the file for both reading and writing.
@ GNUNET_DISK_PERM_USER_READ
Owner can read.
@ GNUNET_DISK_PERM_USER_WRITE
Owner can write.
@ GNUNET_DISK_SEEK_SET
Seek an absolute position (from the start of the file).
@ GNUNET_DISK_SEEK_END
Seek an absolute position from the end of the file.
int GNUNET_CRYPTO_hash_cmp(const struct GNUNET_HashCode *h1, const struct GNUNET_HashCode *h2)
Compare function for HashCodes, producing a total ordering of all hashcodes.
Definition: crypto_hash.c:221
enum GNUNET_GenericReturnValue GNUNET_CONTAINER_multihashmap_contains(const struct GNUNET_CONTAINER_MultiHashMap *map, const struct GNUNET_HashCode *key)
Check if the map contains any value under the given key (including values that are NULL).
int GNUNET_CONTAINER_multihashmap_remove_all(struct GNUNET_CONTAINER_MultiHashMap *map, const struct GNUNET_HashCode *key)
Remove all entries for the given key from the map.
int GNUNET_CONTAINER_multihashmap_iterate(struct GNUNET_CONTAINER_MultiHashMap *map, GNUNET_CONTAINER_MultiHashMapIteratorCallback it, void *it_cls)
Iterate over all entries in the map.
void * GNUNET_CONTAINER_multihashmap_get(const struct GNUNET_CONTAINER_MultiHashMap *map, const struct GNUNET_HashCode *key)
Given a key find a value in the map matching the key.
enum GNUNET_GenericReturnValue GNUNET_CONTAINER_multihashmap_remove(struct GNUNET_CONTAINER_MultiHashMap *map, const struct GNUNET_HashCode *key, const void *value)
Remove the given key-value pair from the map.
enum GNUNET_GenericReturnValue GNUNET_CONTAINER_multihashmap_put(struct GNUNET_CONTAINER_MultiHashMap *map, const struct GNUNET_HashCode *key, void *value, enum GNUNET_CONTAINER_MultiHashMapOption opt)
Store a key-value pair in the map.
void GNUNET_CONTAINER_multihashmap_destroy(struct GNUNET_CONTAINER_MultiHashMap *map)
Destroy a hash map.
struct GNUNET_CONTAINER_MultiHashMap * GNUNET_CONTAINER_multihashmap_create(unsigned int len, int do_not_copy_keys)
Create a multi hash map.
@ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST
, ' bother checking if a value already exists (faster than GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE...
#define GNUNET_log(kind,...)
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
GNUNET_GenericReturnValue
Named constants for return values.
@ GNUNET_OK
@ GNUNET_YES
@ GNUNET_NO
@ GNUNET_SYSERR
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
const char * GNUNET_h2s(const struct GNUNET_HashCode *hc)
Convert a hash value to a string (for printing debug messages).
@ GNUNET_ERROR_TYPE_WARNING
@ GNUNET_ERROR_TYPE_DEBUG
int int GNUNET_asprintf(char **buf, const char *format,...) __attribute__((format(printf
Like asprintf, just portable.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_malloc(size)
Wrapper around malloc.
#define GNUNET_free(ptr)
Wrapper around free.
@ GNUNET_MESSENGER_KIND_UNKNOWN
The unknown kind.
@ GNUNET_MESSENGER_KIND_MERGE
The merge kind.
void encode_message(const struct GNUNET_MESSENGER_Message *message, uint16_t length, char *buffer, enum GNUNET_GenericReturnValue include_header)
Encodes a given message into a buffer of a maximal length in bytes.
void hash_message(const struct GNUNET_MESSENGER_Message *message, uint16_t length, const char *buffer, struct GNUNET_HashCode *hash)
Calculates a hash of a given buffer with a length in bytes from a message.
struct GNUNET_MESSENGER_Message * create_message(enum GNUNET_MESSENGER_MessageKind kind)
Creates and allocates a new message with a specific kind.
void destroy_message(struct GNUNET_MESSENGER_Message *message)
Destroys a message and frees its memory fully.
uint16_t get_message_kind_size(enum GNUNET_MESSENGER_MessageKind kind, enum GNUNET_GenericReturnValue include_header)
Returns the minimal size in bytes to encode a message of a specific kind.
uint16_t get_message_size(const struct GNUNET_MESSENGER_Message *message, enum GNUNET_GenericReturnValue include_header)
Returns the exact size in bytes to encode a given message.
enum GNUNET_GenericReturnValue decode_message(struct GNUNET_MESSENGER_Message *message, uint16_t length, const char *buffer, enum GNUNET_GenericReturnValue include_header, uint16_t *padding)
Decodes a message from a given buffer of a maximal length in bytes.
Handle used to access files (and pipes).
A 512-bit hashcode.
struct GNUNET_MESSENGER_MessageMerge merge
struct GNUNET_HashCode previous
The hash of the previous message from the senders perspective.
enum GNUNET_MESSENGER_MessageKind kind
The kind of the message.
struct GNUNET_HashCode previous
The hash of a second previous message.
struct GNUNET_CONTAINER_MultiHashMap * links
struct GNUNET_DISK_FileHandle * storage_messages
struct GNUNET_CONTAINER_MultiHashMap * messages
struct GNUNET_CONTAINER_MultiHashMap * entries
struct GNUNET_MESSENGER_MessageHeader header
Header.
struct GNUNET_MESSENGER_MessageBody body
Body.