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.
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/>.
20 * @file core/gnunet-service-core_typemap.c
21 * @brief management of map that specifies which message types this peer supports
22 * @author Christian Grothoff
25 #include "gnunet_util_lib.h"
26 #include "gnunet_transport_service.h"
27 #include "gnunet-service-core.h"
28 #include "gnunet-service-core_sessions.h"
29 #include "gnunet-service-core_typemap.h"
34 * A type map describing which messages a given neighbour is able
39 uint32_t bits[(UINT16_MAX + 1) / 32];
43 * Bitmap of message types this peer is able to handle.
45 static struct GSC_TypeMap my_type_map;
48 * Counters for message types this peer is able to handle.
50 static uint8_t map_counters[UINT16_MAX + 1];
53 * Current hash of our (uncompressed) type map.
54 * Lazily computed when needed.
56 static struct GNUNET_HashCode my_tm_hash;
59 * Is #my_tm_hash() current with respect to our type map?
61 static int hash_current;
65 * Our type map changed, recompute its hash.
70 hash_current = GNUNET_NO;
75 * Hash the contents of a type map.
77 * @param tm map to hash
78 * @param hc where to store the hash code
81 GSC_TYPEMAP_hash (const struct GSC_TypeMap *tm,
82 struct GNUNET_HashCode *hc)
84 GNUNET_CRYPTO_hash (tm,
85 sizeof (struct GSC_TypeMap),
91 * Check if the given hash matches our current type map.
93 * @param hc hash code to check if it matches our type map
94 * @return #GNUNET_YES if the hash matches, #GNUNET_NO if not
97 GSC_TYPEMAP_check_hash (const struct GNUNET_HashCode *hc)
99 if (GNUNET_NO == hash_current)
101 GSC_TYPEMAP_hash (&my_type_map,
103 hash_current = GNUNET_YES;
105 return (0 == memcmp (hc, &my_tm_hash, sizeof (struct GNUNET_HashCode)))
106 ? GNUNET_YES : GNUNET_NO;
111 * Compute a type map message for this peer.
113 * @return this peers current type map message.
115 struct GNUNET_MessageHeader *
116 GSC_TYPEMAP_compute_type_map_message ()
120 struct GNUNET_MessageHeader *hdr;
123 dlen = compressBound (sizeof (my_type_map));
125 dlen = sizeof (my_type_map) + (sizeof (my_type_map) / 100) + 20;
126 /* documentation says 100.1% oldSize + 12 bytes, but we
127 * should be able to overshoot by more to be safe */
129 hdr = GNUNET_malloc (dlen + sizeof (struct GNUNET_MessageHeader));
130 tmp = (char *) &hdr[1];
132 compress2 ((Bytef *) tmp, &dlen, (const Bytef *) &my_type_map,
133 sizeof (my_type_map), 9)) || (dlen >= sizeof (my_type_map)))
135 /* compression failed, use uncompressed map */
136 dlen = sizeof (my_type_map);
137 GNUNET_memcpy (tmp, &my_type_map, sizeof (my_type_map));
138 hdr->type = htons (GNUNET_MESSAGE_TYPE_CORE_BINARY_TYPE_MAP);
142 /* compression worked, use compressed map */
143 hdr->type = htons (GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP);
145 hdr->size = htons ((uint16_t) dlen + sizeof (struct GNUNET_MessageHeader));
151 * Extract a type map from a TYPE_MAP message.
153 * @param msg a type map message
154 * @return NULL on error
157 GSC_TYPEMAP_get_from_message (const struct GNUNET_MessageHeader *msg)
159 struct GSC_TypeMap *ret;
163 size = ntohs (msg->size);
164 switch (ntohs (msg->type))
166 case GNUNET_MESSAGE_TYPE_CORE_BINARY_TYPE_MAP:
167 GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# type maps received"),
169 if (size != sizeof (struct GSC_TypeMap))
174 ret = GNUNET_new (struct GSC_TypeMap);
175 GNUNET_memcpy (ret, &msg[1], sizeof (struct GSC_TypeMap));
177 case GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP:
178 GNUNET_STATISTICS_update (GSC_stats,
179 gettext_noop ("# type maps received"),
182 ret = GNUNET_new (struct GSC_TypeMap);
183 dlen = sizeof (struct GSC_TypeMap);
185 uncompress ((Bytef *) ret, &dlen, (const Bytef *) &msg[1],
186 (uLong) size)) || (dlen != sizeof (struct GSC_TypeMap)))
201 * Send my type map to all connected peers (it got changed).
204 broadcast_my_type_map ()
206 struct GNUNET_MessageHeader *hdr;
208 hdr = GSC_TYPEMAP_compute_type_map_message ();
209 GNUNET_STATISTICS_update (GSC_stats,
210 gettext_noop ("# updates to my type map"),
213 GSC_SESSIONS_broadcast_typemap (hdr);
219 * Add a set of types to our type map.
221 * @param types array of message types supported by this peer
222 * @param tlen number of entries in @a types
225 GSC_TYPEMAP_add (const uint16_t *types,
232 for (i = 0; i < tlen; i++)
234 if (0 == map_counters[types[i]]++)
236 my_type_map.bits[types[i] / 32] |= (1 << (types[i] % 32));
237 changed = GNUNET_YES;
240 if (GNUNET_YES == changed)
242 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
243 "Typemap changed, broadcasting!\n");
245 broadcast_my_type_map ();
251 * Remove a set of types from our type map.
253 * @param types array of types to remove
254 * @param tlen length of the @a types array
257 GSC_TYPEMAP_remove (const uint16_t *types,
263 for (unsigned int i = 0; i < tlen; i++)
265 if (0 == --map_counters[types[i]])
267 my_type_map.bits[types[i] / 32] &= ~(1 << (types[i] % 32));
268 changed = GNUNET_YES;
271 if (GNUNET_YES == changed)
274 broadcast_my_type_map ();
280 * Test if any of the types from the types array is in the
283 * @param tmap map to test
284 * @param types array of types
285 * @param tcnt number of entries in @a types
286 * @return #GNUNET_YES if a type is in the map, #GNUNET_NO if not
289 GSC_TYPEMAP_test_match (const struct GSC_TypeMap *tmap,
290 const uint16_t *types,
296 return GNUNET_YES; /* matches all */
297 for (unsigned int i = 0; i < tcnt; i++)
298 if (0 != (tmap->bits[types[i] / 32] & (1 << (types[i] % 32))))
305 * Add additional types to a given typemap.
307 * @param tmap map to extend (not changed)
308 * @param types array of types to add
309 * @param tcnt number of entries in @a types
310 * @return updated type map (fresh copy)
313 GSC_TYPEMAP_extend (const struct GSC_TypeMap *tmap,
314 const uint16_t *types,
317 struct GSC_TypeMap *ret;
319 ret = GNUNET_new (struct GSC_TypeMap);
321 GNUNET_memcpy (ret, tmap, sizeof (struct GSC_TypeMap));
322 for (unsigned int i = 0; i < tcnt; i++)
323 ret->bits[types[i] / 32] |= (1 << (types[i] % 32));
329 * Create an empty type map.
331 * @return an empty type map
334 GSC_TYPEMAP_create ()
336 return GNUNET_new (struct GSC_TypeMap);
341 * Free the given type map.
343 * @param tmap a type map
346 GSC_TYPEMAP_destroy (struct GSC_TypeMap *tmap)
353 * Initialize typemap subsystem.
363 * Shutdown typemap subsystem.
371 /* end of gnunet-service-core_typemap.c */