aboutsummaryrefslogtreecommitdiff
path: root/src/contrib/service/rps/gnunet-service-rps_custommap.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/contrib/service/rps/gnunet-service-rps_custommap.c')
-rw-r--r--src/contrib/service/rps/gnunet-service-rps_custommap.c356
1 files changed, 356 insertions, 0 deletions
diff --git a/src/contrib/service/rps/gnunet-service-rps_custommap.c b/src/contrib/service/rps/gnunet-service-rps_custommap.c
new file mode 100644
index 000000000..b1e73be17
--- /dev/null
+++ b/src/contrib/service/rps/gnunet-service-rps_custommap.c
@@ -0,0 +1,356 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C)
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/**
22 * @file rps/gnunet-service-rps_custommap.c
23 * @brief utilities for managing (information about) peers
24 * @author Julius Bünger
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet-service-rps_custommap.h"
29#include <inttypes.h>
30
31#define LOG(kind, ...) GNUNET_log_from (kind, "rps-peers", __VA_ARGS__)
32
33
34/**
35 * Peer map to store peers with specialised use-cases (push_list, pull_list,
36 * view, ...)
37 *
38 * It is aimed for use as unordered list-like structures that can be indexed.
39 * Main use-case:
40 *
41 * permut = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_STRONG,
42 * CustomPeerMap_size (peer_map));
43 * for (i = 0; i < some_border; i++)
44 * some_array[i] = *CustomPeerMap_get_peer_by_index (peer_map, permut[i]);
45 * for (i = some_border; i < CustomPeerMap_size (peer_map); i++)
46 * other_array[i-some_border] =
47 * *CustomPeerMap_get_peer_by_index (peer_map, permut[i]);
48 *
49 * This list is expected to
50 * - be altered in small steps frequently
51 * - be cleared regularly
52 * - often being queried whether a peer is contained
53 * - alter indices of peers
54 * - contain continuous indices 0 <= i < len
55 * - not contain duplicate peers
56 */
57struct CustomPeerMap
58{
59 /**
60 * Multihashmap to be able to access a random index
61 */
62 struct GNUNET_CONTAINER_MultiHashMap32 *hash_map;
63
64 /**
65 * Peermap to quickly check whether a peer is contained
66 */
67 struct GNUNET_CONTAINER_MultiPeerMap *peer_map;
68};
69
70
71/**
72 * Create an empty peermap.
73 *
74 * @param len the initial length for the internal maps
75 *
76 * @return the newly created custom peer map
77 */
78struct CustomPeerMap *
79CustomPeerMap_create (unsigned int len)
80{
81 struct CustomPeerMap *c_peer_map;
82
83 c_peer_map = GNUNET_new (struct CustomPeerMap);
84 c_peer_map->hash_map = GNUNET_CONTAINER_multihashmap32_create (len);
85 c_peer_map->peer_map = GNUNET_CONTAINER_multipeermap_create (len,
86 GNUNET_NO);
87 return c_peer_map;
88}
89
90
91/**
92 * Get the size of the custom peer map
93 *
94 * @param c_peer_map the custom peer map to look in
95 *
96 * @return size of the map
97 */
98unsigned int
99CustomPeerMap_size (const struct CustomPeerMap *c_peer_map)
100{
101 GNUNET_assert (GNUNET_CONTAINER_multihashmap32_size (c_peer_map->hash_map) ==
102 GNUNET_CONTAINER_multipeermap_size (c_peer_map->peer_map));
103 return GNUNET_CONTAINER_multipeermap_size (c_peer_map->peer_map);
104}
105
106
107/**
108 * Insert peer into the custom peer map
109 *
110 * @param c_peer_map the custom peer map to insert peer
111 * @param peer the peer to insert
112 *
113 * @return GNUNET_OK if map did not contain peer previously
114 * GNUNET_NO if map did contain peer previously
115 */
116int
117CustomPeerMap_put (const struct CustomPeerMap *c_peer_map,
118 const struct GNUNET_PeerIdentity *peer)
119{
120 uint32_t *index;
121 struct GNUNET_PeerIdentity *p;
122
123 GNUNET_assert (GNUNET_CONTAINER_multihashmap32_size (c_peer_map->hash_map) ==
124 GNUNET_CONTAINER_multipeermap_size (c_peer_map->peer_map));
125 if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (c_peer_map->peer_map,
126 peer))
127 {
128 /* Need to store the index of the peer in the peermap to be able to remove
129 * it properly */
130 index = GNUNET_new (uint32_t);
131 *index = CustomPeerMap_size (c_peer_map);
132 p = GNUNET_new (struct GNUNET_PeerIdentity);
133 *p = *peer;
134 GNUNET_assert (p != peer);
135 GNUNET_assert (0 == memcmp (p,
136 peer,
137 sizeof(struct GNUNET_PeerIdentity)));
138 GNUNET_CONTAINER_multipeermap_put (c_peer_map->peer_map,
139 p,
140 index,
141 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
142 GNUNET_CONTAINER_multihashmap32_put (c_peer_map->hash_map,
143 *index,
144 p,
145 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
146 GNUNET_assert (GNUNET_CONTAINER_multihashmap32_size (
147 c_peer_map->hash_map) ==
148 GNUNET_CONTAINER_multipeermap_size (c_peer_map->peer_map));
149 return GNUNET_OK;
150 }
151 return GNUNET_NO;
152}
153
154
155/**
156 * Check whether custom peer map contains a peer
157 *
158 * @param c_peer_map the custom peer map to look in
159 * @param peer the peer to check for
160 *
161 * @return GNUNET_OK if map contains peer
162 * GNUNET_NO otherwise
163 */
164int
165CustomPeerMap_contains_peer (const struct CustomPeerMap *c_peer_map,
166 const struct GNUNET_PeerIdentity *peer)
167{
168 return GNUNET_CONTAINER_multipeermap_contains (c_peer_map->peer_map, peer);
169}
170
171
172/**
173 * Get index of peer in custom peer map
174 *
175 * @param c_peer_map the custom peer map to look in
176 * @param peer the peer to get the index from
177 *
178 * @return the index
179 */
180static uint32_t *
181CustomPeerMap_get_index_pointer (const struct CustomPeerMap *c_peer_map,
182 const struct GNUNET_PeerIdentity *peer)
183{
184 uint32_t *index;
185
186 GNUNET_assert (GNUNET_YES == CustomPeerMap_contains_peer (c_peer_map, peer));
187 index = GNUNET_CONTAINER_multipeermap_get (c_peer_map->peer_map, peer);
188 return index;
189}
190
191
192/**
193 * Remove peer from custom peer map
194 *
195 * @param c_peer_map the custom peer map to remove the peer from
196 * @param peer the peer to remove
197 *
198 * @return GNUNET_OK if map contained peer and removed it successfully
199 * GNUNET_NO if map does not contain peer
200 */
201int
202CustomPeerMap_remove_peer (const struct CustomPeerMap *c_peer_map,
203 const struct GNUNET_PeerIdentity *peer)
204{
205 uint32_t *index;
206 struct GNUNET_PeerIdentity *p;
207 uint32_t *last_index;
208 struct GNUNET_PeerIdentity *last_p;
209 int ret;
210
211 if (GNUNET_NO == CustomPeerMap_contains_peer (c_peer_map,
212 peer))
213 {
214 return GNUNET_NO;
215 }
216 index = CustomPeerMap_get_index_pointer (c_peer_map,
217 peer);
218 GNUNET_assert (*index < CustomPeerMap_size (c_peer_map));
219 /* Need to get the pointer stored in the hashmap to free it */
220 p = GNUNET_CONTAINER_multihashmap32_get (c_peer_map->hash_map,
221 *index);
222 GNUNET_assert (NULL != p);
223 GNUNET_CONTAINER_multihashmap32_remove_all (c_peer_map->hash_map,
224 *index);
225 // TODO wrong peerid?
226 GNUNET_CONTAINER_multipeermap_remove_all (c_peer_map->peer_map,
227 peer);
228 if (*index != CustomPeerMap_size (c_peer_map))
229 { /* fill 'gap' with peer at last index */
230 last_p =
231 GNUNET_CONTAINER_multihashmap32_get (c_peer_map->hash_map,
232 CustomPeerMap_size (c_peer_map));
233 GNUNET_assert (NULL != last_p);
234 last_index = GNUNET_CONTAINER_multipeermap_get (c_peer_map->peer_map,
235 last_p);
236 GNUNET_assert (NULL != last_index);
237 GNUNET_assert (CustomPeerMap_size (c_peer_map) == *last_index);
238 ret = GNUNET_CONTAINER_multihashmap32_put (c_peer_map->hash_map,
239 *index,
240 last_p,
241 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
242 GNUNET_assert (GNUNET_OK == ret);
243 GNUNET_CONTAINER_multihashmap32_remove_all (c_peer_map->hash_map,
244 *last_index);
245 *last_index = *index;
246 }
247 GNUNET_free (index);
248 GNUNET_assert (GNUNET_CONTAINER_multihashmap32_size (c_peer_map->hash_map) ==
249 GNUNET_CONTAINER_multipeermap_size (c_peer_map->peer_map));
250 GNUNET_free (p);
251 return GNUNET_OK;
252}
253
254
255/**
256 * Get a peer by index
257 *
258 * @param c_peer_map the custom peer map to look in
259 * @param index the index of the peer to get
260 *
261 * @return peer to the corresponding index.
262 * if this index is not known, return NULL
263 */
264struct GNUNET_PeerIdentity *
265CustomPeerMap_get_peer_by_index (const struct CustomPeerMap *c_peer_map,
266 uint32_t index)
267{
268 if (GNUNET_YES ==
269 GNUNET_CONTAINER_multihashmap32_contains (c_peer_map->hash_map, index))
270 {
271 return GNUNET_CONTAINER_multihashmap32_get (c_peer_map->hash_map, index);
272 }
273 return NULL;
274}
275
276
277/**
278 * Remove peer from custom peer map by index
279 *
280 * @param c_peer_map the custom peer map to remove the peer from
281 * @param index the index of the peer to remove
282 *
283 * @return GNUNET_OK if map contained peer and removed it successfully
284 * GNUNET_NO if map does not contain (index of) peer
285 */
286int
287CustomPeerMap_remove_peer_by_index (const struct CustomPeerMap *c_peer_map,
288 uint32_t index)
289{
290 uint32_t *index_p;
291 struct GNUNET_PeerIdentity *peer;
292
293 if (index >= CustomPeerMap_size (c_peer_map))
294 {
295 return GNUNET_NO;
296 }
297 GNUNET_assert (GNUNET_CONTAINER_multihashmap32_size (c_peer_map->hash_map) ==
298 GNUNET_CONTAINER_multipeermap_size (c_peer_map->peer_map));
299 if (GNUNET_NO ==
300 GNUNET_CONTAINER_multihashmap32_contains (c_peer_map->hash_map, index))
301 {
302 return GNUNET_NO;
303 }
304 peer = CustomPeerMap_get_peer_by_index (c_peer_map, index);
305 GNUNET_assert (NULL != peer);
306 index_p = CustomPeerMap_get_index_pointer (c_peer_map, peer);
307 GNUNET_assert (index == *index_p);
308 CustomPeerMap_remove_peer (c_peer_map, peer);
309 GNUNET_assert (GNUNET_CONTAINER_multihashmap32_size (c_peer_map->hash_map) ==
310 GNUNET_CONTAINER_multipeermap_size (c_peer_map->peer_map));
311 return GNUNET_OK;
312}
313
314
315/**
316 * Clear the custom peer map
317 *
318 * @param c_peer_map the custom peer map to look in
319 *
320 * @return size of the map
321 */
322void
323CustomPeerMap_clear (const struct CustomPeerMap *c_peer_map)
324{
325 while (0 < CustomPeerMap_size (c_peer_map))
326 {
327 GNUNET_assert (GNUNET_YES ==
328 GNUNET_CONTAINER_multihashmap32_contains (
329 c_peer_map->hash_map,
330 CustomPeerMap_size (
331 c_peer_map) - 1));
332 GNUNET_assert (GNUNET_OK ==
333 CustomPeerMap_remove_peer_by_index (c_peer_map,
334 CustomPeerMap_size (
335 c_peer_map) - 1));
336 }
337 GNUNET_assert (0 == CustomPeerMap_size (c_peer_map));
338}
339
340
341/**
342 * Destroy peermap.
343 *
344 * @param c_peer_map the map to destroy
345 */
346void
347CustomPeerMap_destroy (struct CustomPeerMap *c_peer_map)
348{
349 CustomPeerMap_clear (c_peer_map);
350 GNUNET_CONTAINER_multihashmap32_destroy (c_peer_map->hash_map);
351 GNUNET_CONTAINER_multipeermap_destroy (c_peer_map->peer_map);
352 GNUNET_free (c_peer_map);
353}
354
355
356/* end of gnunet-service-rps_custommap.c */