libgnunet_plugin_block_template_la_SOURCES = \
plugin_block_template.c
libgnunet_plugin_block_template_la_LIBADD = \
- libgnunetblock.la \
+ libgnunetblockgroup.la \
$(top_builddir)/src/util/libgnunetutil.la \
$(LTLIBINTL)
libgnunet_plugin_block_template_la_LDFLAGS = \
libgnunet_plugin_block_test_la_SOURCES = \
plugin_block_test.c
libgnunet_plugin_block_test_la_LIBADD = \
- libgnunetblock.la \
- $(top_builddir)/src/util/libgnunetutil.la \
+ libgnunetblockgroup.la \
+$(top_builddir)/src/util/libgnunetutil.la \
$(LTLIBINTL)
libgnunet_plugin_block_test_la_LDFLAGS = \
$(GN_PLUGIN_LDFLAGS)
* Serialize state of a block group.
*
* @param bg group to serialize
+ * @param[out] nonce set to the nonce of the @a bg
* @param[out] raw_data set to the serialized state
* @param[out] raw_data_size set to the number of bytes in @a raw_data
* @return #GNUNET_OK on success, #GNUNET_NO if serialization is not
*/
static int
bf_group_serialize_cb (struct GNUNET_BLOCK_Group *bg,
+ uint32_t *nonce,
void **raw_data,
size_t *raw_data_size)
{
GNUNET_break (0);
return GNUNET_SYSERR;
}
+ *nonce = gi->bf_mutator;
*raw_data = raw;
*raw_data_size = gi->bf_size;
return GNUNET_OK;
}
+/**
+ * Mark elements as "seen" using a hash of the element. Not supported
+ * by all block plugins.
+ *
+ * @param bg group to update
+ * @param seen_results results already seen
+ * @param seen_results_count number of entries in @a seen_results
+ */
+static void
+bf_group_mark_seen_cb (struct GNUNET_BLOCK_Group *bg,
+ const struct GNUNET_HashCode *seen_results,
+ unsigned int seen_results_count)
+{
+ struct BfGroupInternals *gi = bg->internal_cls;
+
+ for (unsigned int i=0;i<seen_results_count;i++)
+ {
+ struct GNUNET_HashCode mhash;
+
+ GNUNET_BLOCK_mingle_hash (&seen_results[i],
+ gi->bf_mutator,
+ &mhash);
+ GNUNET_CONTAINER_bloomfilter_add (gi->bf,
+ &mhash);
+ }
+}
+
+
+/**
+ * Merge two groups, if possible. Not supported by all block plugins,
+ * can also fail if the nonces were different.
+ *
+ * @param bg1 group to update
+ * @param bg2 group to merge into @a bg1
+ * @return #GNUNET_OK on success, #GNUNET_NO if the nonces were different and thus
+ * we failed.
+ */
+static int
+bf_group_merge_cb (struct GNUNET_BLOCK_Group *bg1,
+ const struct GNUNET_BLOCK_Group *bg2)
+{
+ struct BfGroupInternals *gi1 = bg1->internal_cls;
+ struct BfGroupInternals *gi2 = bg2->internal_cls;
+
+ if (gi1->bf_mutator != gi2->bf_mutator)
+ return GNUNET_NO;
+ if (gi1->bf_size != gi2->bf_size)
+ return GNUNET_NO;
+ GNUNET_CONTAINER_bloomfilter_or2 (gi1->bf,
+ gi2->bf);
+ return GNUNET_OK;
+}
+
+
/**
* Destroy resources used by a block group.
*
bg = GNUNET_new (struct GNUNET_BLOCK_Group);
bg->type = type;
bg->serialize_cb = &bf_group_serialize_cb;
+ bg->mark_seen_cb = &bf_group_mark_seen_cb;
+ bg->merge_cb = &bf_group_merge_cb;
bg->destroy_cb = &bf_group_destroy_cb;
bg->internal_cls = gi;
return bg;
GNUNET_BLOCK_GROUP_bf_test_and_set (struct GNUNET_BLOCK_Group *bg,
const struct GNUNET_HashCode *hc)
{
- struct BfGroupInternals *gi = bg->internal_cls;
+ struct BfGroupInternals *gi;
struct GNUNET_HashCode mhash;
+ if (NULL == bg)
+ return GNUNET_NO;
+ gi = bg->internal_cls;
GNUNET_BLOCK_mingle_hash (hc,
gi->bf_mutator,
&mhash);
* Serialize state of a block group.
*
* @param bg group to serialize
+ * @param[out] nonce set to the nonce of the @a bg
* @param[out] raw_data set to the serialized state
* @param[out] raw_data_size set to the number of bytes in @a raw_data
* @return #GNUNET_OK on success, #GNUNET_NO if serialization is not
*/
int
GNUNET_BLOCK_group_serialize (struct GNUNET_BLOCK_Group *bg,
+ uint32_t *nonce,
void **raw_data,
size_t *raw_data_size)
{
+ *nonce = 0;
*raw_data = NULL;
*raw_data_size = 0;
if (NULL == bg)
if (NULL == bg->serialize_cb)
return GNUNET_NO;
return bg->serialize_cb (bg,
+ nonce,
raw_data,
raw_data_size);
}
}
+/**
+ * Try merging two block groups. Afterwards, @a bg1 should remain
+ * valid and contain the rules from both @a bg1 and @bg2, and
+ * @a bg2 should be destroyed (as part of this call). The latter
+ * should happen even if merging is not supported.
+ *
+ * @param[in,out] bg1 first group to merge, is updated
+ * @param bg2 second group to merge, is destroyed
+ * @return #GNUNET_OK on success,
+ * #GNUNET_NO if merge failed due to different nonce
+ * #GNUNET_SYSERR if merging is not supported
+ */
+int
+GNUNET_BLOCK_group_merge (struct GNUNET_BLOCK_Group *bg1,
+ struct GNUNET_BLOCK_Group *bg2)
+{
+ int ret;
+
+ if (NULL == bg2)
+ return GNUNET_OK;
+ if (NULL == bg1)
+ {
+ bg2->destroy_cb (bg2);
+ return GNUNET_OK;
+ }
+ if (NULL == bg1->merge_cb)
+ return GNUNET_SYSERR;
+ GNUNET_assert (bg1->merge_cb == bg1->merge_cb);
+ ret = bg1->merge_cb (bg1,
+ bg2);
+ bg2->destroy_cb (bg2);
+ return ret;
+}
+
+
/**
* Find a plugin for the given type.
*
enum GNUNET_BLOCK_Type type,
uint32_t nonce,
const void *raw_data,
- size_t raw_data_size)
+ size_t raw_data_size,
+ ...)
{
struct GNUNET_BLOCK_PluginFunctions *plugin;
+ struct GNUNET_BLOCK_Group *bg;
+ va_list ap;
plugin = find_plugin (ctx,
type);
if (NULL == plugin->create_group)
return NULL;
- return plugin->create_group (plugin->cls,
- type,
- nonce,
- raw_data,
- raw_data_size);
+ va_start (ap, raw_data_size);
+ bg = plugin->create_group (plugin->cls,
+ type,
+ nonce,
+ raw_data,
+ raw_data_size,
+ ap);
+ va_end (ap);
+ return bg;
}
*
* @param ctx block contxt
* @param type block type
+ * @param block block group to use
* @param eo control flags
* @param query original query (hash)
- * @param bf pointer to bloom filter associated with query; possibly updated (!)
- * @param bf_mutator mutation value for @a bf
* @param xquery extended query data (can be NULL, depending on type)
* @param xquery_size number of bytes in @a xquery
* @param reply_block response to validate
enum GNUNET_BLOCK_EvaluationResult
GNUNET_BLOCK_evaluate (struct GNUNET_BLOCK_Context *ctx,
enum GNUNET_BLOCK_Type type,
+ struct GNUNET_BLOCK_Group *group,
enum GNUNET_BLOCK_EvaluationOptions eo,
const struct GNUNET_HashCode *query,
- struct GNUNET_CONTAINER_BloomFilter **bf,
- int32_t bf_mutator,
const void *xquery,
size_t xquery_size,
const void *reply_block,
size_t reply_block_size)
{
- struct GNUNET_BLOCK_PluginFunctions *plugin = find_plugin (ctx, type);
+ struct GNUNET_BLOCK_PluginFunctions *plugin = find_plugin (ctx,
+ type);
- if (plugin == NULL)
+ if (NULL == plugin)
return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED;
return plugin->evaluate (plugin->cls,
type,
+ group,
eo,
query,
- bf,
- bf_mutator,
xquery,
xquery_size,
reply_block,
size_t block_size,
struct GNUNET_HashCode *key)
{
- struct GNUNET_BLOCK_PluginFunctions *plugin = find_plugin (ctx, type);
+ struct GNUNET_BLOCK_PluginFunctions *plugin = find_plugin (ctx,
+ type);
if (plugin == NULL)
return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED;
/**
- * How many bytes should a bloomfilter be if we have already seen
- * entry_count responses? Note that #GNUNET_CONSTANTS_BLOOMFILTER_K
- * gives us the number of bits set per entry. Furthermore, we should
- * not re-size the filter too often (to keep it cheap).
- *
- * Since other peers will also add entries but not resize the filter,
- * we should generally pick a slightly larger size than what the
- * strict math would suggest.
- *
- * @param entry_count expected number of entries in the Bloom filter
- * @return must be a power of two and smaller or equal to 2^15.
- */
-static size_t
-compute_bloomfilter_size (unsigned int entry_count)
-{
- size_t size;
- unsigned int ideal = (entry_count * GNUNET_CONSTANTS_BLOOMFILTER_K) / 4;
- uint16_t max = 1 << 15;
-
- if (entry_count > max)
- return max;
- size = 8;
- while ((size < max) && (size < ideal))
- size *= 2;
- if (size > max)
- return max;
- return size;
-}
-
-
-/**
- * Construct a bloom filter that would filter out the given
- * results.
+ * Update block group to filter out the given results. Note that the
+ * use of a hash for seen results implies that the caller magically
+ * knows how the specific block engine hashes for filtering
+ * duplicates, so this API may not always apply.
*
* @param bf_mutator mutation value to use
* @param seen_results results already seen
* @param seen_results_count number of entries in @a seen_results
- * @return NULL if seen_results_count is 0, otherwise a BF
- * that would match the given results.
+ * @return #GNUNET_SYSERR if not supported, #GNUNET_OK on success
*/
-struct GNUNET_CONTAINER_BloomFilter *
-GNUNET_BLOCK_construct_bloomfilter (int32_t bf_mutator,
- const struct GNUNET_HashCode *seen_results,
- unsigned int seen_results_count)
+int
+GNUNET_BLOCK_group_set_seen (struct GNUNET_BLOCK_Group *bg,
+ const struct GNUNET_HashCode *seen_results,
+ unsigned int seen_results_count)
{
- struct GNUNET_CONTAINER_BloomFilter *bf;
- struct GNUNET_HashCode mhash;
- unsigned int i;
- size_t nsize;
-
- nsize = compute_bloomfilter_size (seen_results_count);
- bf = GNUNET_CONTAINER_bloomfilter_init (NULL, nsize,
- GNUNET_CONSTANTS_BLOOMFILTER_K);
- for (i = 0; i < seen_results_count; i++)
- {
- GNUNET_BLOCK_mingle_hash (&seen_results[i], bf_mutator, &mhash);
- GNUNET_CONTAINER_bloomfilter_add (bf, &mhash);
- }
- return bf;
+ if (NULL == bg)
+ return GNUNET_OK;
+ if (NULL == bg->mark_seen_cb)
+ return GNUNET_SYSERR;
+ bg->mark_seen_cb (bg,
+ seen_results,
+ seen_results_count);
+ return GNUNET_OK;
}
#include "platform.h"
#include "gnunet_block_plugin.h"
+#include "gnunet_block_group_lib.h"
#define DEBUG_TEMPLATE GNUNET_EXTRA_LOGGING
+/**
+ * Number of bits we set per entry in the bloomfilter.
+ * Do not change!
+ */
+#define BLOOMFILTER_K 16
+
+
+/**
+ * How big is the BF we use for DHT blocks?
+ */
+#define TEMPLATE_BF_SIZE 8
+
+
+/**
+ * Create a new block group.
+ *
+ * @param ctx block context in which the block group is created
+ * @param type type of the block for which we are creating the group
+ * @param nonce random value used to seed the group creation
+ * @param raw_data optional serialized prior state of the group, NULL if unavailable/fresh
+ * @param raw_data_size number of bytes in @a raw_data, 0 if unavailable/fresh
+ * @param va variable arguments specific to @a type
+ * @return block group handle, NULL if block groups are not supported
+ * by this @a type of block (this is not an error)
+ */
+static struct GNUNET_BLOCK_Group *
+block_plugin_template_create_group (void *cls,
+ enum GNUNET_BLOCK_Type type,
+ uint32_t nonce,
+ const void *raw_data,
+ size_t raw_data_size,
+ va_list va)
+{
+ return GNUNET_BLOCK_GROUP_bf_create (cls,
+ TEMPLATE_BF_SIZE,
+ BLOOMFILTER_K,
+ type,
+ nonce,
+ raw_data,
+ raw_data_size);
+}
+
/**
* Function called to validate a reply or a request. For
*
* @param cls closure
* @param type block type
+ * @param group block group to use
* @param eo control flags
* @param query original query (hash)
- * @param bf pointer to bloom filter associated with query; possibly updated (!)
- * @param bf_mutator mutation value for bf
* @param xquery extrended query data (can be NULL, depending on type)
* @param xquery_size number of bytes in xquery
* @param reply_block response to validate
static enum GNUNET_BLOCK_EvaluationResult
block_plugin_template_evaluate (void *cls,
enum GNUNET_BLOCK_Type type,
+ struct GNUNET_BLOCK_Group *group,
enum GNUNET_BLOCK_EvaluationOptions eo,
const struct GNUNET_HashCode *query,
- struct GNUNET_CONTAINER_BloomFilter **bf,
- int32_t bf_mutator,
const void *xquery,
size_t xquery_size,
const void *reply_block,
size_t reply_block_size)
{
struct GNUNET_HashCode chash;
- struct GNUNET_HashCode mhash;
- /* FIXME: check validity first... */
- /* mandatory duplicate-detection code... */
- if (NULL != bf)
- {
- GNUNET_CRYPTO_hash (reply_block, reply_block_size, &chash);
- GNUNET_BLOCK_mingle_hash (&chash, bf_mutator, &mhash);
- if (NULL != *bf)
- {
- if (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test (*bf, &mhash))
- return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
- }
- else
- {
- *bf = GNUNET_CONTAINER_bloomfilter_init (NULL, 8, 64 /* BLOOMFILTER_K */);
- }
- GNUNET_CONTAINER_bloomfilter_add (*bf, &mhash);
- }
- /* FIXME: other stuff here... */
+ if (NULL == reply_block)
+ return GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
+ GNUNET_CRYPTO_hash (reply_block,
+ reply_block_size,
+ &chash);
+ if (GNUNET_YES ==
+ GNUNET_BLOCK_GROUP_bf_test_and_set (group,
+ &chash))
+ return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED;
}
* @param block block to get the key for
* @param block_size number of bytes in block
* @param key set to the key (query) for the given block
- * @return GNUNET_OK on success, GNUNET_SYSERR if type not supported
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR if type not supported
* (or if extracting a key from a block of this type does not work)
*/
static int
-block_plugin_template_get_key (void *cls, enum GNUNET_BLOCK_Type type,
- const void *block, size_t block_size,
- struct GNUNET_HashCode * key)
+block_plugin_template_get_key (void *cls,
+ enum GNUNET_BLOCK_Type type,
+ const void *block,
+ size_t block_size,
+ struct GNUNET_HashCode *key)
{
return GNUNET_SYSERR;
}
api = GNUNET_new (struct GNUNET_BLOCK_PluginFunctions);
api->evaluate = &block_plugin_template_evaluate;
api->get_key = &block_plugin_template_get_key;
+ api->create_group = &block_plugin_template_create_group;
api->types = types;
return api;
}
#include "platform.h"
#include "gnunet_block_plugin.h"
-
+#include "gnunet_block_group_lib.h"
/**
* Number of bits we set per entry in the bloomfilter.
*/
#define BLOOMFILTER_K 16
+/**
+ * How big is the BF we use for DHT blocks?
+ */
+#define TEST_BF_SIZE 8
+
+
+/**
+ * Create a new block group.
+ *
+ * @param ctx block context in which the block group is created
+ * @param type type of the block for which we are creating the group
+ * @param nonce random value used to seed the group creation
+ * @param raw_data optional serialized prior state of the group, NULL if unavailable/fresh
+ * @param raw_data_size number of bytes in @a raw_data, 0 if unavailable/fresh
+ * @param va variable arguments specific to @a type
+ * @return block group handle, NULL if block groups are not supported
+ * by this @a type of block (this is not an error)
+ */
+static struct GNUNET_BLOCK_Group *
+block_plugin_test_create_group (void *cls,
+ enum GNUNET_BLOCK_Type type,
+ uint32_t nonce,
+ const void *raw_data,
+ size_t raw_data_size,
+ va_list va)
+{
+ return GNUNET_BLOCK_GROUP_bf_create (cls,
+ TEST_BF_SIZE,
+ BLOOMFILTER_K,
+ type,
+ nonce,
+ raw_data,
+ raw_data_size);
+}
+
+
/**
* Function called to validate a reply or a request. For
* request evaluation, simply pass "NULL" for the reply_block.
*
* @param cls closure
* @param type block type
+ * @param group group to check against
* @param eo control flags
* @param query original query (hash)
- * @param bf pointer to bloom filter associated with query; possibly updated (!)
- * @param bf_mutator mutation value for @a bf
* @param xquery extrended query data (can be NULL, depending on type)
* @param xquery_size number of bytes in @a xquery
* @param reply_block response to validate
static enum GNUNET_BLOCK_EvaluationResult
block_plugin_test_evaluate (void *cls,
enum GNUNET_BLOCK_Type type,
+ struct GNUNET_BLOCK_Group *group,
enum GNUNET_BLOCK_EvaluationOptions eo,
const struct GNUNET_HashCode *query,
- struct GNUNET_CONTAINER_BloomFilter **bf,
- int32_t bf_mutator,
const void *xquery,
size_t xquery_size,
const void *reply_block,
size_t reply_block_size)
{
struct GNUNET_HashCode chash;
- struct GNUNET_HashCode mhash;
if ( GNUNET_BLOCK_TYPE_TEST != type)
+ {
+ GNUNET_break (0);
return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED;
+ }
if (0 != xquery_size)
{
GNUNET_break_op (0);
}
if (NULL == reply_block)
return GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
-
- if (NULL != bf)
- {
- GNUNET_CRYPTO_hash (reply_block, reply_block_size, &chash);
- GNUNET_BLOCK_mingle_hash (&chash, bf_mutator, &mhash);
- if (NULL != *bf)
- {
- if (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test (*bf, &mhash))
- return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
- }
- else
- {
- *bf = GNUNET_CONTAINER_bloomfilter_init (NULL, 8, BLOOMFILTER_K);
- }
- GNUNET_CONTAINER_bloomfilter_add (*bf, &mhash);
- }
+ GNUNET_CRYPTO_hash (reply_block,
+ reply_block_size,
+ &chash);
+ if (GNUNET_YES ==
+ GNUNET_BLOCK_GROUP_bf_test_and_set (group,
+ &chash))
+ return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
return GNUNET_BLOCK_EVALUATION_OK_MORE;
}
* (or if extracting a key from a block of this type does not work)
*/
static int
-block_plugin_test_get_key (void *cls, enum GNUNET_BLOCK_Type type,
- const void *block, size_t block_size,
- struct GNUNET_HashCode * key)
+block_plugin_test_get_key (void *cls,
+ enum GNUNET_BLOCK_Type type,
+ const void *block,
+ size_t block_size,
+ struct GNUNET_HashCode *key)
{
/* always fails since there is no fixed relationship between
* keys and values for test values */
api = GNUNET_new (struct GNUNET_BLOCK_PluginFunctions);
api->evaluate = &block_plugin_test_evaluate;
api->get_key = &block_plugin_test_get_key;
+ api->create_group = &block_plugin_test_create_group;
api->types = types;
return api;
}
$(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
$(top_builddir)/src/hello/libgnunethello.la \
$(top_builddir)/src/block/libgnunetblock.la \
+ $(top_builddir)/src/block/libgnunetblockgroup.la \
$(top_builddir)/src/datacache/libgnunetdatacache.la \
$(top_builddir)/src/util/libgnunetutil.la \
-lm
$(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
$(top_builddir)/src/hello/libgnunethello.la \
$(top_builddir)/src/block/libgnunetblock.la \
+ $(top_builddir)/src/block/libgnunetblockgroup.la \
$(top_builddir)/src/datacache/libgnunetdatacache.la \
$(top_builddir)/src/util/libgnunetutil.la \
-lm
$(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
$(top_builddir)/src/hello/libgnunethello.la \
$(top_builddir)/src/block/libgnunetblock.la \
+ $(top_builddir)/src/block/libgnunetblockgroup.la \
$(top_builddir)/src/datacache/libgnunetdatacache.la \
$(top_builddir)/src/util/libgnunetutil.la \
-lm
/*
This file is part of GNUnet.
- Copyright (C) 2009, 2010, 2011, 2016 GNUnet e.V.
+ Copyright (C) 2009, 2010, 2011, 2016, 2017 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
static void
transmit_request (struct ClientQueryRecord *cqr)
{
- int32_t reply_bf_mutator;
- struct GNUNET_CONTAINER_BloomFilter *reply_bf;
+ struct GNUNET_BLOCK_Group *bg;
struct GNUNET_CONTAINER_BloomFilter *peer_bf;
GNUNET_STATISTICS_update (GDS_stats,
gettext_noop ("# GET requests from clients injected"),
1,
GNUNET_NO);
- reply_bf_mutator =
- (int32_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
- UINT32_MAX);
- reply_bf
- = GNUNET_BLOCK_construct_bloomfilter (reply_bf_mutator,
- cqr->seen_replies,
- cqr->seen_replies_count);
+ bg = GNUNET_BLOCK_group_create (GDS_block_context,
+ cqr->type,
+ GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
+ UINT32_MAX),
+ NULL,
+ 0);
+ GNUNET_BLOCK_group_set_seen (bg,
+ cqr->seen_replies,
+ cqr->seen_replies_count);
peer_bf
= GNUNET_CONTAINER_bloomfilter_init (NULL,
DHT_BLOOM_SIZE,
&cqr->key,
cqr->xquery,
cqr->xquery_size,
- reply_bf,
- reply_bf_mutator,
+ bg,
peer_bf);
- GNUNET_CONTAINER_bloomfilter_free (reply_bf);
+ GNUNET_BLOCK_group_destroy (bg);
GNUNET_CONTAINER_bloomfilter_free (peer_bf);
/* exponential back-off for retries.
cqr->xquery,
xquery_size,
NULL,
- 0,
&handle_local_result,
ch);
GNUNET_SERVICE_client_continue (ch->client);
eval
= GNUNET_BLOCK_evaluate (GDS_block_context,
record->type,
+ NULL,
GNUNET_BLOCK_EO_NONE,
key,
- NULL,
- 0,
record->xquery,
record->xquery_size,
frc->data,
/*
This file is part of GNUnet.
- Copyright (C) 2009, 2010, 2011, 2015 GNUnet e.V.
+ Copyright (C) 2009, 2010, 2011, 2015, 2017 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
*/
const void *xquery;
- /**
- * Bloomfilter to filter out duplicate replies (updated)
- */
- struct GNUNET_CONTAINER_BloomFilter **reply_bf;
-
/**
* The key this request was about
*/
struct GNUNET_HashCode key;
/**
- * Number of bytes in xquery.
+ * Block group to use to evaluate replies (updated)
*/
- size_t xquery_size;
+ struct GNUNET_BLOCK_Group *bg;
/**
- * Mutator value for the @e reply_bf, see gnunet_block_lib.h
+ * Function to call on results.
*/
- uint32_t reply_bf_mutator;
+ GDS_DATACACHE_GetCallback gc;
/**
- * Return value to give back.
+ * Closure for @e gc.
*/
- enum GNUNET_BLOCK_EvaluationResult eval;
+ void *gc_cls;
/**
- * Function to call on results.
+ * Number of bytes in xquery.
*/
- GDS_DATACACHE_GetCallback gc;
+ size_t xquery_size;
/**
- * Closure for @e gc.
+ * Return value to give back.
*/
- void *gc_cls;
+ enum GNUNET_BLOCK_EvaluationResult eval;
};
eval
= GNUNET_BLOCK_evaluate (GDS_block_context,
type,
+ ctx->bg,
GNUNET_BLOCK_EO_LOCAL_SKIP_CRYPTO,
key,
- ctx->reply_bf,
- ctx->reply_bf_mutator,
ctx->xquery,
ctx->xquery_size,
data,
* @param type requested data type
* @param xquery extended query
* @param xquery_size number of bytes in @a xquery
- * @param reply_bf where the reply bf is (to be) stored, possibly updated, can be NULL
- * @param reply_bf_mutator mutation value for @a reply_bf
+ * @param bg block group to use for reply evaluation
* @param gc function to call on the results
* @param gc_cls closure for @a gc
* @return evaluation result for the local replies
enum GNUNET_BLOCK_Type type,
const void *xquery,
size_t xquery_size,
- struct GNUNET_CONTAINER_BloomFilter **reply_bf,
- uint32_t reply_bf_mutator,
+ struct GNUNET_BLOCK_Group *bg,
GDS_DATACACHE_GetCallback gc,
void *gc_cls)
{
ctx.key = *key;
ctx.xquery = xquery;
ctx.xquery_size = xquery_size;
- ctx.reply_bf = reply_bf;
- ctx.reply_bf_mutator = reply_bf_mutator;
+ ctx.bg = bg;
ctx.gc = gc;
ctx.gc_cls = gc_cls;
r = GNUNET_DATACACHE_get (datacache,
* @param type requested data type
* @param xquery extended query
* @param xquery_size number of bytes in xquery
- * @param reply_bf where the reply bf is (to be) stored, possibly updated!, can be NULL
- * @param reply_bf_mutator mutation value for reply_bf
+ * @param bg block group to use for evaluation of replies
* @param gc function to call on the results
* @param gc_cls closure for @a gc
* @return evaluation result for the local replies
enum GNUNET_BLOCK_Type type,
const void *xquery,
size_t xquery_size,
- struct GNUNET_CONTAINER_BloomFilter **reply_bf,
- uint32_t reply_bf_mutator,
+ struct GNUNET_BLOCK_Group *bg,
GDS_DATACACHE_GetCallback gc,
void *gc_cls);
/*
This file is part of GNUnet.
- Copyright (C) 2009-2016 GNUnet e.V.
+ Copyright (C) 2009-2017 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
#include "platform.h"
#include "gnunet_util_lib.h"
#include "gnunet_block_lib.h"
+#include "gnunet_block_group_lib.h"
#include "gnunet_hello_lib.h"
#include "gnunet_constants.h"
#include "gnunet_protocols.h"
/**
* Enable slow sanity checks to debug issues.
- */
+ */
#define SANITY_CHECKS 1
/**
}
-/**
- * Closure for #add_known_to_bloom().
- */
-struct BloomConstructorContext
-{
- /**
- * Bloom filter under construction.
- */
- struct GNUNET_CONTAINER_BloomFilter *bloom;
-
- /**
- * Mutator to use.
- */
- uint32_t bf_mutator;
-};
-
-
/**
* Add each of the peers we already know to the bloom filter of
* the request so that we don't get duplicate HELLOs.
*
- * @param cls the 'struct BloomConstructorContext'.
+ * @param cls the `struct GNUNET_BLOCK_Group`
* @param key peer identity to add to the bloom filter
* @param value value the peer information (unused)
* @return #GNUNET_YES (we should continue to iterate)
const struct GNUNET_PeerIdentity *key,
void *value)
{
- struct BloomConstructorContext *ctx = cls;
+ struct GNUNET_BLOCK_Group *bg = cls;
struct GNUNET_HashCode key_hash;
- struct GNUNET_HashCode mh;
GNUNET_CRYPTO_hash (key,
sizeof (struct GNUNET_PeerIdentity),
&key_hash);
- GNUNET_BLOCK_mingle_hash (&key_hash,
- ctx->bf_mutator,
- &mh);
+ GNUNET_BLOCK_GROUP_bf_test_and_set (bg,
+ &key_hash);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Adding known peer (%s) to bloomfilter for FIND PEER with mutation %u\n",
- GNUNET_i2s (key),
- ctx->bf_mutator);
- GNUNET_CONTAINER_bloomfilter_add (ctx->bloom,
- &mh);
+ "Adding known peer (%s) to bloomfilter for FIND PEER\n",
+ GNUNET_i2s (key));
return GNUNET_YES;
}
send_find_peer_message (void *cls)
{
struct GNUNET_TIME_Relative next_send_time;
- struct BloomConstructorContext bcc;
+ struct GNUNET_BLOCK_Group *bg;
struct GNUNET_CONTAINER_BloomFilter *peer_bf;
find_peer_task = NULL;
newly_found_peers = 0;
return;
}
- bcc.bf_mutator =
- GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
- UINT32_MAX);
- bcc.bloom =
- GNUNET_CONTAINER_bloomfilter_init (NULL, DHT_BLOOM_SIZE,
- GNUNET_CONSTANTS_BLOOMFILTER_K);
+ bg = GNUNET_BLOCK_GROUP_bf_create (NULL,
+ DHT_BLOOM_SIZE,
+ GNUNET_CONSTANTS_BLOOMFILTER_K,
+ GNUNET_BLOCK_TYPE_DHT_HELLO,
+ GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
+ UINT32_MAX),
+ NULL,
+ 0);
GNUNET_CONTAINER_multipeermap_iterate (all_connected_peers,
&add_known_to_bloom,
- &bcc);
+ bg);
GNUNET_STATISTICS_update (GDS_stats,
gettext_noop ("# FIND PEER messages initiated"),
1,
GNUNET_NO);
- peer_bf =
- GNUNET_CONTAINER_bloomfilter_init (NULL, DHT_BLOOM_SIZE,
+ peer_bf
+ = GNUNET_CONTAINER_bloomfilter_init (NULL,
+ DHT_BLOOM_SIZE,
GNUNET_CONSTANTS_BLOOMFILTER_K);
// FIXME: pass priority!?
GDS_NEIGHBOURS_handle_get (GNUNET_BLOCK_TYPE_DHT_HELLO,
GNUNET_DHT_RO_FIND_PEER,
- FIND_PEER_REPLICATION_LEVEL, 0,
- &my_identity_hash, NULL, 0, bcc.bloom,
- bcc.bf_mutator, peer_bf);
+ FIND_PEER_REPLICATION_LEVEL,
+ 0,
+ &my_identity_hash,
+ NULL,
+ 0,
+ bg,
+ peer_bf);
GNUNET_CONTAINER_bloomfilter_free (peer_bf);
- GNUNET_CONTAINER_bloomfilter_free (bcc.bloom);
+ GNUNET_BLOCK_group_destroy (bg);
/* schedule next round */
next_send_time.rel_value_us =
DHT_MINIMUM_FIND_PEER_INTERVAL.rel_value_us +
* @param key key for the content
* @param xquery extended query
* @param xquery_size number of bytes in @a xquery
- * @param reply_bf bloomfilter to filter duplicates
- * @param reply_bf_mutator mutator for @a reply_bf
+ * @param bg group to use for filtering replies
* @param peer_bf filter for peers not to select (again)
* @return #GNUNET_OK if the request was forwarded, #GNUNET_NO if not
*/
GDS_NEIGHBOURS_handle_get (enum GNUNET_BLOCK_Type type,
enum GNUNET_DHT_RouteOption options,
uint32_t desired_replication_level,
- uint32_t hop_count, const struct GNUNET_HashCode * key,
- const void *xquery, size_t xquery_size,
- const struct GNUNET_CONTAINER_BloomFilter *reply_bf,
- uint32_t reply_bf_mutator,
+ uint32_t hop_count,
+ const struct GNUNET_HashCode *key,
+ const void *xquery,
+ size_t xquery_size,
+ struct GNUNET_BLOCK_Group *bg,
struct GNUNET_CONTAINER_BloomFilter *peer_bf)
{
unsigned int target_count;
- unsigned int i;
struct PeerInfo **targets;
struct PeerInfo *target;
struct GNUNET_MQ_Envelope *env;
struct PeerGetMessage *pgm;
char *xq;
size_t reply_bf_size;
+ void *reply_bf;
unsigned int skip_count;
+ uint32_t bf_nonce;
GNUNET_assert (NULL != peer_bf);
GNUNET_STATISTICS_update (GDS_stats,
GNUNET_i2s (&my_identity));
return GNUNET_NO;
}
- reply_bf_size = GNUNET_CONTAINER_bloomfilter_get_size (reply_bf);
+ if (GNUNET_OK !=
+ GNUNET_BLOCK_group_serialize (bg,
+ &bf_nonce,
+ &reply_bf,
+ &reply_bf_size))
+ {
+ reply_bf = NULL;
+ reply_bf_size = 0;
+ bf_nonce = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
+ UINT32_MAX);
+ }
msize = xquery_size + reply_bf_size;
if (msize + sizeof (struct PeerGetMessage) >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
{
GNUNET_break (0);
+ GNUNET_free_non_null (reply_bf);
GNUNET_free (targets);
return GNUNET_NO;
}
GNUNET_NO);
/* forward request */
skip_count = 0;
- for (i = 0; i < target_count; i++)
+ for (unsigned int i = 0; i < target_count; i++)
{
target = targets[i];
if (GNUNET_MQ_get_length (target->mq) >= MAXIMUM_PENDING_PER_PEER)
pgm->hop_count = htonl (hop_count + 1);
pgm->desired_replication_level = htonl (desired_replication_level);
pgm->xquery_size = htonl (xquery_size);
- pgm->bf_mutator = reply_bf_mutator;
+ pgm->bf_mutator = bf_nonce;
GNUNET_break (GNUNET_YES ==
GNUNET_CONTAINER_bloomfilter_test (peer_bf,
&target->phash));
GNUNET_memcpy (xq,
xquery,
xquery_size);
- if (NULL != reply_bf)
- GNUNET_assert (GNUNET_OK ==
- GNUNET_CONTAINER_bloomfilter_get_raw_data (reply_bf,
- &xq
- [xquery_size],
- reply_bf_size));
+ GNUNET_memcpy (&xq[xquery_size],
+ reply_bf,
+ reply_bf_size);
GNUNET_MQ_send (target->mq,
env);
}
GNUNET_free (targets);
+ GNUNET_free_non_null (reply_bf);
return (skip_count < target_count) ? GNUNET_OK : GNUNET_NO;
}
{
switch (GNUNET_BLOCK_evaluate (GDS_block_context,
ntohl (put->type),
+ NULL, /* query group */
GNUNET_BLOCK_EO_NONE,
NULL, /* query */
- NULL, 0, /* bloom filer */
NULL, 0, /* xquery */
- payload, payload_size))
+ payload,
+ payload_size))
{
case GNUNET_BLOCK_EVALUATION_OK_MORE:
case GNUNET_BLOCK_EVALUATION_OK_LAST:
}
GNUNET_break (0 != memcmp (&pp[i],
peer->id,
- sizeof (struct GNUNET_PeerIdentity)));
+ sizeof (struct GNUNET_PeerIdentity)));
}
#endif
GNUNET_memcpy (pp,
*
* @param sender sender of the FIND PEER request
* @param key peers close to this key are desired
- * @param bf peers matching this bf are excluded
- * @param bf_mutator mutator for bf
+ * @param bg group for filtering peers
*/
static void
handle_find_peer (const struct GNUNET_PeerIdentity *sender,
const struct GNUNET_HashCode *key,
- struct GNUNET_CONTAINER_BloomFilter *bf,
- uint32_t bf_mutator)
+ struct GNUNET_BLOCK_Group *bg)
{
int bucket_idx;
struct PeerBucket *bucket;
struct PeerInfo *peer;
unsigned int choice;
- struct GNUNET_HashCode mhash;
const struct GNUNET_HELLO_Message *hello;
/* first, check about our own HELLO */
if (NULL != GDS_my_hello)
{
- GNUNET_BLOCK_mingle_hash (&my_identity_hash,
- bf_mutator,
- &mhash);
- if ((NULL == bf) ||
- (GNUNET_YES != GNUNET_CONTAINER_bloomfilter_test (bf, &mhash)))
+ if (GNUNET_YES !=
+ GNUNET_BLOCK_GROUP_bf_test_and_set (bg,
+ &my_identity_hash))
{
size_t hello_size;
do
{
peer = peer->next;
- if (choice-- == 0)
+ if (0 == choice--)
return; /* no non-masked peer available */
if (NULL == peer)
peer = bucket->head;
- GNUNET_BLOCK_mingle_hash (&peer->phash,
- bf_mutator,
- &mhash);
hello = GDS_HELLO_get (peer->id);
- } while ( (hello == NULL) ||
- (GNUNET_YES ==
- GNUNET_CONTAINER_bloomfilter_test (bf,
- &mhash)) );
+ } while ( (NULL == hello) ||
+ (GNUNET_YES ==
+ GNUNET_BLOCK_GROUP_bf_test_and_set (bg,
+ &peer->phash)) );
GDS_NEIGHBOURS_handle_reply (sender,
GNUNET_BLOCK_TYPE_DHT_HELLO,
GNUNET_TIME_relative_to_absolute
enum GNUNET_BLOCK_Type type;
enum GNUNET_DHT_RouteOption options;
enum GNUNET_BLOCK_EvaluationResult eval;
- struct GNUNET_CONTAINER_BloomFilter *reply_bf;
+ struct GNUNET_BLOCK_Group *bg;
struct GNUNET_CONTAINER_BloomFilter *peer_bf;
const char *xquery;
int forwarded;
type = ntohl (get->type);
options = ntohl (get->options);
xquery = (const char *) &get[1];
- reply_bf = NULL;
GNUNET_STATISTICS_update (GDS_stats,
gettext_noop ("# P2P GET requests received"),
1,
xquery);
GNUNET_free (tmp);
}
-
- if (reply_bf_size > 0)
- reply_bf =
- GNUNET_CONTAINER_bloomfilter_init (&xquery[xquery_size],
- reply_bf_size,
- GNUNET_CONSTANTS_BLOOMFILTER_K);
- eval =
- GNUNET_BLOCK_evaluate (GDS_block_context,
+ bg = GNUNET_BLOCK_group_create (GDS_block_context,
+ type,
+ get->bf_mutator,
+ &xquery[xquery_size],
+ reply_bf_size);
+ eval
+ = GNUNET_BLOCK_evaluate (GDS_block_context,
type,
+ bg,
GNUNET_BLOCK_EO_NONE,
&get->key,
- &reply_bf,
- get->bf_mutator,
xquery,
xquery_size,
NULL,
{
/* request invalid or block type not supported */
GNUNET_break_op (eval == GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED);
- if (NULL != reply_bf)
- GNUNET_CONTAINER_bloomfilter_free (reply_bf);
+ GNUNET_BLOCK_group_destroy (bg);
return;
}
peer_bf = GNUNET_CONTAINER_bloomfilter_init (get->bloomfilter,
/* remember request for routing replies */
GDS_ROUTING_add (peer->id,
type,
+ bg, /* bg now owned by routing, but valid at least until end of this function! */
options,
&get->key,
xquery,
- xquery_size,
- reply_bf,
- get->bf_mutator);
+ xquery_size);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"GET for %s at %s after %u hops\n",
GNUNET_h2s (&get->key),
GNUNET_NO);
handle_find_peer (peer->id,
&get->key,
- reply_bf,
- get->bf_mutator);
+ bg);
}
else
{
type,
xquery,
xquery_size,
- &reply_bf,
- get->bf_mutator,
+ bg,
&handle_local_result,
NULL);
}
&get->key,
xquery,
xquery_size,
- reply_bf,
- get->bf_mutator,
+ bg,
peer_bf);
GDS_CLIENTS_process_get (options
| (GNUNET_OK == forwarded)
NULL,
&get->key);
-
- /* clean up */
- if (NULL != reply_bf)
- GNUNET_CONTAINER_bloomfilter_free (reply_bf);
+ /* clean up; note that 'bg' is owned by routing now! */
GNUNET_CONTAINER_bloomfilter_free (peer_bf);
}
}
GNUNET_break (0 != memcmp (&get_path[i],
peer->id,
- sizeof (struct GNUNET_PeerIdentity)));
+ sizeof (struct GNUNET_PeerIdentity)));
}
#endif
GNUNET_memcpy (xget_path,
* @param key key for the content
* @param xquery extended query
* @param xquery_size number of bytes in @a xquery
- * @param reply_bf bloomfilter to filter duplicates
- * @param reply_bf_mutator mutator for @a reply_bf
+ * @param bg block group to filter replies
* @param peer_bf filter for peers not to select (again, updated)
* @return #GNUNET_OK if the request was forwarded, #GNUNET_NO if not
*/
uint32_t desired_replication_level,
uint32_t hop_count,
const struct GNUNET_HashCode *key,
- const void *xquery, size_t xquery_size,
- const struct GNUNET_CONTAINER_BloomFilter *reply_bf,
- uint32_t reply_bf_mutator,
+ const void *xquery,
+ size_t xquery_size,
+ struct GNUNET_BLOCK_Group *bg,
struct GNUNET_CONTAINER_BloomFilter *peer_bf);
GDS_NEIGHBOURS_handle_reply (const struct GNUNET_PeerIdentity *target,
enum GNUNET_BLOCK_Type type,
struct GNUNET_TIME_Absolute expiration_time,
- const struct GNUNET_HashCode * key,
+ const struct GNUNET_HashCode *key,
unsigned int put_path_length,
const struct GNUNET_PeerIdentity *put_path,
unsigned int get_path_length,
const struct GNUNET_PeerIdentity *get_path,
- const void *data, size_t data_size);
+ const void *data,
+ size_t data_size);
/**
struct GNUNET_CONTAINER_HeapNode *heap_node;
/**
- * Bloomfilter for replies to drop.
+ * Block group for filtering replies.
*/
- struct GNUNET_CONTAINER_BloomFilter *reply_bf;
+ struct GNUNET_BLOCK_Group *bg;
/**
* Type of the requested block.
*/
size_t xquery_size;
- /**
- * Mutator value for the reply_bf, see gnunet_block_lib.h
- */
- uint32_t reply_bf_mutator;
-
/**
* Request options.
*/
eval
= GNUNET_BLOCK_evaluate (GDS_block_context,
pc->type,
+ rr->bg,
GNUNET_BLOCK_EO_NONE,
eval_key,
- &rr->reply_bf,
- rr->reply_bf_mutator,
rr->xquery,
rr->xquery_size,
pc->data,
recent_req = GNUNET_CONTAINER_heap_peek (recent_heap);
GNUNET_assert (recent_req != NULL);
GNUNET_CONTAINER_heap_remove_node (recent_req->heap_node);
- GNUNET_CONTAINER_bloomfilter_free (recent_req->reply_bf);
+ GNUNET_BLOCK_group_destroy (recent_req->bg);
GNUNET_assert (GNUNET_YES ==
GNUNET_CONTAINER_multihashmap_remove (recent_map,
&recent_req->key,
rr->xquery,
in->xquery_size)) )
return GNUNET_OK;
- if (in->reply_bf_mutator != rr->reply_bf_mutator)
- {
- rr->reply_bf_mutator = in->reply_bf_mutator;
- GNUNET_CONTAINER_bloomfilter_free (rr->reply_bf);
- rr->reply_bf = in->reply_bf;
- }
- else
- {
- GNUNET_CONTAINER_bloomfilter_or2 (rr->reply_bf,
- in->reply_bf);
- GNUNET_CONTAINER_bloomfilter_free (in->reply_bf);
- }
+ GNUNET_break (GNUNET_SYSERR !=
+ GNUNET_BLOCK_group_merge (in->bg,
+ rr->bg));
+ rr->bg = in->bg;
GNUNET_free (in);
return GNUNET_SYSERR;
}
void
GDS_ROUTING_add (const struct GNUNET_PeerIdentity *sender,
enum GNUNET_BLOCK_Type type,
+ struct GNUNET_BLOCK_Group *bg,
enum GNUNET_DHT_RouteOption options,
const struct GNUNET_HashCode *key,
const void *xquery,
- size_t xquery_size,
- const struct GNUNET_CONTAINER_BloomFilter *reply_bf,
- uint32_t reply_bf_mutator)
+ size_t xquery_size)
{
struct RecentRequest *recent_req;
expire_oldest_entry ();
GNUNET_STATISTICS_update (GDS_stats,
gettext_noop ("# Entries added to routing table"),
- 1, GNUNET_NO);
+ 1,
+ GNUNET_NO);
recent_req = GNUNET_malloc (sizeof (struct RecentRequest) + xquery_size);
recent_req->peer = *sender;
recent_req->key = *key;
- recent_req->reply_bf = GNUNET_CONTAINER_bloomfilter_copy (reply_bf);
+ recent_req->bg = bg;
recent_req->type = type;
recent_req->options = options;
recent_req->xquery = &recent_req[1];
- GNUNET_memcpy (&recent_req[1], xquery, xquery_size);
+ GNUNET_memcpy (&recent_req[1],
+ xquery,
+ xquery_size);
recent_req->xquery_size = xquery_size;
- recent_req->reply_bf_mutator = reply_bf_mutator;
if (GNUNET_SYSERR ==
GNUNET_CONTAINER_multihashmap_get_multiple (recent_map,
key,
1, GNUNET_NO);
return;
}
- recent_req->heap_node =
- GNUNET_CONTAINER_heap_insert (recent_heap, recent_req,
+ recent_req->heap_node
+ = GNUNET_CONTAINER_heap_insert (recent_heap,
+ recent_req,
GNUNET_TIME_absolute_get ().abs_value_us);
- GNUNET_CONTAINER_multihashmap_put (recent_map, key, recent_req,
+ GNUNET_CONTAINER_multihashmap_put (recent_map,
+ key,
+ recent_req,
GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
-
-
}
*
* @param sender peer that originated the request
* @param type type of the block
+ * @param bg block group to evaluate replies, henceforth owned by routing
* @param options options for processing
* @param key key for the content
* @param xquery extended query
* @param xquery_size number of bytes in @a xquery
- * @param reply_bf bloomfilter to filter duplicates
- * @param reply_bf_mutator mutator for @a reply_bf
*/
void
GDS_ROUTING_add (const struct GNUNET_PeerIdentity *sender,
enum GNUNET_BLOCK_Type type,
+ struct GNUNET_BLOCK_Group *bg,
enum GNUNET_DHT_RouteOption options,
- const struct GNUNET_HashCode * key, const void *xquery,
- size_t xquery_size,
- const struct GNUNET_CONTAINER_BloomFilter *reply_bf,
- uint32_t reply_bf_mutator);
+ const struct GNUNET_HashCode * key,
+ const void *xquery,
+ size_t xquery_size);
/**
* @param nonce random value used to seed the group creation
* @param raw_data optional serialized prior state of the group, NULL if unavailable/fresh
* @param raw_data_size number of bytes in @a raw_data, 0 if unavailable/fresh
+ * @param va variable arguments specific to @a type
* @return block group handle, NULL if block groups are not supported
* by this @a type of block (this is not an error)
*/
enum GNUNET_BLOCK_Type type,
uint32_t nonce,
const void *raw_data,
- size_t raw_data_size)
+ size_t raw_data_size,
+ va_list va)
{
return GNUNET_BLOCK_GROUP_bf_create (cls,
DHT_BF_SIZE,
*
* @param cls closure
* @param type block type
+ * @param group block group to check against
* @param eo control flags
* @param query original query (hash)
- * @param bf pointer to bloom filter associated with query; possibly updated (!)
- * @param bf_mutator mutation value for @a bf
* @param xquery extended query data (can be NULL, depending on type)
* @param xquery_size number of bytes in @a xquery
* @param reply_block response to validate
static enum GNUNET_BLOCK_EvaluationResult
block_plugin_dht_evaluate (void *cls,
enum GNUNET_BLOCK_Type type,
+ struct GNUNET_BLOCK_Group *group,
enum GNUNET_BLOCK_EvaluationOptions eo,
const struct GNUNET_HashCode *query,
- struct GNUNET_CONTAINER_BloomFilter **bf,
- int32_t bf_mutator,
const void *xquery,
size_t xquery_size,
const void *reply_block,
size_t reply_block_size)
{
- struct GNUNET_HashCode mhash;
const struct GNUNET_HELLO_Message *hello;
struct GNUNET_PeerIdentity pid;
const struct GNUNET_MessageHeader *msg;
GNUNET_break_op (0);
return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
}
- if (NULL != bf)
- {
- GNUNET_CRYPTO_hash (&pid, sizeof (pid), &phash);
- GNUNET_BLOCK_mingle_hash (&phash, bf_mutator, &mhash);
- if (NULL != *bf)
- {
- if (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test (*bf, &mhash))
- return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
- }
- else
- {
- *bf = GNUNET_CONTAINER_bloomfilter_init (NULL, 8,
- GNUNET_CONSTANTS_BLOOMFILTER_K);
- }
- GNUNET_CONTAINER_bloomfilter_add (*bf, &mhash);
- }
+ GNUNET_CRYPTO_hash (&pid,
+ sizeof (pid),
+ &phash);
+ if (GNUNET_YES ==
+ GNUNET_BLOCK_GROUP_bf_test_and_set (group,
+ &phash))
+ return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
return GNUNET_BLOCK_EVALUATION_OK_MORE;
}
*
* @param cls closure
* @param type block type
+ * @param bg group to evaluate against
* @param eo control flags
* @param query original query (hash)
- * @param bf pointer to bloom filter associated with query; possibly updated (!)
- * @param bf_mutator mutation value for bf
* @param xquery extended query data (can be NULL, depending on type)
* @param xquery_size number of bytes in @a xquery
* @param reply_block response to validate
static enum GNUNET_BLOCK_EvaluationResult
block_plugin_dns_evaluate (void *cls,
enum GNUNET_BLOCK_Type type,
+ struct GNUNET_BLOCK_Group *bg,
enum GNUNET_BLOCK_EvaluationOptions eo,
const struct GNUNET_HashCode * query,
- struct GNUNET_CONTAINER_BloomFilter **bf,
- int32_t bf_mutator,
const void *xquery,
size_t xquery_size,
const void *reply_block,
struct GNUNET_HashCode *replies_seen;
/**
- * Bloomfilter masking replies we've already seen.
+ * Block group for filtering replies we've already seen.
*/
- struct GNUNET_CONTAINER_BloomFilter *bf;
+ struct GNUNET_BLOCK_Group *bg;
/**
* Entry for this pending request in the expiration heap, or NULL.
*/
unsigned int replies_seen_size;
- /**
- * Mingle value we currently use for the bf.
- */
- uint32_t mingle;
-
/**
* Do we have a first UID yet?
*/
* fresh one of minimal size without problems) OR if our peer is the
* initiator (in which case we may resize to larger than mimimum size).
*
+ * @param type type of the request
* @param pr request for which the BF is to be recomputed
*/
static void
-refresh_bloomfilter (struct GSF_PendingRequest *pr)
+refresh_bloomfilter (enum GNUNET_BLOCK_Type type,
+ struct GSF_PendingRequest *pr)
{
- if (pr->bf != NULL)
- GNUNET_CONTAINER_bloomfilter_free (pr->bf);
- pr->mingle =
- GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX);
- pr->bf =
- GNUNET_BLOCK_construct_bloomfilter (pr->mingle, pr->replies_seen,
- pr->replies_seen_count);
+ if (NULL != pr->bg)
+ {
+ GNUNET_BLOCK_group_destroy (pr->bg);
+ pr->bg = NULL;
+ }
+ if (GNUNET_BLOCK_TYPE_FS_UBLOCK != type)
+ return; /* no need */
+ pr->bg
+ = GNUNET_BLOCK_group_create (GSF_block_ctx,
+ type,
+ GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
+ UINT32_MAX),
+ NULL,
+ 0,
+ "fs-seen-set-size",
+ pr->replies_seen_count);
+ if (NULL == pr->bg)
+ return;
+ GNUNET_break (GNUNET_OK ==
+ GNUNET_BLOCK_group_set_seen (pr->bg,
+ pr->replies_seen,
+ pr->replies_seen_count));
}
if (replies_seen_count > 0)
{
pr->replies_seen_size = replies_seen_count;
- pr->replies_seen =
- GNUNET_malloc (sizeof (struct GNUNET_HashCode) * pr->replies_seen_size);
+ pr->replies_seen = GNUNET_new_array (pr->replies_seen_size,
+ struct GNUNET_HashCode);
GNUNET_memcpy (pr->replies_seen,
- replies_seen,
- replies_seen_count * sizeof (struct GNUNET_HashCode));
+ replies_seen,
+ replies_seen_count * sizeof (struct GNUNET_HashCode));
pr->replies_seen_count = replies_seen_count;
}
- if (NULL != bf_data)
+ if ( (NULL != bf_data) &&
+ (GNUNET_BLOCK_TYPE_FS_UBLOCK == pr->public_data.type) )
{
- pr->bf =
- GNUNET_CONTAINER_bloomfilter_init (bf_data,
- bf_size,
- GNUNET_CONSTANTS_BLOOMFILTER_K);
- pr->mingle = mingle;
+ pr->bg
+ = GNUNET_BLOCK_group_create (GSF_block_ctx,
+ pr->public_data.type,
+ mingle,
+ bf_data,
+ bf_size,
+ "fs-seen-set-size",
+ 0);
}
else if ((replies_seen_count > 0) &&
(0 != (options & GSF_PRO_BLOOMFILTER_FULL_REFRESH)))
{
- refresh_bloomfilter (pr);
+ refresh_bloomfilter (pr->public_data.type,
+ pr);
}
GNUNET_CONTAINER_multihashmap_put (pr_map,
&pr->public_data.query,
const struct GNUNET_HashCode * replies_seen,
unsigned int replies_seen_count)
{
- unsigned int i;
- struct GNUNET_HashCode mhash;
-
if (replies_seen_count + pr->replies_seen_count < pr->replies_seen_count)
return; /* integer overflow */
if (0 != (pr->public_data.options & GSF_PRO_BLOOMFILTER_FULL_REFRESH))
{
/* we're responsible for the BF, full refresh */
if (replies_seen_count + pr->replies_seen_count > pr->replies_seen_size)
- GNUNET_array_grow (pr->replies_seen, pr->replies_seen_size,
+ GNUNET_array_grow (pr->replies_seen,
+ pr->replies_seen_size,
replies_seen_count + pr->replies_seen_count);
- GNUNET_memcpy (&pr->replies_seen[pr->replies_seen_count], replies_seen,
- sizeof (struct GNUNET_HashCode) * replies_seen_count);
+ GNUNET_memcpy (&pr->replies_seen[pr->replies_seen_count],
+ replies_seen,
+ sizeof (struct GNUNET_HashCode) * replies_seen_count);
pr->replies_seen_count += replies_seen_count;
- refresh_bloomfilter (pr);
+ refresh_bloomfilter (pr->public_data.type,
+ pr);
}
else
{
- if (NULL == pr->bf)
+ if (NULL == pr->bg)
{
/* we're not the initiator, but the initiator did not give us
* any bloom-filter, so we need to create one on-the-fly */
- pr->mingle =
- GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
- UINT32_MAX);
- pr->bf =
- GNUNET_BLOCK_construct_bloomfilter (pr->mingle,
- replies_seen,
- replies_seen_count);
+ refresh_bloomfilter (pr->public_data.type,
+ pr);
}
else
{
- for (i = 0; i < pr->replies_seen_count; i++)
- {
- GNUNET_BLOCK_mingle_hash (&replies_seen[i],
- pr->mingle,
- &mhash);
- GNUNET_CONTAINER_bloomfilter_add (pr->bf,
- &mhash);
- }
+ GNUNET_break (GNUNET_OK ==
+ GNUNET_BLOCK_group_set_seen (pr->bg,
+ replies_seen,
+ pr->replies_seen_count));
}
}
if (NULL != pr->gh)
struct GNUNET_TIME_Absolute now;
int64_t ttl;
int do_route;
+ void *bf_data;
+ uint32_t bf_nonce;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Building request message for `%s' of type %d\n",
bm |= GET_MESSAGE_BIT_TRANSMIT_TO;
k++;
}
- bf_size = GNUNET_CONTAINER_bloomfilter_get_size (pr->bf);
+ if (GNUNET_OK !=
+ GNUNET_BLOCK_group_serialize (pr->bg,
+ &bf_nonce,
+ &bf_data,
+ &bf_size))
+ {
+ bf_size = 0;
+ bf_data = NULL;
+ }
env = GNUNET_MQ_msg_extra (gm,
bf_size + k * sizeof (struct GNUNET_PeerIdentity),
GNUNET_MESSAGE_TYPE_FS_GET);
now = GNUNET_TIME_absolute_get ();
ttl = (int64_t) (pr->public_data.ttl.abs_value_us - now.abs_value_us);
gm->ttl = htonl (ttl / 1000LL / 1000LL);
- gm->filter_mutator = htonl (pr->mingle);
+ gm->filter_mutator = htonl (bf_nonce);
gm->hash_bitmap = htonl (bm);
gm->query = pr->public_data.query;
ext = (struct GNUNET_PeerIdentity *) &gm[1];
&ext[k++]);
if (NULL != pr->public_data.target)
ext[k++] = *pr->public_data.target;
- if (NULL != pr->bf)
- GNUNET_assert (GNUNET_SYSERR !=
- GNUNET_CONTAINER_bloomfilter_get_raw_data (pr->bf,
- (char *) &ext[k],
- bf_size));
+ GNUNET_memcpy (&ext[k],
+ bf_data,
+ bf_size);
+ GNUNET_free_non_null (bf_data);
return env;
}
}
GSF_plan_notify_request_done_ (pr);
GNUNET_free_non_null (pr->replies_seen);
- if (NULL != pr->bf)
- {
- GNUNET_CONTAINER_bloomfilter_free (pr->bf);
- pr->bf = NULL;
- }
+ GNUNET_BLOCK_group_destroy (pr->bg);
+ pr->bg = NULL;
GNUNET_PEER_change_rc (pr->sender_pid, -1);
pr->sender_pid = 0;
GNUNET_PEER_change_rc (pr->origin_pid, -1);
prq->eval =
GNUNET_BLOCK_evaluate (GSF_block_ctx,
prq->type,
+ pr->bg,
prq->eo,
key,
- &pr->bf,
- pr->mingle,
NULL,
0,
prq->data,
#include "gnunet_fs_service.h"
#include "block_fs.h"
#include "gnunet_signatures.h"
+#include "gnunet_constants.h"
#include "gnunet_block_group_lib.h"
*/
#define BLOOMFILTER_K 16
+
/**
- * How big is the BF we use for FS blocks?
+ * How many bytes should a bloomfilter be if we have already seen
+ * entry_count responses? Note that #GNUNET_CONSTANTS_BLOOMFILTER_K
+ * gives us the number of bits set per entry. Furthermore, we should
+ * not re-size the filter too often (to keep it cheap).
+ *
+ * Since other peers will also add entries but not resize the filter,
+ * we should generally pick a slightly larger size than what the
+ * strict math would suggest.
+ *
+ * @param entry_count expected number of entries in the Bloom filter
+ * @return must be a power of two and smaller or equal to 2^15.
*/
-#define FS_BF_SIZE 8
+static size_t
+compute_bloomfilter_size (unsigned int entry_count)
+{
+ size_t size;
+ unsigned int ideal = (entry_count * GNUNET_CONSTANTS_BLOOMFILTER_K) / 4;
+ uint16_t max = 1 << 15;
+
+ if (entry_count > max)
+ return max;
+ size = 8;
+ while ((size < max) && (size < ideal))
+ size *= 2;
+ if (size > max)
+ return max;
+ return size;
+}
/**
* @param nonce random value used to seed the group creation
* @param raw_data optional serialized prior state of the group, NULL if unavailable/fresh
* @param raw_data_size number of bytes in @a raw_data, 0 if unavailable/fresh
+ * @param va variable arguments specific to @a type
* @return block group handle, NULL if block groups are not supported
* by this @a type of block (this is not an error)
*/
static struct GNUNET_BLOCK_Group *
block_plugin_fs_create_group (void *cls,
- enum GNUNET_BLOCK_Type type,
- uint32_t nonce,
- const void *raw_data,
- size_t raw_data_size)
+ enum GNUNET_BLOCK_Type type,
+ uint32_t nonce,
+ const void *raw_data,
+ size_t raw_data_size,
+ va_list va)
{
+ unsigned int size;
+ const char *guard;
+
switch (type)
{
case GNUNET_BLOCK_TYPE_FS_DBLOCK:
case GNUNET_BLOCK_TYPE_FS_IBLOCK:
return NULL;
case GNUNET_BLOCK_TYPE_FS_UBLOCK:
+ guard = va_arg (va, const char *);
+ if (0 != memcmp (guard,
+ "fs-seen-set-size",
+ strlen ("fs-seen-set-size")))
+ {
+ /* va-args invalid! bad bug, complain! */
+ GNUNET_break (0);
+ size = 8;
+ }
+ else
+ {
+ size = compute_bloomfilter_size (va_arg (va, unsigned int));
+ }
+ if (0 == size)
+ size = raw_data_size; /* not for us to determine, use what we got! */
return GNUNET_BLOCK_GROUP_bf_create (cls,
- FS_BF_SIZE,
+ size,
BLOOMFILTER_K,
type,
nonce,
*
* @param cls closure
* @param type block type
+ * @param bg group to use for evaluation
* @param eo control flags
* @param query original query (hash)
- * @param bf pointer to bloom filter associated with query; possibly updated (!)
- * @param bf_mutator mutation value for @a bf
* @param xquery extrended query data (can be NULL, depending on type)
* @param xquery_size number of bytes in @a xquery
* @param reply_block response to validate
static enum GNUNET_BLOCK_EvaluationResult
block_plugin_fs_evaluate (void *cls,
enum GNUNET_BLOCK_Type type,
+ struct GNUNET_BLOCK_Group *bg,
enum GNUNET_BLOCK_EvaluationOptions eo,
const struct GNUNET_HashCode *query,
- struct GNUNET_CONTAINER_BloomFilter **bf,
- int32_t bf_mutator,
const void *xquery,
size_t xquery_size,
const void *reply_block,
const struct UBlock *ub;
struct GNUNET_HashCode hc;
struct GNUNET_HashCode chash;
- struct GNUNET_HashCode mhash;
switch (type)
{
GNUNET_break_op (0);
return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
}
- if (NULL != bf)
- {
- GNUNET_CRYPTO_hash (reply_block,
- reply_block_size,
- &chash);
- GNUNET_BLOCK_mingle_hash (&chash,
- bf_mutator,
- &mhash);
- if (NULL != *bf)
- {
- if (GNUNET_YES ==
- GNUNET_CONTAINER_bloomfilter_test (*bf, &mhash))
- return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
- }
- else
- {
- *bf = GNUNET_CONTAINER_bloomfilter_init (NULL, 8, BLOOMFILTER_K);
- }
- GNUNET_CONTAINER_bloomfilter_add (*bf, &mhash);
- }
+ GNUNET_CRYPTO_hash (reply_block,
+ reply_block_size,
+ &chash);
+ if (GNUNET_YES ==
+ GNUNET_BLOCK_GROUP_bf_test_and_set (bg,
+ &chash))
+ return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
return GNUNET_BLOCK_EVALUATION_OK_MORE;
default:
return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED;
if (GNUNET_BLOCK_EVALUATION_OK_LAST !=
GNUNET_BLOCK_evaluate (ctx,
GNUNET_BLOCK_TYPE_FS_DBLOCK,
+ NULL,
GNUNET_BLOCK_EO_NONE,
&key,
NULL, 0,
- NULL, 0,
block, sizeof (block)))
return 2;
if (GNUNET_BLOCK_EVALUATION_REQUEST_VALID !=
GNUNET_BLOCK_evaluate (ctx,
GNUNET_BLOCK_TYPE_FS_DBLOCK,
+ NULL,
GNUNET_BLOCK_EO_NONE,
&key,
NULL, 0,
- NULL, 0,
NULL, 0))
return 4;
GNUNET_log_skip (1, GNUNET_NO);
if (GNUNET_BLOCK_EVALUATION_REQUEST_INVALID !=
GNUNET_BLOCK_evaluate (ctx,
GNUNET_BLOCK_TYPE_FS_DBLOCK,
+ NULL,
GNUNET_BLOCK_EO_NONE,
&key,
- NULL, 0,
"bogus", 5,
NULL, 0))
return 8;
* @param nonce random value used to seed the group creation
* @param raw_data optional serialized prior state of the group, NULL if unavailable/fresh
* @param raw_data_size number of bytes in @a raw_data, 0 if unavailable/fresh
+ * @param va variable arguments specific to @a type
* @return block group handle, NULL if block groups are not supported
* by this @a type of block (this is not an error)
*/
enum GNUNET_BLOCK_Type type,
uint32_t nonce,
const void *raw_data,
- size_t raw_data_size)
+ size_t raw_data_size,
+ va_list va)
{
return GNUNET_BLOCK_GROUP_bf_create (cls,
GNS_BF_SIZE,
*
* @param cls closure
* @param type block type
+ * @param bg block group to use for evaluation
* @param eo control flags
* @param query original query (hash)
- * @param bf pointer to bloom filter associated with @a query; possibly updated (!)
- * @param bf_mutator mutation value for @a bf
* @param xquery extrended query data (can be NULL, depending on @a type)
* @param xquery_size number of bytes in @a xquery
* @param reply_block response to validate
static enum GNUNET_BLOCK_EvaluationResult
block_plugin_gns_evaluate (void *cls,
enum GNUNET_BLOCK_Type type,
+ struct GNUNET_BLOCK_Group *bg,
enum GNUNET_BLOCK_EvaluationOptions eo,
const struct GNUNET_HashCode *query,
- struct GNUNET_CONTAINER_BloomFilter **bf,
- int32_t bf_mutator,
const void *xquery,
size_t xquery_size,
const void *reply_block,
const struct GNUNET_GNSRECORD_Block *block;
struct GNUNET_HashCode h;
struct GNUNET_HashCode chash;
- struct GNUNET_HashCode mhash;
if (type != GNUNET_BLOCK_TYPE_GNS_NAMERECORD)
return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED;
GNUNET_break_op (0);
return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
}
- if (NULL != bf)
- {
- GNUNET_CRYPTO_hash (reply_block, reply_block_size, &chash);
- GNUNET_BLOCK_mingle_hash (&chash, bf_mutator, &mhash);
- if (NULL != *bf)
- {
- if (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test(*bf, &mhash))
- return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
- }
- else
- {
- *bf = GNUNET_CONTAINER_bloomfilter_init(NULL, 8, BLOOMFILTER_K);
- }
- GNUNET_CONTAINER_bloomfilter_add(*bf, &mhash);
- }
+ GNUNET_CRYPTO_hash (reply_block,
+ reply_block_size,
+ &chash);
+ if (GNUNET_YES ==
+ GNUNET_BLOCK_GROUP_bf_test_and_set (bg,
+ &chash))
+ return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
return GNUNET_BLOCK_EVALUATION_OK_MORE;
}
size_t raw_data_size);
+/**
+ * Test if @a hc is contained in the Bloom filter of @a bg. If so,
+ * return #GNUNET_YES. If not, add @a hc to the Bloom filter and
+ * return #GNUNET_NO.
+ *
+ * @param bg block group to use for testing
+ * @param hc hash of element to evaluate
+ * @return #GNUNET_YES if @a hc is (likely) a duplicate
+ * #GNUNET_NO if @a hc was definitively not in @bg (but now is)
+ */
+int
+GNUNET_BLOCK_GROUP_bf_test_and_set (struct GNUNET_BLOCK_Group *bg,
+ const struct GNUNET_HashCode *hc);
+
#if 0 /* keep Emacsens' auto-indent happy */
{
* @param nonce random value used to seed the group creation
* @param raw_data optional serialized prior state of the group, NULL if unavailable/fresh
* @param raw_data_size number of bytes in @a raw_data, 0 if unavailable/fresh
+ * @param ... type-specific additional data, can be empty
* @return block group handle, NULL if block groups are not supported
* by this @a type of block (this is not an error)
*/
enum GNUNET_BLOCK_Type type,
uint32_t nonce,
const void *raw_data,
- size_t raw_data_size);
+ size_t raw_data_size,
+ ...);
/**
* Serialize state of a block group.
*
* @param bg group to serialize
+ * @param[out] nonce set to the nonce of the @a bg
* @param[out] raw_data set to the serialized state
* @param[out] raw_data_size set to the number of bytes in @a raw_data
* @return #GNUNET_OK on success, #GNUNET_NO if serialization is not
*/
int
GNUNET_BLOCK_group_serialize (struct GNUNET_BLOCK_Group *bg,
+ uint32_t *nonce,
void **raw_data,
size_t *raw_data_size);
*
* @param ctx block contxt
* @param type block type
+ * @param group block group to use for evaluation
* @param eo evaluation options to control evaluation
* @param query original query (hash)
- * @param bf pointer to bloom filter associated with query; possibly updated (!)
- * @param bf_mutator mutation value for @a bf
* @param xquery extrended query data (can be NULL, depending on type)
* @param xquery_size number of bytes in @a xquery
* @param reply_block response to validate
enum GNUNET_BLOCK_EvaluationResult
GNUNET_BLOCK_evaluate (struct GNUNET_BLOCK_Context *ctx,
enum GNUNET_BLOCK_Type type,
+ struct GNUNET_BLOCK_Group *group,
enum GNUNET_BLOCK_EvaluationOptions eo,
const struct GNUNET_HashCode *query,
- struct GNUNET_CONTAINER_BloomFilter **bf,
- int32_t bf_mutator,
const void *xquery,
size_t xquery_size,
const void *reply_block,
enum GNUNET_BLOCK_Type type,
const void *block,
size_t block_size,
- struct GNUNET_HashCode * key);
-
+ struct GNUNET_HashCode *key);
/**
- * Construct a bloom filter that would filter out the given
- * results.
+ * Update block group to filter out the given results. Note that the
+ * use of a hash for seen results implies that the caller magically
+ * knows how the specific block engine hashes for filtering
+ * duplicates, so this API may not always apply.
*
* @param bf_mutator mutation value to use
* @param seen_results results already seen
* @param seen_results_count number of entries in @a seen_results
- * @return NULL if seen_results_count is 0, otherwise a BF
- * that would match the given results.
+ * @return #GNUNET_SYSERR if not supported, #GNUNET_OK on success
+ */
+int
+GNUNET_BLOCK_group_set_seen (struct GNUNET_BLOCK_Group *bg,
+ const struct GNUNET_HashCode *seen_results,
+ unsigned int seen_results_count);
+
+
+/**
+ * Try merging two block groups. Afterwards, @a bg1 should remain
+ * valid and contain the rules from both @a bg1 and @bg2, and
+ * @a bg2 should be destroyed (as part of this call). The latter
+ * should happen even if merging is not supported.
+ *
+ * @param[in,out] bg1 first group to merge, is updated
+ * @param bg2 second group to merge, is destroyed
+ * @return #GNUNET_OK on success,
+ * #GNUNET_NO if merge failed due to different nonce
+ * #GNUNET_SYSERR if merging is not supported
*/
-struct GNUNET_CONTAINER_BloomFilter *
-GNUNET_BLOCK_construct_bloomfilter (int32_t bf_mutator,
- const struct GNUNET_HashCode *seen_results,
- unsigned int seen_results_count);
+int
+GNUNET_BLOCK_group_merge (struct GNUNET_BLOCK_Group *bg1,
+ struct GNUNET_BLOCK_Group *bg2);
#if 0 /* keep Emacsens' auto-indent happy */
#include "gnunet_block_lib.h"
+/**
+ * Mark elements as "seen" using a hash of the element. Not supported
+ * by all block plugins.
+ *
+ * @param bg group to update
+ * @param seen_results results already seen
+ * @param seen_results_count number of entries in @a seen_results
+ */
+typedef void
+(*GNUNET_BLOCK_GroupMarkSeenFunction)(struct GNUNET_BLOCK_Group *bg,
+ const struct GNUNET_HashCode *seen_results,
+ unsigned int seen_results_count);
+
+
+/**
+ * Merge two groups, if possible. Not supported by all block plugins,
+ * can also fail if the nonces were different.
+ *
+ * @param bg1 group to update
+ * @param bg2 group to merge into @a bg1
+ * @return #GNUNET_OK on success, #GNUNET_NO if the nonces were different and thus
+ * we failed.
+ */
+typedef int
+(*GNUNET_BLOCK_GroupMergeFunction)(struct GNUNET_BLOCK_Group *bg1,
+ const struct GNUNET_BLOCK_Group *bg2);
+
+
/**
* Serialize state of a block group.
*
* @param bg group to serialize
+ * @param[out] nonce set to the nonce of the @a bg
* @param[out] raw_data set to the serialized state
* @param[out] raw_data_size set to the number of bytes in @a raw_data
* @return #GNUNET_OK on success, #GNUNET_NO if serialization is not
*/
typedef int
(*GNUNET_BLOCK_GroupSerializeFunction)(struct GNUNET_BLOCK_Group *bg,
+ uint32_t *nonce,
void **raw_data,
size_t *raw_data_size);
*/
GNUNET_BLOCK_GroupSerializeFunction serialize_cb;
+ /**
+ * Function to call to mark elements as seen in the group.
+ * Can be NULL if not supported.
+ */
+ GNUNET_BLOCK_GroupMarkSeenFunction mark_seen_cb;
+
+ /**
+ * Function to call to merge two groups.
+ * Can be NULL if not supported.
+ */
+ GNUNET_BLOCK_GroupMergeFunction merge_cb;
+
/**
* Function to call to destroy the block group.
* Must not be NULL.
* @param nonce random value used to seed the group creation
* @param raw_data optional serialized prior state of the group, NULL if unavailable/fresh
* @param raw_data_size number of bytes in @a raw_data, 0 if unavailable/fresh
+ * @param va variable arguments specific to @a type
* @return block group handle, NULL if block groups are not supported
* by this @a type of block (this is not an error)
*/
enum GNUNET_BLOCK_Type type,
uint32_t nonce,
const void *raw_data,
- size_t raw_data_size);
+ size_t raw_data_size,
+ va_list va);
/**
*
* @param cls closure
* @param type block type
+ * @param group which block group to use for evaluation
* @param eo evaluation options to control evaluation
* @param query original query (hash)
- * @param bf pointer to bloom filter associated with query; possibly updated (!)
- * @param bf_mutator mutation value for @a bf
* @param xquery extrended query data (can be NULL, depending on type)
* @param xquery_size number of bytes in @a xquery
* @param reply_block response to validate
typedef enum GNUNET_BLOCK_EvaluationResult
(*GNUNET_BLOCK_EvaluationFunction) (void *cls,
enum GNUNET_BLOCK_Type type,
+ struct GNUNET_BLOCK_Group *group,
enum GNUNET_BLOCK_EvaluationOptions eo,
const struct GNUNET_HashCode *query,
- struct GNUNET_CONTAINER_BloomFilter **bf,
- int32_t bf_mutator,
const void *xquery,
size_t xquery_size,
const void *reply_block,
* @param nonce random value used to seed the group creation
* @param raw_data optional serialized prior state of the group, NULL if unavailable/fresh
* @param raw_data_size number of bytes in @a raw_data, 0 if unavailable/fresh
+ * @param va variable arguments specific to @a type
* @return block group handle, NULL if block groups are not supported
* by this @a type of block (this is not an error)
*/
enum GNUNET_BLOCK_Type type,
uint32_t nonce,
const void *raw_data,
- size_t raw_data_size)
+ size_t raw_data_size,
+ va_list va)
{
return GNUNET_BLOCK_GROUP_bf_create (cls,
REGEX_BF_SIZE,
*
* @param cls closure
* @param type block type
+ * @param bg block group to evaluate against
* @param eo control flags
* @param query original query (hash)
- * @param bf pointer to bloom filter associated with query; possibly updated (!)
- * @param bf_mutator mutation value for bf
* @param xquery extrended query data (can be NULL, depending on type)
* @param xquery_size number of bytes in @a xquery
* @param reply_block response to validate
static enum GNUNET_BLOCK_EvaluationResult
evaluate_block_regex (void *cls,
enum GNUNET_BLOCK_Type type,
+ struct GNUNET_BLOCK_Group *bg,
enum GNUNET_BLOCK_EvaluationOptions eo,
const struct GNUNET_HashCode *query,
- struct GNUNET_CONTAINER_BloomFilter **bf,
- int32_t bf_mutator,
const void *xquery,
size_t xquery_size,
const void *reply_block,
size_t reply_block_size)
{
+ struct GNUNET_HashCode chash;
+
if (NULL == reply_block)
{
if (0 != xquery_size)
default:
break;
}
- if (NULL != bf)
- {
- struct GNUNET_HashCode chash;
- struct GNUNET_HashCode mhash;
-
- GNUNET_CRYPTO_hash (reply_block, reply_block_size, &chash);
- GNUNET_BLOCK_mingle_hash (&chash, bf_mutator, &mhash);
- if (NULL != *bf)
- {
- if (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test (*bf, &mhash))
- return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
- }
- else
- {
- *bf = GNUNET_CONTAINER_bloomfilter_init (NULL, 8, GNUNET_CONSTANTS_BLOOMFILTER_K);
- }
- GNUNET_CONTAINER_bloomfilter_add (*bf, &mhash);
- }
+ GNUNET_CRYPTO_hash (reply_block,
+ reply_block_size,
+ &chash);
+ if (GNUNET_YES ==
+ GNUNET_BLOCK_GROUP_bf_test_and_set (bg,
+ &chash))
+ return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
return GNUNET_BLOCK_EVALUATION_OK_MORE;
}
*
* @param cls closure
* @param type block type
+ * @param bg block group to evaluate against
* @param eo control flags
* @param query original query (hash)
- * @param bf pointer to bloom filter associated with query; possibly updated (!)
- * @param bf_mutator mutation value for bf
* @param xquery extrended query data (can be NULL, depending on type)
* @param xquery_size number of bytes in @a xquery
* @param reply_block response to validate
static enum GNUNET_BLOCK_EvaluationResult
evaluate_block_regex_accept (void *cls,
enum GNUNET_BLOCK_Type type,
+ struct GNUNET_BLOCK_Group *bg,
enum GNUNET_BLOCK_EvaluationOptions eo,
- const struct GNUNET_HashCode * query,
- struct GNUNET_CONTAINER_BloomFilter **bf,
- int32_t bf_mutator, const void *xquery,
+ const struct GNUNET_HashCode *query,
+ const void *xquery,
size_t xquery_size, const void *reply_block,
size_t reply_block_size)
{
const struct RegexAcceptBlock *rba;
+ struct GNUNET_HashCode chash;
if (0 != xquery_size)
{
GNUNET_break_op(0);
return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
}
- if (NULL != bf)
- {
- struct GNUNET_HashCode chash;
- struct GNUNET_HashCode mhash;
-
- GNUNET_CRYPTO_hash (reply_block, reply_block_size, &chash);
- GNUNET_BLOCK_mingle_hash (&chash, bf_mutator, &mhash);
- if (NULL != *bf)
- {
- if (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test (*bf, &mhash))
- return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
- }
- else
- {
- *bf = GNUNET_CONTAINER_bloomfilter_init (NULL, 8, GNUNET_CONSTANTS_BLOOMFILTER_K);
- }
- GNUNET_CONTAINER_bloomfilter_add (*bf, &mhash);
- }
+ GNUNET_CRYPTO_hash (reply_block,
+ reply_block_size,
+ &chash);
+ if (GNUNET_YES ==
+ GNUNET_BLOCK_GROUP_bf_test_and_set (bg,
+ &chash))
+ return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
return GNUNET_BLOCK_EVALUATION_OK_MORE;
}
*
* @param cls closure
* @param type block type
+ * @param bg group to evaluate against
* @param eo control flags
* @param query original query (hash)
- * @param bf pointer to bloom filter associated with query; possibly updated (!)
- * @param bf_mutator mutation value for bf
* @param xquery extrended query data (can be NULL, depending on type)
* @param xquery_size number of bytes in xquery
* @param reply_block response to validate
static enum GNUNET_BLOCK_EvaluationResult
block_plugin_regex_evaluate (void *cls,
enum GNUNET_BLOCK_Type type,
+ struct GNUNET_BLOCK_Group *bg,
enum GNUNET_BLOCK_EvaluationOptions eo,
const struct GNUNET_HashCode *query,
- struct GNUNET_CONTAINER_BloomFilter **bf,
- int32_t bf_mutator,
const void *xquery,
size_t xquery_size,
const void *reply_block,
case GNUNET_BLOCK_TYPE_REGEX:
result = evaluate_block_regex (cls,
type,
+ bg,
eo,
query,
- bf, bf_mutator,
xquery, xquery_size,
reply_block, reply_block_size);
break;
case GNUNET_BLOCK_TYPE_REGEX_ACCEPT:
result = evaluate_block_regex_accept (cls,
type,
+ bg,
eo,
query,
- bf, bf_mutator,
xquery, xquery_size,
reply_block, reply_block_size);
break;