aboutsummaryrefslogtreecommitdiff
path: root/src/service/core/gnunet-service-core_typemap.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/service/core/gnunet-service-core_typemap.c')
-rw-r--r--src/service/core/gnunet-service-core_typemap.c370
1 files changed, 370 insertions, 0 deletions
diff --git a/src/service/core/gnunet-service-core_typemap.c b/src/service/core/gnunet-service-core_typemap.c
new file mode 100644
index 000000000..200a84b23
--- /dev/null
+++ b/src/service/core/gnunet-service-core_typemap.c
@@ -0,0 +1,370 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011-2014 GNUnet e.V.
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 core/gnunet-service-core_typemap.c
23 * @brief management of map that specifies which message types this peer supports
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet-service-core.h"
29#include "gnunet-service-core_sessions.h"
30#include "gnunet-service-core_typemap.h"
31#include <zlib.h>
32
33
34/**
35 * A type map describing which messages a given neighbour is able
36 * to process.
37 */
38struct GSC_TypeMap
39{
40 uint32_t bits[(UINT16_MAX + 1) / 32];
41};
42
43/**
44 * Bitmap of message types this peer is able to handle.
45 */
46static struct GSC_TypeMap my_type_map;
47
48/**
49 * Counters for message types this peer is able to handle.
50 */
51static uint8_t map_counters[UINT16_MAX + 1];
52
53/**
54 * Current hash of our (uncompressed) type map.
55 * Lazily computed when needed.
56 */
57static struct GNUNET_HashCode my_tm_hash;
58
59/**
60 * Is #my_tm_hash() current with respect to our type map?
61 */
62static int hash_current;
63
64
65/**
66 * Our type map changed, recompute its hash.
67 */
68static void
69rehash_typemap ()
70{
71 hash_current = GNUNET_NO;
72}
73
74
75/**
76 * Hash the contents of a type map.
77 *
78 * @param tm map to hash
79 * @param hc where to store the hash code
80 */
81void
82GSC_TYPEMAP_hash (const struct GSC_TypeMap *tm, struct GNUNET_HashCode *hc)
83{
84 GNUNET_CRYPTO_hash (tm, sizeof(struct GSC_TypeMap), hc);
85}
86
87
88/**
89 * Check if the given hash matches our current type map.
90 *
91 * @param hc hash code to check if it matches our type map
92 * @return #GNUNET_YES if the hash matches, #GNUNET_NO if not
93 */
94int
95GSC_TYPEMAP_check_hash (const struct GNUNET_HashCode *hc)
96{
97 if (GNUNET_NO == hash_current)
98 {
99 GSC_TYPEMAP_hash (&my_type_map, &my_tm_hash);
100 hash_current = GNUNET_YES;
101 }
102 return (0 == memcmp (hc, &my_tm_hash, sizeof(struct GNUNET_HashCode)))
103 ? GNUNET_YES
104 : GNUNET_NO;
105}
106
107
108/**
109 * Compute a type map message for this peer.
110 *
111 * @return this peers current type map message.
112 */
113struct GNUNET_MessageHeader *
114GSC_TYPEMAP_compute_type_map_message ()
115{
116 char *tmp;
117 uLongf dlen;
118 struct GNUNET_MessageHeader *hdr;
119
120#ifdef compressBound
121 dlen = compressBound (sizeof(my_type_map));
122#else
123 dlen = sizeof(my_type_map) + (sizeof(my_type_map) / 100) + 20;
124 /* documentation says 100.1% oldSize + 12 bytes, but we
125 * should be able to overshoot by more to be safe */
126#endif
127 hdr = GNUNET_malloc (dlen + sizeof(struct GNUNET_MessageHeader));
128 tmp = (char *) &hdr[1];
129 if ((Z_OK != compress2 ((Bytef *) tmp,
130 &dlen,
131 (const Bytef *) &my_type_map,
132 sizeof(my_type_map),
133 9)) ||
134 (dlen >= sizeof(my_type_map)))
135 {
136 /* compression failed, use uncompressed map */
137 dlen = sizeof(my_type_map);
138 GNUNET_memcpy (tmp, &my_type_map, sizeof(my_type_map));
139 hdr->type = htons (GNUNET_MESSAGE_TYPE_CORE_BINARY_TYPE_MAP);
140 }
141 else
142 {
143 /* compression worked, use compressed map */
144 hdr->type = htons (GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP);
145 }
146 hdr->size = htons ((uint16_t) dlen + sizeof(struct GNUNET_MessageHeader));
147 return hdr;
148}
149
150
151/**
152 * Extract a type map from a TYPE_MAP message.
153 *
154 * @param msg a type map message
155 * @return NULL on error
156 */
157struct GSC_TypeMap *
158GSC_TYPEMAP_get_from_message (const struct GNUNET_MessageHeader *msg)
159{
160 struct GSC_TypeMap *ret;
161 uint16_t size;
162 uLongf dlen;
163
164 size = ntohs (msg->size);
165 switch (ntohs (msg->type))
166 {
167 case GNUNET_MESSAGE_TYPE_CORE_BINARY_TYPE_MAP:
168 GNUNET_STATISTICS_update (GSC_stats,
169 gettext_noop ("# type maps received"),
170 1,
171 GNUNET_NO);
172 if (size != sizeof(struct GSC_TypeMap))
173 {
174 GNUNET_break_op (0);
175 return NULL;
176 }
177 ret = GNUNET_new (struct GSC_TypeMap);
178 GNUNET_memcpy (ret, &msg[1], sizeof(struct GSC_TypeMap));
179 return ret;
180
181 case GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP:
182 GNUNET_STATISTICS_update (GSC_stats,
183 gettext_noop ("# type maps received"),
184 1,
185 GNUNET_NO);
186 ret = GNUNET_new (struct GSC_TypeMap);
187 dlen = sizeof(struct GSC_TypeMap);
188 if ((Z_OK != uncompress ((Bytef *) ret,
189 &dlen,
190 (const Bytef *) &msg[1],
191 (uLong) size)) ||
192 (dlen != sizeof(struct GSC_TypeMap)))
193 {
194 GNUNET_break_op (0);
195 GNUNET_free (ret);
196 return NULL;
197 }
198 return ret;
199
200 default:
201 GNUNET_break (0);
202 return NULL;
203 }
204}
205
206
207/**
208 * Send my type map to all connected peers (it got changed).
209 */
210static void
211broadcast_my_type_map ()
212{
213 struct GNUNET_MessageHeader *hdr;
214
215 hdr = GSC_TYPEMAP_compute_type_map_message ();
216 GNUNET_STATISTICS_update (GSC_stats,
217 gettext_noop ("# updates to my type map"),
218 1,
219 GNUNET_NO);
220 GSC_SESSIONS_broadcast_typemap (hdr);
221 GNUNET_free (hdr);
222}
223
224
225/**
226 * Add a set of types to our type map.
227 *
228 * @param types array of message types supported by this peer
229 * @param tlen number of entries in @a types
230 */
231void
232GSC_TYPEMAP_add (const uint16_t *types, unsigned int tlen)
233{
234 unsigned int i;
235 int changed;
236
237 changed = GNUNET_NO;
238 for (i = 0; i < tlen; i++)
239 {
240 if (0 == map_counters[types[i]]++)
241 {
242 my_type_map.bits[types[i] / 32] |= (1 << (types[i] % 32));
243 changed = GNUNET_YES;
244 }
245 }
246 if (GNUNET_YES == changed)
247 {
248 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Typemap changed, broadcasting!\n");
249 rehash_typemap ();
250 broadcast_my_type_map ();
251 }
252}
253
254
255void
256GSC_TYPEMAP_remove (const uint16_t *types, unsigned int tlen)
257{
258 int changed;
259
260 changed = GNUNET_NO;
261 for (unsigned int i = 0; i < tlen; i++)
262 {
263 if (0 == --map_counters[types[i]])
264 {
265 my_type_map.bits[types[i] / 32] &= ~(1 << (types[i] % 32));
266 changed = GNUNET_YES;
267 }
268 }
269 if (GNUNET_YES == changed)
270 {
271 rehash_typemap ();
272 broadcast_my_type_map ();
273 }
274}
275
276
277/**
278 * Test if any of the types from the types array is in the
279 * given type map.
280 *
281 * @param tmap map to test
282 * @param types array of types
283 * @param tcnt number of entries in @a types
284 * @return #GNUNET_YES if a type is in the map, #GNUNET_NO if not
285 */
286int
287GSC_TYPEMAP_test_match (const struct GSC_TypeMap *tmap,
288 const uint16_t *types,
289 unsigned int tcnt)
290{
291 if (NULL == tmap)
292 return GNUNET_NO;
293 if (0 == tcnt)
294 return GNUNET_YES; /* matches all */
295 for (unsigned int i = 0; i < tcnt; i++)
296 if (0 != (tmap->bits[types[i] / 32] & (1 << (types[i] % 32))))
297 return GNUNET_YES;
298 return GNUNET_NO;
299}
300
301
302/**
303 * Add additional types to a given typemap.
304 *
305 * @param tmap map to extend (not changed)
306 * @param types array of types to add
307 * @param tcnt number of entries in @a types
308 * @return updated type map (fresh copy)
309 */
310struct GSC_TypeMap *
311GSC_TYPEMAP_extend (const struct GSC_TypeMap *tmap,
312 const uint16_t *types,
313 unsigned int tcnt)
314{
315 struct GSC_TypeMap *ret;
316
317 ret = GNUNET_new (struct GSC_TypeMap);
318 if (NULL != tmap)
319 GNUNET_memcpy (ret, tmap, sizeof(struct GSC_TypeMap));
320 for (unsigned int i = 0; i < tcnt; i++)
321 ret->bits[types[i] / 32] |= (1 << (types[i] % 32));
322 return ret;
323}
324
325
326/**
327 * Create an empty type map.
328 *
329 * @return an empty type map
330 */
331struct GSC_TypeMap *
332GSC_TYPEMAP_create ()
333{
334 return GNUNET_new (struct GSC_TypeMap);
335}
336
337
338/**
339 * Free the given type map.
340 *
341 * @param tmap a type map
342 */
343void
344GSC_TYPEMAP_destroy (struct GSC_TypeMap *tmap)
345{
346 GNUNET_free (tmap);
347}
348
349
350/**
351 * Initialize typemap subsystem.
352 */
353void
354GSC_TYPEMAP_init ()
355{
356 /* nothing to do */
357}
358
359
360/**
361 * Shutdown typemap subsystem.
362 */
363void
364GSC_TYPEMAP_done ()
365{
366 /* nothing to do */
367}
368
369
370/* end of gnunet-service-core_typemap.c */