/** * 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; }
/** * Route the given request via the DHT. This includes updating * the bloom filter and retransmission times, building the P2P * message and initiating the routing operation. */ static void transmit_request (struct ClientQueryRecord *cqr) { int32_t reply_bf_mutator; struct GNUNET_CONTAINER_BloomFilter *reply_bf; 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); peer_bf = GNUNET_CONTAINER_bloomfilter_init (NULL, DHT_BLOOM_SIZE, GNUNET_CONSTANTS_BLOOMFILTER_K); LOG (GNUNET_ERROR_TYPE_DEBUG, "Initiating GET for %s, replication %u, already have %u replies\n", GNUNET_h2s(&cqr->key), cqr->replication, cqr->seen_replies_count); GDS_NEIGHBOURS_handle_get (cqr->type, cqr->msg_options, cqr->replication, 0 /* hop count */ , &cqr->key, cqr->xquery, cqr->xquery_size, reply_bf, reply_bf_mutator, peer_bf); GNUNET_CONTAINER_bloomfilter_free (reply_bf); GNUNET_CONTAINER_bloomfilter_free (peer_bf); /* exponential back-off for retries. * max GNUNET_TIME_STD_EXPONENTIAL_BACKOFF_THRESHOLD (15 min) */ cqr->retry_frequency = GNUNET_TIME_STD_BACKOFF (cqr->retry_frequency); cqr->retry_time = GNUNET_TIME_relative_to_absolute (cqr->retry_frequency); }
/** * Copy an existing memory. Any association with a file * on-disk will be lost in the process. * @param bf the filter to copy * @return copy of the bf */ struct GNUNET_CONTAINER_BloomFilter * GNUNET_CONTAINER_bloomfilter_copy (const struct GNUNET_CONTAINER_BloomFilter *bf) { return GNUNET_CONTAINER_bloomfilter_init (bf->bitArray, bf->bitArraySize, bf->addressesPerElement); }
/** * 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); }
/** * Handler for PUT messages. * * @param cls closure for the service * @param client the client we received this message from * @param message the actual message received */ static void handle_dht_local_put (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { const struct GNUNET_DHT_ClientPutMessage *dht_msg; struct GNUNET_CONTAINER_BloomFilter *peer_bf; uint16_t size; struct PendingMessage *pm; struct GNUNET_DHT_ClientPutConfirmationMessage *conf; size = ntohs (message->size); if (size < sizeof (struct GNUNET_DHT_ClientPutMessage)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# PUT requests received from clients"), 1, GNUNET_NO); dht_msg = (const struct GNUNET_DHT_ClientPutMessage *) message; LOG_TRAFFIC (GNUNET_ERROR_TYPE_DEBUG, "XDHT CLIENT-PUT %s @ %u\n", GNUNET_h2s (&dht_msg->key), getpid ()); /* give to local clients */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Handling local PUT of %u-bytes for query %s\n", size - sizeof (struct GNUNET_DHT_ClientPutMessage), GNUNET_h2s (&dht_msg->key)); GDS_CLIENTS_handle_reply (GNUNET_TIME_absolute_ntoh (dht_msg->expiration), &dht_msg->key, 0, NULL, 0, NULL, ntohl (dht_msg->type), size - sizeof (struct GNUNET_DHT_ClientPutMessage), &dht_msg[1]); /* store locally */ GDS_DATACACHE_handle_put (GNUNET_TIME_absolute_ntoh (dht_msg->expiration), &dht_msg->key, 0, NULL, ntohl (dht_msg->type), size - sizeof (struct GNUNET_DHT_ClientPutMessage), &dht_msg[1]); /* route to other peers */ peer_bf = GNUNET_CONTAINER_bloomfilter_init (NULL, DHT_BLOOM_SIZE, GNUNET_CONSTANTS_BLOOMFILTER_K); GDS_NEIGHBOURS_handle_put (ntohl (dht_msg->type), ntohl (dht_msg->options), ntohl (dht_msg->desired_replication_level), GNUNET_TIME_absolute_ntoh (dht_msg->expiration), 0 /* hop count */ , peer_bf, &dht_msg->key, 0, NULL, &dht_msg[1], size - sizeof (struct GNUNET_DHT_ClientPutMessage)); GDS_CLIENTS_process_put (ntohl (dht_msg->options), ntohl (dht_msg->type), 0, ntohl (dht_msg->desired_replication_level), 1, GDS_NEIGHBOURS_get_id(), GNUNET_TIME_absolute_ntoh (dht_msg->expiration), &dht_msg->key, &dht_msg[1], size - sizeof (struct GNUNET_DHT_ClientPutMessage)); GNUNET_CONTAINER_bloomfilter_free (peer_bf); pm = GNUNET_malloc (sizeof (struct PendingMessage) + sizeof (struct GNUNET_DHT_ClientPutConfirmationMessage)); conf = (struct GNUNET_DHT_ClientPutConfirmationMessage *) &pm[1]; conf->header.size = htons (sizeof (struct GNUNET_DHT_ClientPutConfirmationMessage)); conf->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_CLIENT_PUT_OK); conf->reserved = htonl (0); conf->unique_id = dht_msg->unique_id; pm->msg = &conf->header; add_pending_message (find_active_client (client), pm); GNUNET_SERVER_receive_done (client, 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; }
/** * Create a data cache. * * @param cfg configuration to use * @param section section in the configuration that contains our options * @return handle to use to access the service */ struct GNUNET_DATACACHE_Handle * GNUNET_DATACACHE_create (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section) { unsigned int bf_size; unsigned long long quota; struct GNUNET_DATACACHE_Handle *ret; char *libname; char *name; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_size (cfg, section, "QUOTA", "a)) { LOG (GNUNET_ERROR_TYPE_ERROR, _("No `%s' specified for `%s' in configuration!\n"), "QUOTA", section); return NULL; } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, section, "DATABASE", &name)) { LOG (GNUNET_ERROR_TYPE_ERROR, _("No `%s' specified for `%s' in configuration!\n"), "DATABASE", section); return NULL; } bf_size = quota / 32; /* 8 bit per entry, 1 bit per 32 kb in DB */ ret = GNUNET_malloc (sizeof (struct GNUNET_DATACACHE_Handle)); if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_yesno (cfg, section, "DISABLE_BF")) { if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_yesno (cfg, section, "DISABLE_BF_RC")) { ret->bloom_name = GNUNET_DISK_mktemp ("gnunet-datacachebloom"); } if (NULL != ret->bloom_name) { ret->filter = GNUNET_CONTAINER_bloomfilter_load (ret->bloom_name, quota / 1024, /* 8 bit per entry in DB, expect 1k entries */ 5); } if (NULL == ret->filter) { ret->filter = GNUNET_CONTAINER_bloomfilter_init (NULL, bf_size, 5); /* approx. 3% false positives at max use */ } } ret->stats = GNUNET_STATISTICS_create ("datacache", cfg); ret->section = GNUNET_strdup (section); ret->env.cfg = cfg; ret->env.delete_notify = &env_delete_notify; ret->env.section = ret->section; ret->env.cls = ret; ret->env.delete_notify = &env_delete_notify; ret->env.quota = quota; LOG (GNUNET_ERROR_TYPE_INFO, _("Loading `%s' datacache plugin\n"), name); GNUNET_asprintf (&libname, "libgnunet_plugin_datacache_%s", name); ret->short_name = name; ret->lib_name = libname; ret->api = GNUNET_PLUGIN_load (libname, &ret->env); if (ret->api == NULL) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Failed to load datacache plugin for `%s'\n"), name); GNUNET_DATACACHE_destroy (ret); return NULL; } return ret; }