/** * 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 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 * @param reply_block_size number of bytes in reply block * @return characterization of result */ static enum GNUNET_BLOCK_EvaluationResult block_plugin_template_evaluate (void *cls, enum GNUNET_BLOCK_Type type, 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... */ return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED; }
/** * Calculate when we would like to send the next HELLO to this * peer and ask for it. * * @param cls for which peer to schedule the HELLO */ static void schedule_next_hello (void *cls) { struct Peer *pl = cls; struct FindAdvHelloContext fah; struct GNUNET_MQ_Envelope *env; size_t want; struct GNUNET_TIME_Relative delay; struct GNUNET_HashCode hc; pl->hello_delay_task = NULL; GNUNET_assert (NULL != pl->mq); /* find applicable HELLOs */ fah.peer = pl; fah.result = NULL; fah.max_size = GNUNET_SERVER_MAX_MESSAGE_SIZE - 1; fah.next_adv = GNUNET_TIME_UNIT_FOREVER_REL; GNUNET_CONTAINER_multipeermap_iterate (peers, &find_advertisable_hello, &fah); pl->hello_delay_task = GNUNET_SCHEDULER_add_delayed (fah.next_adv, &schedule_next_hello, pl); if (NULL == fah.result) return; delay = GNUNET_TIME_absolute_get_remaining (pl->next_hello_allowed); if (0 != delay.rel_value_us) return; want = GNUNET_HELLO_size (fah.result->hello); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending HELLO with %u bytes", (unsigned int) want); env = GNUNET_MQ_msg_copy (&fah.result->hello->header); GNUNET_MQ_send (pl->mq, env); /* avoid sending this one again soon */ GNUNET_CRYPTO_hash (&pl->pid, sizeof (struct GNUNET_PeerIdentity), &hc); GNUNET_CONTAINER_bloomfilter_add (fah.result->filter, &hc); GNUNET_STATISTICS_update (stats, gettext_noop ("# HELLO messages gossipped"), 1, GNUNET_NO); /* prepare to send the next one */ if (NULL != pl->hello_delay_task) GNUNET_SCHEDULER_cancel (pl->hello_delay_task); pl->next_hello_allowed = GNUNET_TIME_relative_to_absolute (HELLO_ADVERTISEMENT_MIN_FREQUENCY); pl->hello_delay_task = GNUNET_SCHEDULER_add_now (&schedule_next_hello, pl); }
/** * Setup bloom filter for the given peer entry. * * @param peer entry to initialize */ static void setup_filter (struct Peer *peer) { /* 2^{-5} chance of not sending a HELLO to a peer is * acceptably small (if the filter is 50% full); * 64 bytes of memory are small compared to the rest * of the data structure and would only really become * "useless" once a HELLO has been passed on to ~100 * other peers, which is likely more than enough in * any case; hence 64, 5 as bloomfilter parameters. */ peer->filter = GNUNET_CONTAINER_bloomfilter_init (NULL, 64, 5); peer->filter_expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADVERTISEMENT_MIN_REPEAT_FREQUENCY); /* never send a peer its own HELLO */ GNUNET_CONTAINER_bloomfilter_add (peer->filter, &peer->pid.hashPubKey); }
/** * Resize a bloom filter. Note that this operation * is pretty costly. Essentially, the bloom filter * needs to be completely re-build. * * @param bf the filter * @param iterator an iterator over all elements stored in the BF * @param iterator_cls argument to the iterator function * @param size the new size for the filter * @param k the new number of GNUNET_CRYPTO_hash-function to apply per element */ void GNUNET_CONTAINER_bloomfilter_resize (struct GNUNET_CONTAINER_BloomFilter *bf, GNUNET_HashCodeIterator iterator, void *iterator_cls, size_t size, unsigned int k) { GNUNET_HashCode hc; unsigned int i; GNUNET_free (bf->bitArray); i = 1; while (i < size) i *= 2; size = i; /* make sure it's a power of 2 */ bf->bitArraySize = size; bf->bitArray = GNUNET_malloc (size); if (bf->filename != NULL) make_empty_file (bf->fh, bf->bitArraySize * 4LL); while (GNUNET_YES == iterator (iterator_cls, &hc)) GNUNET_CONTAINER_bloomfilter_add (bf, &hc); }
/** * Store an item in the datastore. * * @param h handle to the datacache * @param key key to store data under * @param size number of bytes in data * @param data data to store * @param type type of the value * @param discard_time when to discard the value in any case * @param path_info_len number of entries in 'path_info' * @param path_info a path through the network * @return GNUNET_OK on success, GNUNET_SYSERR on error, GNUNET_NO if duplicate */ int GNUNET_DATACACHE_put (struct GNUNET_DATACACHE_Handle *h, const struct GNUNET_HashCode * key, size_t size, const char *data, enum GNUNET_BLOCK_Type type, struct GNUNET_TIME_Absolute discard_time, unsigned int path_info_len, const struct GNUNET_PeerIdentity *path_info) { ssize_t used; used = h->api->put (h->api->cls, key, size, data, type, discard_time, path_info_len, path_info); if (-1 == used) { GNUNET_break (0); return GNUNET_SYSERR; } if (0 == used) { /* duplicate */ return GNUNET_NO; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Stored data under key `%s' in cache\n", GNUNET_h2s (key)); GNUNET_STATISTICS_update (h->stats, gettext_noop ("# bytes stored"), size, GNUNET_NO); GNUNET_STATISTICS_update (h->stats, gettext_noop ("# items stored"), 1, GNUNET_NO); if (NULL != h->filter) GNUNET_CONTAINER_bloomfilter_add (h->filter, key); while (h->utilization + used > h->env.quota) GNUNET_assert (GNUNET_OK == h->api->del (h->api->cls)); h->utilization += used; return GNUNET_OK; }
/** * Function to fill send buffer with HELLO. * * @param cls 'struct Peer' of the target peer * @param size number of bytes available in buf * @param buf where the callee should write the message * @return number of bytes written to buf */ static size_t hello_advertising_ready (void *cls, size_t size, void *buf) { struct Peer *pl = cls; struct FindAdvHelloContext fah; size_t want; pl->hello_req = NULL; GNUNET_assert (GNUNET_YES == pl->is_connected); /* find applicable HELLOs */ fah.peer = pl; fah.result = NULL; fah.max_size = size; fah.next_adv = GNUNET_TIME_UNIT_FOREVER_REL; GNUNET_CONTAINER_multihashmap_iterate (peers, &find_advertisable_hello, &fah); want = 0; if (fah.result != NULL) { want = GNUNET_HELLO_size (fah.result->hello); GNUNET_assert (want <= size); memcpy (buf, fah.result->hello, want); GNUNET_CONTAINER_bloomfilter_add (fah.result->filter, &pl->pid.hashPubKey); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' with %u bytes", "HELLO", (unsigned int) want); GNUNET_STATISTICS_update (stats, gettext_noop ("# HELLO messages gossipped"), 1, GNUNET_NO); } if (pl->hello_delay_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (pl->hello_delay_task); pl->next_hello_allowed = GNUNET_TIME_relative_to_absolute (HELLO_ADVERTISEMENT_MIN_FREQUENCY); pl->hello_delay_task = GNUNET_SCHEDULER_add_now (&schedule_next_hello, pl); return want; }
/** * Store an item in the datastore. * * @param h handle to the datacache * @param key key to store data under * @param size number of bytes in data * @param data data to store * @param type type of the value * @param discard_time when to discard the value in any case * @return GNUNET_OK on success, GNUNET_SYSERR on error (full, etc.) */ int GNUNET_DATACACHE_put (struct GNUNET_DATACACHE_Handle *h, const GNUNET_HashCode * key, size_t size, const char *data, enum GNUNET_BLOCK_Type type, struct GNUNET_TIME_Absolute discard_time) { uint32_t used; used = h->api->put (h->api->cls, key, size, data, type, discard_time); if (used == 0) { GNUNET_break (0); return GNUNET_SYSERR; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Stored data under key `%s' in cache\n", GNUNET_h2s (key)); GNUNET_STATISTICS_update (h->stats, gettext_noop ("# bytes stored"), size, GNUNET_NO); GNUNET_CONTAINER_bloomfilter_add (h->filter, key); while (h->utilization + used > h->env.quota) GNUNET_assert (GNUNET_OK == h->api->del (h->api->cls)); h->utilization += used; return GNUNET_OK; }
int main (int argc, char *argv[]) { struct GNUNET_CONTAINER_BloomFilter *bf; struct GNUNET_CONTAINER_BloomFilter *bfi; GNUNET_HashCode tmp; int i; int ok1; int ok2; int falseok; char buf[SIZE]; struct stat sbuf; GNUNET_log_setup ("test-container-bloomfilter", "WARNING", NULL); GNUNET_CRYPTO_seed_weak_random (1); if (0 == STAT (TESTFILE, &sbuf)) if (0 != UNLINK (TESTFILE)) GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "unlink", TESTFILE); bf = GNUNET_CONTAINER_bloomfilter_load (TESTFILE, SIZE, K); for (i = 0; i < 200; i++) { nextHC (&tmp); GNUNET_CONTAINER_bloomfilter_add (bf, &tmp); } GNUNET_CRYPTO_seed_weak_random (1); ok1 = 0; for (i = 0; i < 200; i++) { nextHC (&tmp); if (GNUNET_CONTAINER_bloomfilter_test (bf, &tmp) == GNUNET_YES) ok1++; } if (ok1 != 200) { printf ("Got %d elements out of" "200 expected after insertion.\n", ok1); GNUNET_CONTAINER_bloomfilter_free (bf); return -1; } if (GNUNET_OK != GNUNET_CONTAINER_bloomfilter_get_raw_data (bf, buf, SIZE)) { GNUNET_CONTAINER_bloomfilter_free (bf); return -1; } GNUNET_CONTAINER_bloomfilter_free (bf); bf = GNUNET_CONTAINER_bloomfilter_load (TESTFILE, SIZE, K); GNUNET_assert (bf != NULL); bfi = GNUNET_CONTAINER_bloomfilter_init (buf, SIZE, K); GNUNET_assert (bfi != NULL); GNUNET_CRYPTO_seed_weak_random (1); ok1 = 0; ok2 = 0; for (i = 0; i < 200; i++) { nextHC (&tmp); if (GNUNET_CONTAINER_bloomfilter_test (bf, &tmp) == GNUNET_YES) ok1++; if (GNUNET_CONTAINER_bloomfilter_test (bfi, &tmp) == GNUNET_YES) ok2++; } if (ok1 != 200) { printf ("Got %d elements out of 200 " "expected after reloading.\n", ok1); GNUNET_CONTAINER_bloomfilter_free (bf); GNUNET_CONTAINER_bloomfilter_free (bfi); return -1; } if (ok2 != 200) { printf ("Got %d elements out of 200 " "expected after initialization.\n", ok2); GNUNET_CONTAINER_bloomfilter_free (bf); GNUNET_CONTAINER_bloomfilter_free (bfi); return -1; } GNUNET_CRYPTO_seed_weak_random (1); for (i = 0; i < 100; i++) { nextHC (&tmp); GNUNET_CONTAINER_bloomfilter_remove (bf, &tmp); GNUNET_CONTAINER_bloomfilter_remove (bfi, &tmp); } GNUNET_CRYPTO_seed_weak_random (1); ok1 = 0; ok2 = 0; for (i = 0; i < 200; i++) { nextHC (&tmp); if (GNUNET_CONTAINER_bloomfilter_test (bf, &tmp) == GNUNET_YES) ok1++; if (GNUNET_CONTAINER_bloomfilter_test (bfi, &tmp) == GNUNET_YES) ok2++; } if (ok1 != 100) { printf ("Expected 100 elements in loaded filter" " after adding 200 and deleting 100, got %d\n", ok1); GNUNET_CONTAINER_bloomfilter_free (bf); GNUNET_CONTAINER_bloomfilter_free (bfi); return -1; } if (ok2 != 200) { printf ("Expected 200 elements in initialized filter" " after adding 200 and deleting 100 " "(which should do nothing for a filter not backed by a file), got %d\n", ok2); GNUNET_CONTAINER_bloomfilter_free (bf); GNUNET_CONTAINER_bloomfilter_free (bfi); return -1; } GNUNET_CRYPTO_seed_weak_random (3); GNUNET_CONTAINER_bloomfilter_clear (bf); falseok = 0; for (i = 0; i < 1000; i++) { nextHC (&tmp); if (GNUNET_CONTAINER_bloomfilter_test (bf, &tmp) == GNUNET_YES) falseok++; } if (falseok > 0) { GNUNET_CONTAINER_bloomfilter_free (bf); GNUNET_CONTAINER_bloomfilter_free (bfi); return -1; } if (GNUNET_OK != GNUNET_CONTAINER_bloomfilter_or (bf, buf, SIZE)) { GNUNET_CONTAINER_bloomfilter_free (bf); GNUNET_CONTAINER_bloomfilter_free (bfi); return -1; } GNUNET_CRYPTO_seed_weak_random (2); i = 20; GNUNET_CONTAINER_bloomfilter_resize (bfi, &add_iterator, &i, SIZE * 2, K); GNUNET_CRYPTO_seed_weak_random (2); i = 20; GNUNET_CONTAINER_bloomfilter_resize (bf, &add_iterator, &i, SIZE * 2, K); GNUNET_CRYPTO_seed_weak_random (2); ok1 = 0; ok2 = 0; for (i = 0; i < 20; i++) { nextHC (&tmp); if (GNUNET_CONTAINER_bloomfilter_test (bf, &tmp) == GNUNET_YES) ok1++; if (GNUNET_CONTAINER_bloomfilter_test (bfi, &tmp) == GNUNET_YES) ok2++; } if (ok1 != 20) { printf ("Expected 20 elements in resized file-backed filter" " after adding 20, got %d\n", ok1); GNUNET_CONTAINER_bloomfilter_free (bf); GNUNET_CONTAINER_bloomfilter_free (bfi); return -1; } if (ok2 != 20) { printf ("Expected 20 elements in resized filter" " after adding 20, got %d\n", ok2); GNUNET_CONTAINER_bloomfilter_free (bf); GNUNET_CONTAINER_bloomfilter_free (bfi); return -1; } GNUNET_CONTAINER_bloomfilter_free (bf); GNUNET_CONTAINER_bloomfilter_free (bfi); GNUNET_break (0 == UNLINK (TESTFILE)); return 0; }
/** * Function called to validate a reply or a request of type * #GNUNET_BLOCK_TYPE_REGEX. * For request evaluation, pass "NULL" for the reply_block. * Note that it is assumed that the reply has already been * matched to the key (and signatures checked) as it would * be done with the #GNUNET_BLOCK_get_key() function. * * @param cls closure * @param type block type * @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 * @param reply_block_size number of bytes in @a reply_block * @return characterization of result */ static enum GNUNET_BLOCK_EvaluationResult evaluate_block_regex (void *cls, enum GNUNET_BLOCK_Type type, 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) { if (NULL == reply_block) { if (0 != xquery_size) { const char *s; s = (const char *) xquery; if ('\0' != s[xquery_size - 1]) /* must be valid 0-terminated string */ { GNUNET_break_op (0); return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID; } } return GNUNET_BLOCK_EVALUATION_REQUEST_VALID; } if (0 != xquery_size) { const char *s; s = (const char *) xquery; if ('\0' != s[xquery_size - 1]) /* must be valid 0-terminated string */ { GNUNET_break_op (0); return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID; } } else if (NULL != query) { /* xquery is required for regex GETs, at least an empty string */ GNUNET_break_op (0); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "type %d, query %p, xquery %p\n", type, query, xquery); return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID; } switch (REGEX_BLOCK_check (reply_block, reply_block_size, query, xquery)) { case GNUNET_SYSERR: GNUNET_break_op(0); return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; case GNUNET_NO: /* xquery missmatch, can happen */ return GNUNET_BLOCK_EVALUATION_RESULT_IRRELEVANT; 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); } return GNUNET_BLOCK_EVALUATION_OK_MORE; }
/** * Function called to validate a reply or a request of type * #GNUNET_BLOCK_TYPE_REGEX_ACCEPT. * For request evaluation, pass "NULL" for the reply_block. * Note that it is assumed that the reply has already been * matched to the key (and signatures checked) as it would * be done with the #GNUNET_BLOCK_get_key() function. * * @param cls closure * @param type block type * @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 * @param reply_block_size number of bytes in @a reply_block * @return characterization of result */ static enum GNUNET_BLOCK_EvaluationResult evaluate_block_regex_accept (void *cls, enum GNUNET_BLOCK_Type type, 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) { const struct RegexAcceptBlock *rba; if (0 != xquery_size) { GNUNET_break_op (0); return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID; } if (NULL == reply_block) return GNUNET_BLOCK_EVALUATION_REQUEST_VALID; if (sizeof (struct RegexAcceptBlock) != reply_block_size) { GNUNET_break_op(0); return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; } rba = reply_block; if (ntohl (rba->purpose.size) != sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + sizeof (struct GNUNET_TIME_AbsoluteNBO) + sizeof (struct GNUNET_HashCode)) { GNUNET_break_op(0); return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; } if (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (rba->expiration_time)).rel_value_us) { /* technically invalid, but can happen without an error, so we're nice by reporting it as a 'duplicate' */ return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE; } if (GNUNET_OK != GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_REGEX_ACCEPT, &rba->purpose, &rba->signature, &rba->peer.public_key)) { 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); } return GNUNET_BLOCK_EVALUATION_OK_MORE; }
/** * Function called to validate a reply or a request. For * request evaluation, simply pass "NULL" for the @a reply_block. * * @param cls closure * @param type block type * @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 * @param reply_block_size number of bytes in @a reply_block * @return characterization of result */ static enum GNUNET_BLOCK_EvaluationResult block_plugin_dht_evaluate (void *cls, enum GNUNET_BLOCK_Type type, 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; struct GNUNET_HashCode phash; if (type != GNUNET_BLOCK_TYPE_DHT_HELLO) return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED; if (xquery_size != 0) { GNUNET_break_op (0); return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID; } if (NULL == reply_block) return GNUNET_BLOCK_EVALUATION_REQUEST_VALID; if (reply_block_size < sizeof (struct GNUNET_MessageHeader)) { GNUNET_break_op (0); return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; } msg = reply_block; if (reply_block_size != ntohs (msg->size)) { GNUNET_break_op (0); return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; } hello = reply_block; if (GNUNET_OK != GNUNET_HELLO_get_id (hello, &pid)) { 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); } return GNUNET_BLOCK_EVALUATION_OK_MORE; }
/** * Function called to validate a reply or a request. For * request evaluation, simply pass "NULL" for the reply_block. * Note that it is assumed that the reply has already been * matched to the key (and signatures checked) as it would * be done with the "get_key" function. * * @param cls closure * @param type block type * @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 * @param reply_block_size number of bytes in @a reply_block * @return characterization of result */ static enum GNUNET_BLOCK_EvaluationResult block_plugin_gns_evaluate (void *cls, enum GNUNET_BLOCK_Type type, 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) { 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; if (NULL == reply_block) { if (0 != xquery_size) { GNUNET_break_op (0); return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID; } return GNUNET_BLOCK_EVALUATION_REQUEST_VALID; } /* this is a reply */ if (reply_block_size < sizeof (struct GNUNET_GNSRECORD_Block)) { GNUNET_break_op (0); return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; } block = reply_block; if (ntohl (block->purpose.size) + sizeof (struct GNUNET_CRYPTO_EcdsaSignature) + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) != reply_block_size) { GNUNET_break_op (0); return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; } GNUNET_CRYPTO_hash (&block->derived_key, sizeof (block->derived_key), &h); if (0 != memcmp (&h, query, sizeof (struct GNUNET_HashCode))) { GNUNET_break_op (0); return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; } if (GNUNET_OK != GNUNET_GNSRECORD_block_verify (block)) { 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); } return GNUNET_BLOCK_EVALUATION_OK_MORE; }