gnunet-service-rps_custommap.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C)
  4. GNUnet is free software: you can redistribute it and/or modify it
  5. under the terms of the GNU Affero General Public License as published
  6. by the Free Software Foundation, either version 3 of the License,
  7. or (at your option) any later version.
  8. GNUnet is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Affero General Public License for more details.
  12. You should have received a copy of the GNU Affero General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. SPDX-License-Identifier: AGPL3.0-or-later
  15. */
  16. /**
  17. * @file rps/gnunet-service-rps_custommap.c
  18. * @brief utilities for managing (information about) peers
  19. * @author Julius Bünger
  20. */
  21. #include "platform.h"
  22. #include "gnunet_util_lib.h"
  23. #include "gnunet-service-rps_custommap.h"
  24. #include <inttypes.h>
  25. #define LOG(kind, ...) GNUNET_log_from (kind, "rps-peers", __VA_ARGS__)
  26. /**
  27. * Peer map to store peers with specialised use-cases (push_list, pull_list,
  28. * view, ...)
  29. *
  30. * It is aimed for use as unordered list-like structures that can be indexed.
  31. * Main use-case:
  32. *
  33. * permut = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_STRONG,
  34. * CustomPeerMap_size (peer_map));
  35. * for (i = 0; i < some_border; i++)
  36. * some_array[i] = *CustomPeerMap_get_peer_by_index (peer_map, permut[i]);
  37. * for (i = some_border; i < CustomPeerMap_size (peer_map); i++)
  38. * other_array[i-some_border] =
  39. * *CustomPeerMap_get_peer_by_index (peer_map, permut[i]);
  40. *
  41. * This list is expected to
  42. * - be altered in small steps frequently
  43. * - be cleared regularly
  44. * - often being queried whether a peer is contained
  45. * - alter indices of peers
  46. * - contain continuous indices 0 <= i < len
  47. * - not contain duplicate peers
  48. */
  49. struct CustomPeerMap
  50. {
  51. /**
  52. * Multihashmap to be able to access a random index
  53. */
  54. struct GNUNET_CONTAINER_MultiHashMap32 *hash_map;
  55. /**
  56. * Peermap to quickly check whether a peer is contained
  57. */
  58. struct GNUNET_CONTAINER_MultiPeerMap *peer_map;
  59. };
  60. /**
  61. * Create an empty peermap.
  62. *
  63. * @param len the initial length for the internal maps
  64. *
  65. * @return the newly created custom peer map
  66. */
  67. struct CustomPeerMap *
  68. CustomPeerMap_create (unsigned int len)
  69. {
  70. struct CustomPeerMap *c_peer_map;
  71. c_peer_map = GNUNET_new (struct CustomPeerMap);
  72. c_peer_map->hash_map = GNUNET_CONTAINER_multihashmap32_create (len);
  73. c_peer_map->peer_map = GNUNET_CONTAINER_multipeermap_create (len,
  74. GNUNET_NO);
  75. return c_peer_map;
  76. }
  77. /**
  78. * Get the size of the custom peer map
  79. *
  80. * @param c_peer_map the custom peer map to look in
  81. *
  82. * @return size of the map
  83. */
  84. unsigned int
  85. CustomPeerMap_size (const struct CustomPeerMap *c_peer_map)
  86. {
  87. GNUNET_assert (GNUNET_CONTAINER_multihashmap32_size (c_peer_map->hash_map) ==
  88. GNUNET_CONTAINER_multipeermap_size (c_peer_map->peer_map));
  89. return GNUNET_CONTAINER_multipeermap_size (c_peer_map->peer_map);
  90. }
  91. /**
  92. * Insert peer into the custom peer map
  93. *
  94. * @param c_peer_map the custom peer map to insert peer
  95. * @param peer the peer to insert
  96. *
  97. * @return GNUNET_OK if map did not contain peer previously
  98. * GNUNET_NO if map did contain peer previously
  99. */
  100. int
  101. CustomPeerMap_put (const struct CustomPeerMap *c_peer_map,
  102. const struct GNUNET_PeerIdentity *peer)
  103. {
  104. uint32_t *index;
  105. struct GNUNET_PeerIdentity *p;
  106. GNUNET_assert (GNUNET_CONTAINER_multihashmap32_size (c_peer_map->hash_map) ==
  107. GNUNET_CONTAINER_multipeermap_size (c_peer_map->peer_map));
  108. if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (c_peer_map->peer_map,
  109. peer))
  110. {
  111. /* Need to store the index of the peer in the peermap to be able to remove
  112. * it properly */
  113. index = GNUNET_new (uint32_t);
  114. *index = CustomPeerMap_size (c_peer_map);
  115. p = GNUNET_new (struct GNUNET_PeerIdentity);
  116. *p = *peer;
  117. GNUNET_assert (p != peer);
  118. GNUNET_assert (0 == memcmp (p,
  119. peer,
  120. sizeof(struct GNUNET_PeerIdentity)));
  121. GNUNET_CONTAINER_multipeermap_put (c_peer_map->peer_map,
  122. p,
  123. index,
  124. GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
  125. GNUNET_CONTAINER_multihashmap32_put (c_peer_map->hash_map,
  126. *index,
  127. p,
  128. GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
  129. GNUNET_assert (GNUNET_CONTAINER_multihashmap32_size (
  130. c_peer_map->hash_map) ==
  131. GNUNET_CONTAINER_multipeermap_size (c_peer_map->peer_map));
  132. return GNUNET_OK;
  133. }
  134. return GNUNET_NO;
  135. }
  136. /**
  137. * Check whether custom peer map contains a peer
  138. *
  139. * @param c_peer_map the custom peer map to look in
  140. * @param peer the peer to check for
  141. *
  142. * @return GNUNET_OK if map contains peer
  143. * GNUNET_NO otherwise
  144. */
  145. int
  146. CustomPeerMap_contains_peer (const struct CustomPeerMap *c_peer_map,
  147. const struct GNUNET_PeerIdentity *peer)
  148. {
  149. return GNUNET_CONTAINER_multipeermap_contains (c_peer_map->peer_map, peer);
  150. }
  151. /**
  152. * Get index of peer in custom peer map
  153. *
  154. * @param c_peer_map the custom peer map to look in
  155. * @param peer the peer to get the index from
  156. *
  157. * @return the index
  158. */
  159. static uint32_t *
  160. CustomPeerMap_get_index_pointer (const struct CustomPeerMap *c_peer_map,
  161. const struct GNUNET_PeerIdentity *peer)
  162. {
  163. uint32_t *index;
  164. GNUNET_assert (GNUNET_YES == CustomPeerMap_contains_peer (c_peer_map, peer));
  165. index = GNUNET_CONTAINER_multipeermap_get (c_peer_map->peer_map, peer);
  166. return index;
  167. }
  168. /**
  169. * Remove peer from custom peer map
  170. *
  171. * @param c_peer_map the custom peer map to remove the peer from
  172. * @param peer the peer to remove
  173. *
  174. * @return GNUNET_OK if map contained peer and removed it successfully
  175. * GNUNET_NO if map does not contain peer
  176. */
  177. int
  178. CustomPeerMap_remove_peer (const struct CustomPeerMap *c_peer_map,
  179. const struct GNUNET_PeerIdentity *peer)
  180. {
  181. uint32_t *index;
  182. struct GNUNET_PeerIdentity *p;
  183. uint32_t *last_index;
  184. struct GNUNET_PeerIdentity *last_p;
  185. int ret;
  186. if (GNUNET_NO == CustomPeerMap_contains_peer (c_peer_map,
  187. peer))
  188. {
  189. return GNUNET_NO;
  190. }
  191. index = CustomPeerMap_get_index_pointer (c_peer_map,
  192. peer);
  193. GNUNET_assert (*index < CustomPeerMap_size (c_peer_map));
  194. /* Need to get the pointer stored in the hashmap to free it */
  195. p = GNUNET_CONTAINER_multihashmap32_get (c_peer_map->hash_map,
  196. *index);
  197. GNUNET_assert (NULL != p);
  198. GNUNET_CONTAINER_multihashmap32_remove_all (c_peer_map->hash_map,
  199. *index);
  200. // TODO wrong peerid?
  201. GNUNET_CONTAINER_multipeermap_remove_all (c_peer_map->peer_map,
  202. peer);
  203. if (*index != CustomPeerMap_size (c_peer_map))
  204. { /* fill 'gap' with peer at last index */
  205. last_p =
  206. GNUNET_CONTAINER_multihashmap32_get (c_peer_map->hash_map,
  207. CustomPeerMap_size (c_peer_map));
  208. GNUNET_assert (NULL != last_p);
  209. last_index = GNUNET_CONTAINER_multipeermap_get (c_peer_map->peer_map,
  210. last_p);
  211. GNUNET_assert (NULL != last_index);
  212. GNUNET_assert (CustomPeerMap_size (c_peer_map) == *last_index);
  213. ret = GNUNET_CONTAINER_multihashmap32_put (c_peer_map->hash_map,
  214. *index,
  215. last_p,
  216. GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
  217. GNUNET_assert (GNUNET_OK == ret);
  218. GNUNET_CONTAINER_multihashmap32_remove_all (c_peer_map->hash_map,
  219. *last_index);
  220. *last_index = *index;
  221. }
  222. GNUNET_free (index);
  223. GNUNET_assert (GNUNET_CONTAINER_multihashmap32_size (c_peer_map->hash_map) ==
  224. GNUNET_CONTAINER_multipeermap_size (c_peer_map->peer_map));
  225. GNUNET_free (p);
  226. return GNUNET_OK;
  227. }
  228. /**
  229. * Get a peer by index
  230. *
  231. * @param c_peer_map the custom peer map to look in
  232. * @param index the index of the peer to get
  233. *
  234. * @return peer to the corresponding index.
  235. * if this index is not known, return NULL
  236. */
  237. struct GNUNET_PeerIdentity *
  238. CustomPeerMap_get_peer_by_index (const struct CustomPeerMap *c_peer_map,
  239. uint32_t index)
  240. {
  241. if (GNUNET_YES ==
  242. GNUNET_CONTAINER_multihashmap32_contains (c_peer_map->hash_map, index))
  243. {
  244. return GNUNET_CONTAINER_multihashmap32_get (c_peer_map->hash_map, index);
  245. }
  246. return NULL;
  247. }
  248. /**
  249. * Remove peer from custom peer map by index
  250. *
  251. * @param c_peer_map the custom peer map to remove the peer from
  252. * @param index the index of the peer to remove
  253. *
  254. * @return GNUNET_OK if map contained peer and removed it successfully
  255. * GNUNET_NO if map does not contain (index of) peer
  256. */
  257. int
  258. CustomPeerMap_remove_peer_by_index (const struct CustomPeerMap *c_peer_map,
  259. uint32_t index)
  260. {
  261. uint32_t *index_p;
  262. struct GNUNET_PeerIdentity *peer;
  263. if (index >= CustomPeerMap_size (c_peer_map))
  264. {
  265. return GNUNET_NO;
  266. }
  267. GNUNET_assert (GNUNET_CONTAINER_multihashmap32_size (c_peer_map->hash_map) ==
  268. GNUNET_CONTAINER_multipeermap_size (c_peer_map->peer_map));
  269. if (GNUNET_NO ==
  270. GNUNET_CONTAINER_multihashmap32_contains (c_peer_map->hash_map, index))
  271. {
  272. return GNUNET_NO;
  273. }
  274. peer = CustomPeerMap_get_peer_by_index (c_peer_map, index);
  275. GNUNET_assert (NULL != peer);
  276. index_p = CustomPeerMap_get_index_pointer (c_peer_map, peer);
  277. GNUNET_assert (index == *index_p);
  278. CustomPeerMap_remove_peer (c_peer_map, peer);
  279. GNUNET_assert (GNUNET_CONTAINER_multihashmap32_size (c_peer_map->hash_map) ==
  280. GNUNET_CONTAINER_multipeermap_size (c_peer_map->peer_map));
  281. return GNUNET_OK;
  282. }
  283. /**
  284. * Clear the custom peer map
  285. *
  286. * @param c_peer_map the custom peer map to look in
  287. *
  288. * @return size of the map
  289. */
  290. void
  291. CustomPeerMap_clear (const struct CustomPeerMap *c_peer_map)
  292. {
  293. while (0 < CustomPeerMap_size (c_peer_map))
  294. {
  295. GNUNET_assert (GNUNET_YES ==
  296. GNUNET_CONTAINER_multihashmap32_contains (
  297. c_peer_map->hash_map,
  298. CustomPeerMap_size (
  299. c_peer_map) - 1));
  300. GNUNET_assert (GNUNET_OK ==
  301. CustomPeerMap_remove_peer_by_index (c_peer_map,
  302. CustomPeerMap_size (
  303. c_peer_map) - 1));
  304. }
  305. GNUNET_assert (0 == CustomPeerMap_size (c_peer_map));
  306. }
  307. /**
  308. * Destroy peermap.
  309. *
  310. * @param c_peer_map the map to destroy
  311. */
  312. void
  313. CustomPeerMap_destroy (struct CustomPeerMap *c_peer_map)
  314. {
  315. CustomPeerMap_clear (c_peer_map);
  316. GNUNET_CONTAINER_multihashmap32_destroy (c_peer_map->hash_map);
  317. GNUNET_CONTAINER_multipeermap_destroy (c_peer_map->peer_map);
  318. GNUNET_free (c_peer_map);
  319. }
  320. /* end of gnunet-service-rps_custommap.c */