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/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
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
27 #include "gnunet_util_lib.h"
28 #include "gnunet_transport_service.h"
29 #include "gnunet-service-core.h"
30 #include "gnunet-service-core_sessions.h"
31 #include "gnunet-service-core_typemap.h"
36 * A type map describing which messages a given neighbour is able
40 uint32_t bits[(UINT16_MAX + 1) / 32];
44 * Bitmap of message types this peer is able to handle.
46 static struct GSC_TypeMap my_type_map;
49 * Counters for message types this peer is able to handle.
51 static uint8_t map_counters[UINT16_MAX + 1];
54 * Current hash of our (uncompressed) type map.
55 * Lazily computed when needed.
57 static struct GNUNET_HashCode my_tm_hash;
60 * Is #my_tm_hash() current with respect to our type map?
62 static int hash_current;
66 * Our type map changed, recompute its hash.
71 hash_current = GNUNET_NO;
76 * Hash the contents of a type map.
78 * @param tm map to hash
79 * @param hc where to store the hash code
82 GSC_TYPEMAP_hash(const struct GSC_TypeMap *tm, struct GNUNET_HashCode *hc)
84 GNUNET_CRYPTO_hash(tm, sizeof(struct GSC_TypeMap), hc);
89 * Check if the given hash matches our current type map.
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
95 GSC_TYPEMAP_check_hash(const struct GNUNET_HashCode *hc)
97 if (GNUNET_NO == hash_current)
99 GSC_TYPEMAP_hash(&my_type_map, &my_tm_hash);
100 hash_current = GNUNET_YES;
102 return (0 == memcmp(hc, &my_tm_hash, sizeof(struct GNUNET_HashCode)))
109 * Compute a type map message for this peer.
111 * @return this peers current type map message.
113 struct GNUNET_MessageHeader *
114 GSC_TYPEMAP_compute_type_map_message()
118 struct GNUNET_MessageHeader *hdr;
121 dlen = compressBound(sizeof(my_type_map));
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 */
127 hdr = GNUNET_malloc(dlen + sizeof(struct GNUNET_MessageHeader));
128 tmp = (char *)&hdr[1];
129 if ((Z_OK != compress2((Bytef *)tmp,
131 (const Bytef *)&my_type_map,
134 (dlen >= sizeof(my_type_map)))
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);
143 /* compression worked, use compressed map */
144 hdr->type = htons(GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP);
146 hdr->size = htons((uint16_t)dlen + sizeof(struct GNUNET_MessageHeader));
152 * Extract a type map from a TYPE_MAP message.
154 * @param msg a type map message
155 * @return NULL on error
158 GSC_TYPEMAP_get_from_message(const struct GNUNET_MessageHeader *msg)
160 struct GSC_TypeMap *ret;
164 size = ntohs(msg->size);
165 switch (ntohs(msg->type))
167 case GNUNET_MESSAGE_TYPE_CORE_BINARY_TYPE_MAP:
168 GNUNET_STATISTICS_update(GSC_stats,
169 gettext_noop("# type maps received"),
172 if (size != sizeof(struct GSC_TypeMap))
177 ret = GNUNET_new(struct GSC_TypeMap);
178 GNUNET_memcpy(ret, &msg[1], sizeof(struct GSC_TypeMap));
181 case GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP:
182 GNUNET_STATISTICS_update(GSC_stats,
183 gettext_noop("# type maps received"),
186 ret = GNUNET_new(struct GSC_TypeMap);
187 dlen = sizeof(struct GSC_TypeMap);
188 if ((Z_OK != uncompress((Bytef *)ret,
190 (const Bytef *)&msg[1],
192 (dlen != sizeof(struct GSC_TypeMap)))
208 * Send my type map to all connected peers (it got changed).
211 broadcast_my_type_map()
213 struct GNUNET_MessageHeader *hdr;
215 hdr = GSC_TYPEMAP_compute_type_map_message();
216 GNUNET_STATISTICS_update(GSC_stats,
217 gettext_noop("# updates to my type map"),
220 GSC_SESSIONS_broadcast_typemap(hdr);
226 * Add a set of types to our type map.
228 * @param types array of message types supported by this peer
229 * @param tlen number of entries in @a types
232 GSC_TYPEMAP_add(const uint16_t *types, unsigned int tlen)
238 for (i = 0; i < tlen; i++)
240 if (0 == map_counters[types[i]]++)
242 my_type_map.bits[types[i] / 32] |= (1 << (types[i] % 32));
243 changed = GNUNET_YES;
246 if (GNUNET_YES == changed)
248 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Typemap changed, broadcasting!\n");
250 broadcast_my_type_map();
256 * Remove a set of types from our type map.
258 * @param types array of types to remove
259 * @param tlen length of the @a types array
262 GSC_TYPEMAP_remove(const uint16_t *types, unsigned int tlen)
267 for (unsigned int i = 0; i < tlen; i++)
269 if (0 == --map_counters[types[i]])
271 my_type_map.bits[types[i] / 32] &= ~(1 << (types[i] % 32));
272 changed = GNUNET_YES;
275 if (GNUNET_YES == changed)
278 broadcast_my_type_map();
284 * Test if any of the types from the types array is in the
287 * @param tmap map to test
288 * @param types array of types
289 * @param tcnt number of entries in @a types
290 * @return #GNUNET_YES if a type is in the map, #GNUNET_NO if not
293 GSC_TYPEMAP_test_match(const struct GSC_TypeMap *tmap,
294 const uint16_t *types,
300 return GNUNET_YES; /* matches all */
301 for (unsigned int i = 0; i < tcnt; i++)
302 if (0 != (tmap->bits[types[i] / 32] & (1 << (types[i] % 32))))
309 * Add additional types to a given typemap.
311 * @param tmap map to extend (not changed)
312 * @param types array of types to add
313 * @param tcnt number of entries in @a types
314 * @return updated type map (fresh copy)
317 GSC_TYPEMAP_extend(const struct GSC_TypeMap *tmap,
318 const uint16_t *types,
321 struct GSC_TypeMap *ret;
323 ret = GNUNET_new(struct GSC_TypeMap);
325 GNUNET_memcpy(ret, tmap, sizeof(struct GSC_TypeMap));
326 for (unsigned int i = 0; i < tcnt; i++)
327 ret->bits[types[i] / 32] |= (1 << (types[i] % 32));
333 * Create an empty type map.
335 * @return an empty type map
340 return GNUNET_new(struct GSC_TypeMap);
345 * Free the given type map.
347 * @param tmap a type map
350 GSC_TYPEMAP_destroy(struct GSC_TypeMap *tmap)
357 * Initialize typemap subsystem.
367 * Shutdown typemap subsystem.
375 /* end of gnunet-service-core_typemap.c */