2 This file is part of GNUnet.
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.
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.
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/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
22 * @file rps/gnunet-service-rps_custommap.c
23 * @brief utilities for managing (information about) peers
24 * @author Julius Bünger
27 #include "gnunet_util_lib.h"
28 #include "gnunet-service-rps_custommap.h"
31 #define LOG(kind, ...) GNUNET_log_from (kind, "rps-peers", __VA_ARGS__)
35 * Peer map to store peers with specialised use-cases (push_list, pull_list,
38 * It is aimed for use as unordered list-like structures that can be indexed.
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]);
49 * This list is expected to
50 * - be altered in small steps frequently
51 * - be cleared regularily
52 * - often being queried whether a peer is contained
53 * - alter indices of peers
54 * - contain continous indices 0 <= i < len
55 * - not contain duplicate peers
60 * Multihashmap to be able to access a random index
62 struct GNUNET_CONTAINER_MultiHashMap32 *hash_map;
65 * Peermap to quickly check whether a peer is contained
67 struct GNUNET_CONTAINER_MultiPeerMap *peer_map;
72 * Create an empty peermap.
74 * @param len the initial length for the internal maps
76 * @return the newly created custom peer map
78 struct CustomPeerMap *
79 CustomPeerMap_create (unsigned int len)
81 struct CustomPeerMap *c_peer_map;
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,
92 * Get the size of the custom peer map
94 * @param c_peer_map the custom peer map to look in
96 * @return size of the map
99 CustomPeerMap_size (const struct CustomPeerMap *c_peer_map)
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);
108 * Insert peer into the custom peer map
110 * @param c_peer_map the custom peer map to insert peer
111 * @param peer the peer to insert
113 * @return GNUNET_OK if map did not contain peer previously
114 * GNUNET_NO if map did contain peer previously
117 CustomPeerMap_put (const struct CustomPeerMap *c_peer_map,
118 const struct GNUNET_PeerIdentity *peer)
121 struct GNUNET_PeerIdentity *p;
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,
128 /* Need to store the index of the peer in the peermap to be able to remove
130 index = GNUNET_new (uint32_t);
131 *index = CustomPeerMap_size (c_peer_map);
132 p = GNUNET_new (struct GNUNET_PeerIdentity);
134 GNUNET_assert (p != peer);
135 GNUNET_assert (0 == memcmp (p,
137 sizeof(struct GNUNET_PeerIdentity)));
138 GNUNET_CONTAINER_multipeermap_put (c_peer_map->peer_map,
141 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
142 GNUNET_CONTAINER_multihashmap32_put (c_peer_map->hash_map,
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));
156 * Check whether custom peer map contains a peer
158 * @param c_peer_map the custom peer map to look in
159 * @param peer the peer to check for
161 * @return GNUNET_OK if map contains peer
162 * GNUNET_NO otherwise
165 CustomPeerMap_contains_peer (const struct CustomPeerMap *c_peer_map,
166 const struct GNUNET_PeerIdentity *peer)
168 return GNUNET_CONTAINER_multipeermap_contains (c_peer_map->peer_map, peer);
173 * Get index of peer in custom peer map
175 * @param c_peer_map the custom peer map to look in
176 * @param peer the peer to get the index from
181 CustomPeerMap_get_index_pointer (const struct CustomPeerMap *c_peer_map,
182 const struct GNUNET_PeerIdentity *peer)
186 GNUNET_assert (GNUNET_YES == CustomPeerMap_contains_peer (c_peer_map, peer));
187 index = GNUNET_CONTAINER_multipeermap_get (c_peer_map->peer_map, peer);
193 * Remove peer from custom peer map
195 * @param c_peer_map the custom peer map to remove the peer from
196 * @param peer the peer to remove
198 * @return GNUNET_OK if map contained peer and removed it successfully
199 * GNUNET_NO if map does not contain peer
202 CustomPeerMap_remove_peer (const struct CustomPeerMap *c_peer_map,
203 const struct GNUNET_PeerIdentity *peer)
206 struct GNUNET_PeerIdentity *p;
207 uint32_t *last_index;
208 struct GNUNET_PeerIdentity *last_p;
210 if (GNUNET_NO == CustomPeerMap_contains_peer (c_peer_map,
215 index = CustomPeerMap_get_index_pointer (c_peer_map,
217 GNUNET_assert (*index < CustomPeerMap_size (c_peer_map));
218 /* Need to get the pointer stored in the hashmap to free it */
219 p = GNUNET_CONTAINER_multihashmap32_get (c_peer_map->hash_map,
221 GNUNET_assert (NULL != p);
222 GNUNET_CONTAINER_multihashmap32_remove_all (c_peer_map->hash_map,
224 // TODO wrong peerid?
225 GNUNET_CONTAINER_multipeermap_remove_all (c_peer_map->peer_map,
227 if (*index != CustomPeerMap_size (c_peer_map))
228 { /* fill 'gap' with peer at last index */
230 GNUNET_CONTAINER_multihashmap32_get (c_peer_map->hash_map,
231 CustomPeerMap_size (c_peer_map));
232 GNUNET_assert (NULL != last_p);
233 last_index = GNUNET_CONTAINER_multipeermap_get (c_peer_map->peer_map,
235 GNUNET_assert (NULL != last_index);
236 GNUNET_assert (CustomPeerMap_size (c_peer_map) == *last_index);
237 GNUNET_CONTAINER_multihashmap32_put (c_peer_map->hash_map,
239 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
240 GNUNET_CONTAINER_multihashmap32_remove_all (c_peer_map->hash_map,
242 *last_index = *index;
245 GNUNET_assert (GNUNET_CONTAINER_multihashmap32_size (c_peer_map->hash_map) ==
246 GNUNET_CONTAINER_multipeermap_size (c_peer_map->peer_map));
253 * Get a peer by index
255 * @param c_peer_map the custom peer map to look in
256 * @param index the index of the peer to get
258 * @return peer to the corresponding index.
259 * if this index is not known, return NULL
261 struct GNUNET_PeerIdentity *
262 CustomPeerMap_get_peer_by_index (const struct CustomPeerMap *c_peer_map,
266 GNUNET_CONTAINER_multihashmap32_contains (c_peer_map->hash_map, index))
268 return GNUNET_CONTAINER_multihashmap32_get (c_peer_map->hash_map, index);
275 * Remove peer from custom peer map by index
277 * @param c_peer_map the custom peer map to remove the peer from
278 * @param index the index of the peer to remove
280 * @return GNUNET_OK if map contained peer and removed it successfully
281 * GNUNET_NO if map does not contain (index of) peer
284 CustomPeerMap_remove_peer_by_index (const struct CustomPeerMap *c_peer_map,
288 struct GNUNET_PeerIdentity *peer;
290 if (index >= CustomPeerMap_size (c_peer_map))
294 GNUNET_assert (GNUNET_CONTAINER_multihashmap32_size (c_peer_map->hash_map) ==
295 GNUNET_CONTAINER_multipeermap_size (c_peer_map->peer_map));
297 GNUNET_CONTAINER_multihashmap32_contains (c_peer_map->hash_map, index))
301 peer = CustomPeerMap_get_peer_by_index (c_peer_map, index);
302 GNUNET_assert (NULL != peer);
303 index_p = CustomPeerMap_get_index_pointer (c_peer_map, peer);
304 GNUNET_assert (index == *index_p);
305 CustomPeerMap_remove_peer (c_peer_map, peer);
306 GNUNET_assert (GNUNET_CONTAINER_multihashmap32_size (c_peer_map->hash_map) ==
307 GNUNET_CONTAINER_multipeermap_size (c_peer_map->peer_map));
313 * Clear the custom peer map
315 * @param c_peer_map the custom peer map to look in
317 * @return size of the map
320 CustomPeerMap_clear (const struct CustomPeerMap *c_peer_map)
322 while (0 < CustomPeerMap_size (c_peer_map))
324 GNUNET_assert (GNUNET_YES ==
325 GNUNET_CONTAINER_multihashmap32_contains (
326 c_peer_map->hash_map,
329 GNUNET_assert (GNUNET_OK ==
330 CustomPeerMap_remove_peer_by_index (c_peer_map,
334 GNUNET_assert (0 == CustomPeerMap_size (c_peer_map));
341 * @param c_peer_map the map to destroy
344 CustomPeerMap_destroy (struct CustomPeerMap *c_peer_map)
346 CustomPeerMap_clear (c_peer_map);
347 GNUNET_CONTAINER_multihashmap32_destroy (c_peer_map->hash_map);
348 GNUNET_CONTAINER_multipeermap_destroy (c_peer_map->peer_map);
349 GNUNET_free (c_peer_map);
353 /* end of gnunet-service-rps_custommap.c */