glitch in the license text detected by hyazinthe, thank you!
[oweals/gnunet.git] / src / rps / gnunet-service-rps_view.c
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
16 /**
17  * @file rps/gnunet-service-rps_view.c
18  * @brief wrapper around the "local view"
19  * @author Julius Bünger
20  */
21 #include "platform.h"
22 #include "gnunet_util_lib.h"
23 #include "gnunet-service-rps_view.h"
24 #include <inttypes.h>
25
26
27 /**
28  * Array containing the peers
29  */
30 static struct GNUNET_PeerIdentity *array;
31
32 /**
33  * (Maximum) length of the view
34  */
35 static uint32_t length;
36
37 /**
38  * Multipeermap containing the peers
39  */
40 static struct GNUNET_CONTAINER_MultiPeerMap *mpm;
41
42
43 /**
44  * Create an empty view.
45  *
46  * @param len the maximum length for the view
47  */
48 void
49 View_create (uint32_t len)
50 {
51   length = len;
52   array = GNUNET_new_array (len, struct GNUNET_PeerIdentity);
53   mpm = GNUNET_CONTAINER_multipeermap_create (len, GNUNET_NO); /* might even be
54                                                                 * set to _YES */
55 }
56
57 /**
58  * Change length of view
59  *
60  * If size is decreased, peers with higher indices are removed.
61  *
62  * @param len the (maximum) length for the view
63  */
64 void
65 View_change_len (uint32_t len)
66 {
67   uint32_t i;
68   uint32_t *index;
69
70   if (GNUNET_CONTAINER_multipeermap_size (mpm) < len)
71   { /* Simply shrink */
72     /* We might simply clear and free the left over space */
73     GNUNET_array_grow (array, length, len);
74   }
75   else /* We have to remove elements */
76   {
77     /* TODO find a way to preserve indices */
78     for (i = 0; i < len; i++)
79     {
80       index = GNUNET_CONTAINER_multipeermap_get (mpm, &array[i]);
81       GNUNET_assert (NULL != index);
82       GNUNET_free (index);
83     }
84     GNUNET_array_grow (array, length, len);
85     GNUNET_CONTAINER_multipeermap_destroy (mpm);
86     mpm = GNUNET_CONTAINER_multipeermap_create (len, GNUNET_NO);
87     for (i = 0; i < len; i++)
88     {
89       index = GNUNET_new (uint32_t);
90       *index = i;
91       GNUNET_CONTAINER_multipeermap_put (mpm, &array[i], index,
92           GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
93     }
94   }
95   GNUNET_assert (length == len);
96 }
97
98 /**
99  * Get the view as an array
100  *
101  * @return the view in array representation
102  */
103 const struct GNUNET_PeerIdentity *
104 View_get_as_array ()
105 {
106   return array;
107 }
108
109 /**
110  * Get the size of the view
111  *
112  * @return current number of actually contained peers
113  */
114 unsigned int
115 View_size ()
116 {
117   return GNUNET_CONTAINER_multipeermap_size (mpm);
118 }
119
120 /**
121  * Insert peer into the view
122  *
123  * @param peer the peer to insert
124  *
125  * @return GNUNET_OK if peer was actually inserted
126  *         GNUNET_NO if peer was not inserted
127  */
128 int
129 View_put (const struct GNUNET_PeerIdentity *peer)
130 {
131   uint32_t *index;
132
133   if ((length <= View_size ()) || /* If array is 'full' */
134       (GNUNET_YES == View_contains_peer (peer)))
135   {
136     return GNUNET_NO;
137   }
138   else
139   {
140     index = GNUNET_new (uint32_t);
141     *index = (uint32_t) View_size ();
142     array[*index] = *peer;
143     GNUNET_CONTAINER_multipeermap_put (mpm, peer, index,
144         GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
145     return GNUNET_OK;
146   }
147 }
148
149 /**
150  * Check whether view contains a peer
151  *
152  * @param peer the peer to check for
153  *
154  * @return GNUNET_OK if view contains peer
155  *         GNUNET_NO otherwise
156  */
157 int
158 View_contains_peer (const struct GNUNET_PeerIdentity *peer)
159 {
160   return GNUNET_CONTAINER_multipeermap_contains (mpm, peer);
161 }
162
163 /**
164  * Remove peer from view
165  *
166  * @param peer the peer to remove
167  *
168  * @return GNUNET_OK if view contained peer and removed it successfully
169  *         GNUNET_NO if view does not contain peer
170  */
171 int
172 View_remove_peer (const struct GNUNET_PeerIdentity *peer)
173 {
174   uint32_t *index;
175   uint32_t *swap_index;
176   uint32_t last_index;
177
178   if (GNUNET_NO == View_contains_peer (peer))
179   {
180     return GNUNET_NO;
181   }
182   index = GNUNET_CONTAINER_multipeermap_get (mpm, peer);
183   GNUNET_assert (NULL != index);
184   last_index = View_size () - 1;
185   if (*index < last_index)
186   { /* Fill the 'gap' in the array with the last peer */
187     array[*index] = array[last_index];
188     GNUNET_assert (GNUNET_YES == View_contains_peer (&array[last_index]));
189     swap_index = GNUNET_CONTAINER_multipeermap_get (mpm, &array[last_index]);
190     GNUNET_assert (NULL != swap_index);
191     *swap_index = *index;
192     GNUNET_free (index);
193   }
194   GNUNET_CONTAINER_multipeermap_remove_all (mpm, peer);
195   return GNUNET_OK;
196 }
197
198 /**
199  * Get a peer by index
200  *
201  * @param index the index of the peer to get
202  *
203  * @return peer to the corresponding index.
204  *         NULL if this index is not known
205  */
206 const struct GNUNET_PeerIdentity *
207 View_get_peer_by_index (uint32_t index)
208 {
209   if (index < GNUNET_CONTAINER_multipeermap_size (mpm))
210   {
211     return &array[index];
212   }
213   else
214   {
215     return NULL;
216   }
217 }
218
219 /**
220  * Clear the custom peer map
221  *
222  * @param c_peer_map the custom peer map to look in
223  *
224  * @return size of the map
225  */
226 void
227 View_clear ()
228 {
229   uint32_t i;
230   uint32_t *index;
231
232   for (i = 0; 0 < View_size (); i++)
233   { /* Need to free indices stored at peers */
234     GNUNET_assert (GNUNET_YES ==
235         GNUNET_CONTAINER_multipeermap_contains (mpm, &array[i]));
236     index = GNUNET_CONTAINER_multipeermap_get (mpm, &array[i]);
237     GNUNET_assert (NULL != index);
238     GNUNET_free (index);
239     GNUNET_CONTAINER_multipeermap_remove_all (mpm, &array[i]);
240   }
241   GNUNET_assert (0 == View_size ());
242 }
243
244 /**
245  * Destroy peermap.
246  *
247  * @param c_peer_map the map to destroy
248  */
249 void
250 View_destroy ()
251 {
252   View_clear ();
253   GNUNET_free (array);
254   GNUNET_CONTAINER_multipeermap_destroy (mpm);
255 }
256
257 /* end of gnunet-service-rps_view.c */