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.c282
1 files changed, 282 insertions, 0 deletions
diff --git a/src/messenger/gnunet-service-messenger_message_store.c b/src/messenger/gnunet-service-messenger_message_store.c
new file mode 100644
index 000000000..5933d6390
--- /dev/null
+++ b/src/messenger/gnunet-service-messenger_message_store.c
@@ -0,0 +1,282 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2020 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 store->storage_messages = NULL;
33
34 store->entries = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
35 store->messages = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
36}
37
38static int
39iterate_destroy_entries (void *cls, const struct GNUNET_HashCode *key, void *value)
40{
41 struct GNUNET_MESSENGER_MessageEntry *entry = value;
42
43 GNUNET_free(entry);
44
45 return GNUNET_YES;
46}
47
48static int
49iterate_destroy_messages (void *cls, const struct GNUNET_HashCode *key, void *value)
50{
51 struct GNUNET_MESSENGER_Message *message = value;
52
53 destroy_message (message);
54
55 return GNUNET_YES;
56}
57
58void
59clear_message_store (struct GNUNET_MESSENGER_MessageStore *store)
60{
61 if (store->storage_messages)
62 {
63 GNUNET_DISK_file_close (store->storage_messages);
64
65 store->storage_messages = NULL;
66 }
67
68 GNUNET_CONTAINER_multihashmap_iterate (store->entries, iterate_destroy_entries, NULL);
69 GNUNET_CONTAINER_multihashmap_iterate (store->messages, iterate_destroy_messages, NULL);
70
71 GNUNET_CONTAINER_multihashmap_destroy (store->entries);
72 GNUNET_CONTAINER_multihashmap_destroy (store->messages);
73}
74
75struct GNUNET_MESSENGER_MessageEntryStorage
76{
77 struct GNUNET_HashCode hash;
78 struct GNUNET_MESSENGER_MessageEntry entry;
79};
80
81void
82load_message_store (struct GNUNET_MESSENGER_MessageStore *store, const char *directory)
83{
84 enum GNUNET_DISK_AccessPermissions permission = (GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE);
85
86 if (store->storage_messages)
87 GNUNET_DISK_file_close (store->storage_messages);
88
89 char *filename;
90 GNUNET_asprintf (&filename, "%s%s", directory, "messages.store");
91
92 if (GNUNET_YES == GNUNET_DISK_file_test (filename))
93 store->storage_messages = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ, permission);
94 else
95 store->storage_messages = NULL;
96
97 GNUNET_free(filename);
98
99 if (!store->storage_messages)
100 return;
101
102 GNUNET_asprintf (&filename, "%s%s", directory, "entries.store");
103
104 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
105 goto free_filename;
106
107 struct GNUNET_DISK_FileHandle *entries = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ, permission);
108
109 if (!entries)
110 goto free_filename;
111
112 struct GNUNET_MESSENGER_MessageEntryStorage storage;
113 struct GNUNET_MESSENGER_MessageEntry *entry;
114
115 do
116 {
117 entry = GNUNET_new(struct GNUNET_MESSENGER_MessageEntry);
118
119 if (GNUNET_DISK_file_read (entries, &storage, sizeof(storage)) == sizeof(storage))
120 {
121 GNUNET_memcpy(entry, &(storage.entry), sizeof(*entry));
122
123 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (store->entries, &(storage.hash), entry,
124 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
125 GNUNET_free(entry);
126 }
127 else
128 {
129 GNUNET_free(entry);
130
131 entry = NULL;
132 }
133 }
134 while (entry);
135
136 GNUNET_DISK_file_close (entries);
137
138free_filename:
139 GNUNET_free(filename);
140}
141
142struct GNUNET_MESSENGER_MessageSave
143{
144 struct GNUNET_MESSENGER_MessageStore *store;
145
146 struct GNUNET_DISK_FileHandle *storage_entries;
147};
148
149static int
150iterate_save_messages (void *cls, const struct GNUNET_HashCode *key, void *value)
151{
152 struct GNUNET_MESSENGER_MessageSave *save = cls;
153
154 if (GNUNET_NO != GNUNET_CONTAINER_multihashmap_contains (save->store->entries, key))
155 return GNUNET_YES;
156
157 struct GNUNET_MESSENGER_Message *message = value;
158 struct GNUNET_MESSENGER_MessageEntryStorage storage;
159
160 GNUNET_memcpy(&(storage.hash), key, sizeof(storage.hash));
161
162 storage.entry.length = get_message_size (message);
163 storage.entry.offset = GNUNET_DISK_file_seek (save->store->storage_messages, 0, GNUNET_DISK_SEEK_END);
164
165 if ((GNUNET_SYSERR == storage.entry.offset) ||
166 (sizeof(storage) != GNUNET_DISK_file_write (save->storage_entries, &storage, sizeof(storage))))
167 return GNUNET_YES;
168
169 char *buffer = GNUNET_malloc(storage.entry.length);
170
171 encode_message (message, storage.entry.length, buffer);
172
173 GNUNET_DISK_file_write (save->store->storage_messages, buffer, storage.entry.length);
174
175 GNUNET_free(buffer);
176
177 return GNUNET_YES;
178}
179
180void
181save_message_store (struct GNUNET_MESSENGER_MessageStore *store, const char *directory)
182{
183 struct GNUNET_MESSENGER_MessageSave save;
184
185 enum GNUNET_DISK_AccessPermissions permission = (GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE);
186
187 char *filename;
188 GNUNET_asprintf (&filename, "%s%s", directory, "entries.store");
189
190 save.store = store;
191 save.storage_entries = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE, permission);
192
193 GNUNET_free(filename);
194
195 if (!save.storage_entries)
196 return;
197
198 if (GNUNET_SYSERR == GNUNET_DISK_file_seek (save.storage_entries, 0, GNUNET_DISK_SEEK_END))
199 goto close_entries;
200
201 if (store->storage_messages)
202 GNUNET_DISK_file_close (store->storage_messages);
203
204 GNUNET_asprintf (&filename, "%s%s", directory, "messages.store");
205
206 store->storage_messages = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READWRITE | GNUNET_DISK_OPEN_CREATE,
207 permission);
208
209 GNUNET_free(filename);
210
211 if (store->storage_messages)
212 {
213 GNUNET_CONTAINER_multihashmap_iterate (store->messages, iterate_save_messages, &save);
214
215 GNUNET_DISK_file_sync (store->storage_messages);
216 GNUNET_DISK_file_sync (save.storage_entries);
217 }
218
219close_entries:
220 GNUNET_DISK_file_close (save.storage_entries);
221}
222
223int
224contains_store_message (struct GNUNET_MESSENGER_MessageStore *store, const struct GNUNET_HashCode *hash)
225{
226 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (store->messages, hash))
227 return GNUNET_YES;
228
229 return GNUNET_CONTAINER_multihashmap_contains (store->entries, hash);
230}
231
232const struct GNUNET_MESSENGER_Message*
233get_store_message (struct GNUNET_MESSENGER_MessageStore *store, const struct GNUNET_HashCode *hash)
234{
235 struct GNUNET_MESSENGER_Message *message = GNUNET_CONTAINER_multihashmap_get (store->messages, hash);
236
237 if (message)
238 return message;
239
240 if (!store->storage_messages)
241 return NULL;
242
243 const struct GNUNET_MESSENGER_MessageEntry *entry = GNUNET_CONTAINER_multihashmap_get (store->entries, hash);
244
245 if (!entry)
246 return NULL;
247
248 if (entry->offset != GNUNET_DISK_file_seek (store->storage_messages, entry->offset, GNUNET_DISK_SEEK_SET))
249 return message;
250
251 char *buffer = GNUNET_malloc(entry->length);
252
253 if (GNUNET_DISK_file_read (store->storage_messages, buffer, entry->length) != entry->length)
254 goto free_buffer;
255
256
257 message = create_message (GNUNET_MESSENGER_KIND_UNKNOWN);
258
259 if ((GNUNET_YES != decode_message (message, entry->length, buffer)) || (GNUNET_OK
260 != GNUNET_CONTAINER_multihashmap_put (store->messages, hash, message,
261 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)))
262 {
263 destroy_message (message);
264
265 message = NULL;
266
267 GNUNET_CONTAINER_multihashmap_remove (store->entries, hash, entry);
268 }
269
270free_buffer:
271 GNUNET_free(buffer);
272
273 return message;
274}
275
276int
277put_store_message (struct GNUNET_MESSENGER_MessageStore *store, const struct GNUNET_HashCode *hash,
278 struct GNUNET_MESSENGER_Message *message)
279{
280 return GNUNET_CONTAINER_multihashmap_put (store->messages, hash, message,
281 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
282}