2 This file is part of GNUnet.
3 Copyright (C) 2011-2014 GNUnet e.V.
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.
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.
17 * @file core/gnunet-service-core_typemap.c
18 * @brief management of map that specifies which message types this peer supports
19 * @author Christian Grothoff
22 #include "gnunet_util_lib.h"
23 #include "gnunet_transport_service.h"
24 #include "gnunet-service-core.h"
25 #include "gnunet-service-core_sessions.h"
26 #include "gnunet-service-core_typemap.h"
31 * A type map describing which messages a given neighbour is able
36 uint32_t bits[(UINT16_MAX + 1) / 32];
40 * Bitmap of message types this peer is able to handle.
42 static struct GSC_TypeMap my_type_map;
45 * Counters for message types this peer is able to handle.
47 static uint8_t map_counters[UINT16_MAX + 1];
50 * Current hash of our (uncompressed) type map.
51 * Lazily computed when needed.
53 static struct GNUNET_HashCode my_tm_hash;
56 * Is #my_tm_hash() current with respect to our type map?
58 static int hash_current;
62 * Our type map changed, recompute its hash.
67 hash_current = GNUNET_NO;
72 * Hash the contents of a type map.
74 * @param tm map to hash
75 * @param hc where to store the hash code
78 GSC_TYPEMAP_hash (const struct GSC_TypeMap *tm,
79 struct GNUNET_HashCode *hc)
81 GNUNET_CRYPTO_hash (tm,
82 sizeof (struct GSC_TypeMap),
88 * Check if the given hash matches our current type map.
90 * @param hc hash code to check if it matches our type map
91 * @return #GNUNET_YES if the hash matches, #GNUNET_NO if not
94 GSC_TYPEMAP_check_hash (const struct GNUNET_HashCode *hc)
96 if (GNUNET_NO == hash_current)
98 GSC_TYPEMAP_hash (&my_type_map,
100 hash_current = GNUNET_YES;
102 return (0 == memcmp (hc, &my_tm_hash, sizeof (struct GNUNET_HashCode)))
103 ? GNUNET_YES : GNUNET_NO;
108 * Compute a type map message for this peer.
110 * @return this peers current type map message.
112 struct GNUNET_MessageHeader *
113 GSC_TYPEMAP_compute_type_map_message ()
117 struct GNUNET_MessageHeader *hdr;
120 dlen = compressBound (sizeof (my_type_map));
122 dlen = sizeof (my_type_map) + (sizeof (my_type_map) / 100) + 20;
123 /* documentation says 100.1% oldSize + 12 bytes, but we
124 * should be able to overshoot by more to be safe */
126 hdr = GNUNET_malloc (dlen + sizeof (struct GNUNET_MessageHeader));
127 tmp = (char *) &hdr[1];
129 compress2 ((Bytef *) tmp, &dlen, (const Bytef *) &my_type_map,
130 sizeof (my_type_map), 9)) || (dlen >= sizeof (my_type_map)))
132 /* compression failed, use uncompressed map */
133 dlen = sizeof (my_type_map);
134 GNUNET_memcpy (tmp, &my_type_map, sizeof (my_type_map));
135 hdr->type = htons (GNUNET_MESSAGE_TYPE_CORE_BINARY_TYPE_MAP);
139 /* compression worked, use compressed map */
140 hdr->type = htons (GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP);
142 hdr->size = htons ((uint16_t) dlen + sizeof (struct GNUNET_MessageHeader));
148 * Extract a type map from a TYPE_MAP message.
150 * @param msg a type map message
151 * @return NULL on error
154 GSC_TYPEMAP_get_from_message (const struct GNUNET_MessageHeader *msg)
156 struct GSC_TypeMap *ret;
160 size = ntohs (msg->size);
161 switch (ntohs (msg->type))
163 case GNUNET_MESSAGE_TYPE_CORE_BINARY_TYPE_MAP:
164 GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# type maps received"),
166 if (size != sizeof (struct GSC_TypeMap))
171 ret = GNUNET_new (struct GSC_TypeMap);
172 GNUNET_memcpy (ret, &msg[1], sizeof (struct GSC_TypeMap));
174 case GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP:
175 GNUNET_STATISTICS_update (GSC_stats,
176 gettext_noop ("# type maps received"),
179 ret = GNUNET_new (struct GSC_TypeMap);
180 dlen = sizeof (struct GSC_TypeMap);
182 uncompress ((Bytef *) ret, &dlen, (const Bytef *) &msg[1],
183 (uLong) size)) || (dlen != sizeof (struct GSC_TypeMap)))
198 * Send my type map to all connected peers (it got changed).
201 broadcast_my_type_map ()
203 struct GNUNET_MessageHeader *hdr;
205 hdr = GSC_TYPEMAP_compute_type_map_message ();
206 GNUNET_STATISTICS_update (GSC_stats,
207 gettext_noop ("# updates to my type map"),
210 GSC_SESSIONS_broadcast_typemap (hdr);
216 * Add a set of types to our type map.
218 * @param types array of message types supported by this peer
219 * @param tlen number of entries in @a types
222 GSC_TYPEMAP_add (const uint16_t *types,
229 for (i = 0; i < tlen; i++)
231 if (0 == map_counters[types[i]]++)
233 my_type_map.bits[types[i] / 32] |= (1 << (types[i] % 32));
234 changed = GNUNET_YES;
237 if (GNUNET_YES == changed)
239 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
240 "Typemap changed, broadcasting!\n");
242 broadcast_my_type_map ();
248 * Remove a set of types from our type map.
250 * @param types array of types to remove
251 * @param tlen length of the @a types array
254 GSC_TYPEMAP_remove (const uint16_t *types,
260 for (unsigned int i = 0; i < tlen; i++)
262 if (0 == --map_counters[types[i]])
264 my_type_map.bits[types[i] / 32] &= ~(1 << (types[i] % 32));
265 changed = GNUNET_YES;
268 if (GNUNET_YES == changed)
271 broadcast_my_type_map ();
277 * Test if any of the types from the types array is in the
280 * @param tmap map to test
281 * @param types array of types
282 * @param tcnt number of entries in @a types
283 * @return #GNUNET_YES if a type is in the map, #GNUNET_NO if not
286 GSC_TYPEMAP_test_match (const struct GSC_TypeMap *tmap,
287 const uint16_t *types,
293 return GNUNET_YES; /* matches all */
294 for (unsigned int i = 0; i < tcnt; i++)
295 if (0 != (tmap->bits[types[i] / 32] & (1 << (types[i] % 32))))
302 * Add additional types to a given typemap.
304 * @param tmap map to extend (not changed)
305 * @param types array of types to add
306 * @param tcnt number of entries in @a types
307 * @return updated type map (fresh copy)
310 GSC_TYPEMAP_extend (const struct GSC_TypeMap *tmap,
311 const uint16_t *types,
314 struct GSC_TypeMap *ret;
316 ret = GNUNET_new (struct GSC_TypeMap);
318 GNUNET_memcpy (ret, tmap, sizeof (struct GSC_TypeMap));
319 for (unsigned int i = 0; i < tcnt; i++)
320 ret->bits[types[i] / 32] |= (1 << (types[i] % 32));
326 * Create an empty type map.
328 * @return an empty type map
331 GSC_TYPEMAP_create ()
333 return GNUNET_new (struct GSC_TypeMap);
338 * Free the given type map.
340 * @param tmap a type map
343 GSC_TYPEMAP_destroy (struct GSC_TypeMap *tmap)
350 * Initialize typemap subsystem.
360 * Shutdown typemap subsystem.
368 /* end of gnunet-service-core_typemap.c */