X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fcore%2Fgnunet-service-core_typemap.c;h=0600f59ef937af81afb905438ae8d222961a5767;hb=17f5db6f7c8d60930367738b3d872fbf891486ee;hp=dfd0b88882eaf48101b5e64894a502a04b696f62;hpb=d7591587eb28a40e44a3065c30ec1b60a9bcba68;p=oweals%2Fgnunet.git diff --git a/src/core/gnunet-service-core_typemap.c b/src/core/gnunet-service-core_typemap.c index dfd0b8888..0600f59ef 100644 --- a/src/core/gnunet-service-core_typemap.c +++ b/src/core/gnunet-service-core_typemap.c @@ -1,70 +1,111 @@ +/* + This file is part of GNUnet. + Copyright (C) 2011-2014 GNUnet e.V. + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +/** + * @file core/gnunet-service-core_typemap.c + * @brief management of map that specifies which message types this peer supports + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_transport_service.h" +#include "gnunet-service-core.h" +#include "gnunet-service-core_sessions.h" +#include "gnunet-service-core_typemap.h" +#include + /** * A type map describing which messages a given neighbour is able * to process. */ -struct GSC_TypeMap +struct GSC_TypeMap { uint32_t bits[(UINT16_MAX + 1) / 32]; }; - /** * Bitmap of message types this peer is able to handle. */ -static uint32_t my_type_map[(UINT16_MAX + 1) / 32]; +static struct GSC_TypeMap my_type_map; +/** + * Counters for message types this peer is able to handle. + */ +static uint8_t map_counters[UINT16_MAX + 1]; /** - * Add a set of types to our type map. + * Current hash of our (uncompressed) type map. + * Lazily computed when needed. */ -void -GSC_TYPEMAP_add (const uint16_t *types, - unsigned int tlen) -{ - unsigned int i; +static struct GNUNET_HashCode my_tm_hash; - for (i=0;i 0) - broadcast_my_type_map (); +/** + * Is #my_tm_hash() current with respect to our type map? + */ +static int hash_current; + + +/** + * Our type map changed, recompute its hash. + */ +static void +rehash_typemap () +{ + hash_current = GNUNET_NO; } /** - * Remove a set of types from our type map. + * Hash the contents of a type map. + * + * @param tm map to hash + * @param hc where to store the hash code */ void -GSC_TYPEMAP_remove (const uint16_t *types, - unsigned int tlen) +GSC_TYPEMAP_hash (const struct GSC_TypeMap *tm, + struct GNUNET_HashCode *hc) { - /* rebuild my_type_map */ - memset (my_type_map, 0, sizeof (my_type_map)); - for (pos = clients; NULL != pos; pos = pos->next) - { - wtypes = (const uint16_t *) &pos[1]; - for (i = 0; i < pos->tcnt; i++) - my_type_map[wtypes[i] / 32] |= (1 << (wtypes[i] % 32)); - } - broadcast_my_type_map (); + GNUNET_CRYPTO_hash (tm, + sizeof (struct GSC_TypeMap), + hc); } /** - * Test if any of the types from the types array is in the - * given type map. + * Check if the given hash matches our current type map. * - * @param map map to test - * @param types array of types - * @param tcnt number of entries in types - * @return GNUNET_YES if a type is in the map, GNUNET_NO if not - */ + * @param hc hash code to check if it matches our type map + * @return #GNUNET_YES if the hash matches, #GNUNET_NO if not + */ int -GSC_TYPEMAP_test_match (struct GSC_TypeMap *tmap, - const uint16_t *types, - unsigned int tcnt) +GSC_TYPEMAP_check_hash (const struct GNUNET_HashCode *hc) { - return GNUNET_YES; /* FIXME */ + if (GNUNET_NO == hash_current) + { + GSC_TYPEMAP_hash (&my_type_map, + &my_tm_hash); + hash_current = GNUNET_YES; + } + return (0 == memcmp (hc, &my_tm_hash, sizeof (struct GNUNET_HashCode))) + ? GNUNET_YES : GNUNET_NO; } @@ -73,8 +114,8 @@ GSC_TYPEMAP_test_match (struct GSC_TypeMap *tmap, * * @return this peers current type map message. */ -static struct GNUNET_MessageHeader * -compute_type_map_message () +struct GNUNET_MessageHeader * +GSC_TYPEMAP_compute_type_map_message () { char *tmp; uLongf dlen; @@ -88,57 +129,76 @@ compute_type_map_message () * should be able to overshoot by more to be safe */ #endif hdr = GNUNET_malloc (dlen + sizeof (struct GNUNET_MessageHeader)); - hdr->size = htons ((uint16_t) dlen + sizeof (struct GNUNET_MessageHeader)); tmp = (char *) &hdr[1]; if ((Z_OK != - compress2 ((Bytef *) tmp, &dlen, (const Bytef *) my_type_map, + compress2 ((Bytef *) tmp, &dlen, (const Bytef *) &my_type_map, sizeof (my_type_map), 9)) || (dlen >= sizeof (my_type_map))) { + /* compression failed, use uncompressed map */ dlen = sizeof (my_type_map); - memcpy (tmp, my_type_map, sizeof (my_type_map)); + GNUNET_memcpy (tmp, &my_type_map, sizeof (my_type_map)); hdr->type = htons (GNUNET_MESSAGE_TYPE_CORE_BINARY_TYPE_MAP); } else { + /* compression worked, use compressed map */ hdr->type = htons (GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP); } + hdr->size = htons ((uint16_t) dlen + sizeof (struct GNUNET_MessageHeader)); return hdr; } /** - * Send a type map message to the neighbour. + * Extract a type map from a TYPE_MAP message. * - * @param cls the type map message - * @param key neighbour's identity - * @param value 'struct Neighbour' of the target - * @return always GNUNET_OK + * @param msg a type map message + * @return NULL on error */ -static int -send_type_map_to_neighbour (void *cls, const GNUNET_HashCode * key, void *value) +struct GSC_TypeMap * +GSC_TYPEMAP_get_from_message (const struct GNUNET_MessageHeader *msg) { - struct GNUNET_MessageHeader *hdr = cls; - struct Neighbour *n = value; - struct MessageEntry *m; + struct GSC_TypeMap *ret; uint16_t size; + uLongf dlen; - if (n == &self) - return GNUNET_OK; - size = ntohs (hdr->size); - m = GNUNET_malloc (sizeof (struct MessageEntry) + size); - memcpy (&m[1], hdr, size); - m->deadline = GNUNET_TIME_UNIT_FOREVER_ABS; - m->slack_deadline = GNUNET_TIME_UNIT_FOREVER_ABS; - m->priority = UINT_MAX; - m->sender_status = n->status; - m->size = size; - m->next = n->messages; - n->messages = m; - return GNUNET_OK; + size = ntohs (msg->size); + switch (ntohs (msg->type)) + { + case GNUNET_MESSAGE_TYPE_CORE_BINARY_TYPE_MAP: + GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# type maps received"), + 1, GNUNET_NO); + if (size != sizeof (struct GSC_TypeMap)) + { + GNUNET_break_op (0); + return NULL; + } + ret = GNUNET_new (struct GSC_TypeMap); + GNUNET_memcpy (ret, &msg[1], sizeof (struct GSC_TypeMap)); + return ret; + case GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP: + GNUNET_STATISTICS_update (GSC_stats, + gettext_noop ("# type maps received"), + 1, + GNUNET_NO); + ret = GNUNET_new (struct GSC_TypeMap); + dlen = sizeof (struct GSC_TypeMap); + if ((Z_OK != + uncompress ((Bytef *) ret, &dlen, (const Bytef *) &msg[1], + (uLong) size)) || (dlen != sizeof (struct GSC_TypeMap))) + { + GNUNET_break_op (0); + GNUNET_free (ret); + return NULL; + } + return ret; + default: + GNUNET_break (0); + return NULL; + } } - /** * Send my type map to all connected peers (it got changed). */ @@ -147,13 +207,167 @@ broadcast_my_type_map () { struct GNUNET_MessageHeader *hdr; - if (NULL == neighbours) - return; - hdr = compute_type_map_message (); - GNUNET_CONTAINER_multihashmap_iterate (neighbours, - &send_type_map_to_neighbour, hdr); + hdr = GSC_TYPEMAP_compute_type_map_message (); + GNUNET_STATISTICS_update (GSC_stats, + gettext_noop ("# updates to my type map"), + 1, + GNUNET_NO); + GSC_SESSIONS_broadcast_typemap (hdr); GNUNET_free (hdr); } +/** + * Add a set of types to our type map. + * + * @param types array of message types supported by this peer + * @param tlen number of entries in @a types + */ +void +GSC_TYPEMAP_add (const uint16_t *types, + unsigned int tlen) +{ + unsigned int i; + int changed; + + changed = GNUNET_NO; + for (i = 0; i < tlen; i++) + { + if (0 == map_counters[types[i]]++) + { + my_type_map.bits[types[i] / 32] |= (1 << (types[i] % 32)); + changed = GNUNET_YES; + } + } + if (GNUNET_YES == changed) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Typemap changed, broadcasting!\n"); + rehash_typemap (); + broadcast_my_type_map (); + } +} + + +/** + * Remove a set of types from our type map. + * + * @param types array of types to remove + * @param tlen length of the @a types array + */ +void +GSC_TYPEMAP_remove (const uint16_t *types, + unsigned int tlen) +{ + int changed; + + changed = GNUNET_NO; + for (unsigned int i = 0; i < tlen; i++) + { + if (0 == --map_counters[types[i]]) + { + my_type_map.bits[types[i] / 32] &= ~(1 << (types[i] % 32)); + changed = GNUNET_YES; + } + } + if (GNUNET_YES == changed) + { + rehash_typemap (); + broadcast_my_type_map (); + } +} + + +/** + * Test if any of the types from the types array is in the + * given type map. + * + * @param tmap map to test + * @param types array of types + * @param tcnt number of entries in @a types + * @return #GNUNET_YES if a type is in the map, #GNUNET_NO if not + */ +int +GSC_TYPEMAP_test_match (const struct GSC_TypeMap *tmap, + const uint16_t *types, + unsigned int tcnt) +{ + if (NULL == tmap) + return GNUNET_NO; + if (0 == tcnt) + return GNUNET_YES; /* matches all */ + for (unsigned int i = 0; i < tcnt; i++) + if (0 != (tmap->bits[types[i] / 32] & (1 << (types[i] % 32)))) + return GNUNET_YES; + return GNUNET_NO; +} + + +/** + * Add additional types to a given typemap. + * + * @param tmap map to extend (not changed) + * @param types array of types to add + * @param tcnt number of entries in @a types + * @return updated type map (fresh copy) + */ +struct GSC_TypeMap * +GSC_TYPEMAP_extend (const struct GSC_TypeMap *tmap, + const uint16_t *types, + unsigned int tcnt) +{ + struct GSC_TypeMap *ret; + + ret = GNUNET_new (struct GSC_TypeMap); + if (NULL != tmap) + GNUNET_memcpy (ret, tmap, sizeof (struct GSC_TypeMap)); + for (unsigned int i = 0; i < tcnt; i++) + ret->bits[types[i] / 32] |= (1 << (types[i] % 32)); + return ret; +} + + +/** + * Create an empty type map. + * + * @return an empty type map + */ +struct GSC_TypeMap * +GSC_TYPEMAP_create () +{ + return GNUNET_new (struct GSC_TypeMap); +} + + +/** + * Free the given type map. + * + * @param tmap a type map + */ +void +GSC_TYPEMAP_destroy (struct GSC_TypeMap *tmap) +{ + GNUNET_free (tmap); +} + + +/** + * Initialize typemap subsystem. + */ +void +GSC_TYPEMAP_init () +{ + /* nothing to do */ +} + + +/** + * Shutdown typemap subsystem. + */ +void +GSC_TYPEMAP_done () +{ + /* nothing to do */ +} +/* end of gnunet-service-core_typemap.c */