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