/* This file is part of GNUnet. Copyright (C) GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ /** * @file rps/gnunet-service-rps_view.c * @brief wrapper around the "local view" * @author Julius Bünger */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet-service-rps_view.h" #include /** * Array containing the peers */ static struct GNUNET_PeerIdentity *array; /** * (Maximum) length of the view */ static uint32_t length; /** * Multipeermap containing the peers */ static struct GNUNET_CONTAINER_MultiPeerMap *mpm; /** * Create an empty view. * * @param len the maximum length for the view */ void View_create (uint32_t len) { length = len; array = GNUNET_new_array (len, struct GNUNET_PeerIdentity); mpm = GNUNET_CONTAINER_multipeermap_create (len, GNUNET_NO); /* might even be * set to _YES */ } /** * Change length of view * * If size is decreased, peers with higher indices are removed. * * @param len the (maximum) length for the view */ void View_change_len (uint32_t len) { uint32_t i; uint32_t *index; if (GNUNET_CONTAINER_multipeermap_size (mpm) < len) { /* Simply shrink */ /* We might simply clear and free the left over space */ GNUNET_array_grow (array, length, len); } else /* We have to remove elements */ { /* TODO find a way to preserve indices */ for (i = 0; i < len; i++) { index = GNUNET_CONTAINER_multipeermap_get (mpm, &array[i]); GNUNET_assert (NULL != index); GNUNET_free (index); } GNUNET_array_grow (array, length, len); GNUNET_CONTAINER_multipeermap_destroy (mpm); mpm = GNUNET_CONTAINER_multipeermap_create (len, GNUNET_NO); for (i = 0; i < len; i++) { index = GNUNET_new (uint32_t); *index = i; GNUNET_CONTAINER_multipeermap_put (mpm, &array[i], index, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); } } GNUNET_assert (length == len); } /** * Get the view as an array * * @return the view in array representation */ const struct GNUNET_PeerIdentity * View_get_as_array () { return array; } /** * Get the size of the view * * @return current number of actually contained peers */ unsigned int View_size () { return GNUNET_CONTAINER_multipeermap_size (mpm); } /** * Insert peer into the view * * @param peer the peer to insert * * @return GNUNET_OK if peer was actually inserted * GNUNET_NO if peer was not inserted */ int View_put (const struct GNUNET_PeerIdentity *peer) { uint32_t *index; if ((length <= View_size ()) || /* If array is 'full' */ (GNUNET_YES == View_contains_peer (peer))) { return GNUNET_NO; } else { index = GNUNET_new (uint32_t); *index = (uint32_t) View_size (); array[*index] = *peer; GNUNET_CONTAINER_multipeermap_put (mpm, peer, index, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); return GNUNET_OK; } } /** * Check whether view contains a peer * * @param peer the peer to check for * * @return GNUNET_OK if view contains peer * GNUNET_NO otherwise */ int View_contains_peer (const struct GNUNET_PeerIdentity *peer) { return GNUNET_CONTAINER_multipeermap_contains (mpm, peer); } /** * Remove peer from view * * @param peer the peer to remove * * @return GNUNET_OK if view contained peer and removed it successfully * GNUNET_NO if view does not contain peer */ int View_remove_peer (const struct GNUNET_PeerIdentity *peer) { uint32_t *index; uint32_t *swap_index; uint32_t last_index; if (GNUNET_NO == View_contains_peer (peer)) { return GNUNET_NO; } index = GNUNET_CONTAINER_multipeermap_get (mpm, peer); GNUNET_assert (NULL != index); last_index = View_size () - 1; if (*index < last_index) { /* Fill the 'gap' in the array with the last peer */ array[*index] = array[last_index]; GNUNET_assert (GNUNET_YES == View_contains_peer (&array[last_index])); swap_index = GNUNET_CONTAINER_multipeermap_get (mpm, &array[last_index]); GNUNET_assert (NULL != swap_index); *swap_index = *index; GNUNET_free (index); } GNUNET_CONTAINER_multipeermap_remove_all (mpm, peer); return GNUNET_OK; } /** * Get a peer by index * * @param index the index of the peer to get * * @return peer to the corresponding index. * NULL if this index is not known */ const struct GNUNET_PeerIdentity * View_get_peer_by_index (uint32_t index) { if (index < GNUNET_CONTAINER_multipeermap_size (mpm)) { return &array[index]; } else { return NULL; } } /** * Clear the custom peer map * * @param c_peer_map the custom peer map to look in * * @return size of the map */ void View_clear () { uint32_t i; uint32_t *index; for (i = 0; 0 < View_size (); i++) { /* Need to free indices stored at peers */ GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multipeermap_contains (mpm, &array[i])); index = GNUNET_CONTAINER_multipeermap_get (mpm, &array[i]); GNUNET_assert (NULL != index); GNUNET_free (index); GNUNET_CONTAINER_multipeermap_remove_all (mpm, &array[i]); } GNUNET_assert (0 == View_size ()); } /** * Destroy peermap. * * @param c_peer_map the map to destroy */ void View_destroy () { View_clear (); GNUNET_free (array); GNUNET_CONTAINER_multipeermap_destroy (mpm); } /* end of gnunet-service-rps_view.c */