From 2b869471ca92027e0ffa1d8180585055d7698762 Mon Sep 17 00:00:00 2001 From: Bart Polot Date: Mon, 11 Mar 2013 14:51:21 +0000 Subject: [PATCH] - allow GNUNET_BLOCK_evaluate on PUT requests for regex blocks --- src/regex/gnunet-regex-profiler.c | 2 +- src/regex/plugin_block_regex.c | 252 +++++++++++++++++++----------- src/regex/regex_block_lib.c | 74 ++++----- src/regex/regex_block_lib.h | 13 +- 4 files changed, 203 insertions(+), 138 deletions(-) diff --git a/src/regex/gnunet-regex-profiler.c b/src/regex/gnunet-regex-profiler.c index 41e454bbf..139092686 100644 --- a/src/regex/gnunet-regex-profiler.c +++ b/src/regex/gnunet-regex-profiler.c @@ -37,7 +37,7 @@ #include "gnunet_testbed_service.h" #define FIND_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 90) -#define SEARCHES_IN_PARALLEL 1 +#define SEARCHES_IN_PARALLEL 2 /** * DLL of operations diff --git a/src/regex/plugin_block_regex.c b/src/regex/plugin_block_regex.c index d3c973560..bfee12d7f 100644 --- a/src/regex/plugin_block_regex.c +++ b/src/regex/plugin_block_regex.c @@ -58,6 +58,157 @@ rdebug (void *cls, } +/** + * 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 "get_key" function. + * + * @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 +evaluate_block_regex (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) +{ + if (NULL == reply_block) /* queries (GET) are always valid */ + return GNUNET_BLOCK_EVALUATION_REQUEST_VALID; + if (0 != xquery_size) + { + const char *query; + + query = (const char *) xquery; + if ('\0' != query[xquery_size - 1]) /* must be valid string */ + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Block xquery not a valid string\n"); + return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; + } + } + else if (NULL != query) /* PUTs don't need xquery */ + { + const struct RegexBlock *rblock = reply_block; + + GNUNET_break_op (0); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Block with no xquery\n"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " key: %s, %u edges\n", + GNUNET_h2s (&rblock->key), ntohl (rblock->n_edges)); + GNUNET_REGEX_block_iterate (rblock, reply_block_size, &rdebug, NULL); + return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; + } + switch (GNUNET_REGEX_block_check (reply_block, + reply_block_size, + xquery)) + { + case GNUNET_SYSERR: + GNUNET_break_op(0); + return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; + case GNUNET_NO: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "BLOCK XQUERY %s not accepted\n", xquery); + return GNUNET_BLOCK_EVALUATION_RESULT_IRRELEVANT; + default: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "BLOCK XQUERY %s accepted\n", xquery); + 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, 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 "get_key" function. + * + * @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 +evaluate_block_regex_accept (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) +{ + 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 RegexAccept) != reply_block_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, 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. @@ -84,105 +235,26 @@ block_plugin_regex_evaluate (void *cls, enum GNUNET_BLOCK_Type type, size_t xquery_size, const void *reply_block, size_t reply_block_size) { - struct GNUNET_HashCode chash; - struct GNUNET_HashCode mhash; + enum GNUNET_BLOCK_EvaluationResult result; switch (type) { case GNUNET_BLOCK_TYPE_REGEX: - if (NULL == reply_block) - return GNUNET_BLOCK_EVALUATION_REQUEST_VALID; - if (0 != xquery_size) - { - const char *query; - - query = (const char *) xquery; - if ('\0' != query[xquery_size - 1]) /* must be valid string */ - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Block xquery not a valid string\n"); - return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; - } - } - else - { - const struct RegexBlock *rblock = reply_block; - - GNUNET_break_op (0); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Block with no xquery\n"); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " key: %s, %u edges\n", - GNUNET_h2s (&rblock->key), ntohl (rblock->n_edges)); - GNUNET_REGEX_block_iterate (rblock, reply_block_size, &rdebug, NULL); - return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; - } - switch (GNUNET_REGEX_block_check (reply_block, - reply_block_size, - xquery)) - { - case GNUNET_SYSERR: - GNUNET_break_op(0); - return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; - case GNUNET_NO: - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "BLOCK XQUERY %s not accepted\n", xquery); - return GNUNET_BLOCK_EVALUATION_RESULT_IRRELEVANT; - default: - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "BLOCK XQUERY %s accepted\n", xquery); - break; - } - 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; - + result = evaluate_block_regex (cls, type, query, bf, bf_mutator, + xquery, xquery_size, + reply_block, reply_block_size); + break; case GNUNET_BLOCK_TYPE_REGEX_ACCEPT: - 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 RegexAccept) != reply_block_size) - { - 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; - + result = evaluate_block_regex_accept (cls, type, query, bf, bf_mutator, + xquery, xquery_size, + reply_block, reply_block_size); + break; default: - return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED; + result = GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED; } + return result; } diff --git a/src/regex/regex_block_lib.c b/src/regex/regex_block_lib.c index deb496fd9..3f7c9473a 100644 --- a/src/regex/regex_block_lib.c +++ b/src/regex/regex_block_lib.c @@ -62,7 +62,9 @@ check_edge (void *cls, struct regex_block_xquery_ctx *ctx = cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " edge %.*s [%u]\n", - (int) len, token, len); + (int) len, token, len); + if (NULL == ctx->xquery) + return GNUNET_YES; if (strlen (ctx->xquery) < len) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " too long!\n"); @@ -82,54 +84,37 @@ check_edge (void *cls, } -/** - * Check if the regex block is well formed, including all edges - * - * @param block The start of the block. - * @param size The size of the block. - * @param xquery String describing the edge we are looking for. - * - * @return GNUNET_OK in case it's fine. - * GNUNET_NO in case the xquery is not found. - * GNUNET_SYSERR if the block is invalid. - */ int GNUNET_REGEX_block_check (const struct RegexBlock *block, - size_t size, - const char *xquery) + size_t size, + const char *xquery) { int res; struct regex_block_xquery_ctx ctx; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "* Checking block with xquery \"%s\"\n", - xquery); - if ( (GNUNET_YES == ntohl(block->accepting)) && ('\0' == xquery[0]) ) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "* Checking block with xquery \"%s\"\n", + NULL != xquery ? xquery : "NULL"); + if ( (GNUNET_YES == ntohl (block->accepting)) && + ( (NULL == xquery) || ('\0' == xquery[0]) ) + ) return GNUNET_OK; ctx.xquery = xquery; ctx.found = GNUNET_NO; res = GNUNET_REGEX_block_iterate (block, size, &check_edge, &ctx); if (GNUNET_SYSERR == res) return GNUNET_SYSERR; + if (NULL == xquery) + return GNUNET_YES; return ctx.found; } -/** - * Iterate over all edges of a block of a regex state. - * - * @param block Block to iterate over. - * @param size Size of block. - * @param iterator Function to call on each edge in the block. - * @param iter_cls Closure for the iterator. - * - * @return How many bytes of block have been processed - */ int GNUNET_REGEX_block_iterate (const struct RegexBlock *block, - size_t size, - GNUNET_REGEX_EgdeIterator iterator, - void *iter_cls) + size_t size, + GNUNET_REGEX_EgdeIterator iterator, + void *iter_cls) { struct RegexEdge *edge; unsigned int n; @@ -142,7 +127,7 @@ GNUNET_REGEX_block_iterate (const struct RegexBlock *block, LOG (GNUNET_ERROR_TYPE_DEBUG, "* Start iterating block of size %u, off %u\n", size, offset); - if (offset > size) // Is it safe to access the regex block? + if (offset >= size) /* Is it safe to access the regex block? */ { LOG (GNUNET_ERROR_TYPE_WARNING, "* Block is smaller than struct RegexBlock, END\n"); @@ -153,22 +138,23 @@ GNUNET_REGEX_block_iterate (const struct RegexBlock *block, offset += n; LOG (GNUNET_ERROR_TYPE_DEBUG, "* Proof length: %u, off %u\n", n, offset); - if (offset > size) // Is it safe to access the regex proof? + if (offset >= size) /* Is it safe to access the regex proof? */ { LOG (GNUNET_ERROR_TYPE_WARNING, "* Block is smaller than Block + proof, END\n"); GNUNET_break_op (0); return GNUNET_SYSERR; } - aux = (char *) &block[1]; // Skip regex block - aux = &aux[n]; // Skip regex proof + aux = (char *) &block[1]; /* Skip regex block */ + aux = &aux[n]; /* Skip regex proof */ n = ntohl (block->n_edges); LOG (GNUNET_ERROR_TYPE_DEBUG, "* Edges: %u\n", n); - for (i = 0; i < n; i++) // aux always points at the end of the previous block + /* aux always points at the end of the previous block */ + for (i = 0; i < n; i++) { offset += sizeof (struct RegexEdge); LOG (GNUNET_ERROR_TYPE_DEBUG, "* Edge %u, off %u\n", i, offset); - if (offset > size) // Is it safe to access the next edge block? + if (offset >= size) /* Is it safe to access the next edge block? */ { LOG (GNUNET_ERROR_TYPE_WARNING, "* Size not enough for RegexEdge, END\n"); @@ -179,23 +165,23 @@ GNUNET_REGEX_block_iterate (const struct RegexBlock *block, n_token = ntohl (edge->n_token); offset += n_token; LOG (GNUNET_ERROR_TYPE_DEBUG, - "* Token lenght %u, off %u\n", n_token, offset); - if (offset > size) // Is it safe to access the edge token? + "* Token length %u, off %u\n", n_token, offset); + if (offset > size) /* Is it safe to access the edge token? */ { LOG (GNUNET_ERROR_TYPE_WARNING, "* Size not enough for edge token, END\n"); GNUNET_break_op (0); return GNUNET_SYSERR; } - aux = (char *) &edge[1]; // Skip edge block + aux = (char *) &edge[1]; /* Skip edge block */ if (NULL != iterator) if (GNUNET_NO == iterator (iter_cls, aux, n_token, &edge->key)) return GNUNET_OK; - aux = &aux[n_token]; // Skip edge token + aux = &aux[n_token]; /* Skip edge token */ } - // The total size should be exactly the size of (regex + all edges) blocks - // If size == -1, block is from cache and therefore previously checked and - // assumed correct. + /* The total size should be exactly the size of (regex + all edges) blocks + * If size == -1, block is from cache and therefore previously checked and + * assumed correct. */ if (offset == size || SIZE_MAX == size) { LOG (GNUNET_ERROR_TYPE_DEBUG, "* Block processed, END OK\n"); diff --git a/src/regex/regex_block_lib.h b/src/regex/regex_block_lib.h index f591f5f61..ca7a2ee22 100644 --- a/src/regex/regex_block_lib.h +++ b/src/regex/regex_block_lib.h @@ -39,14 +39,15 @@ extern "C" #include "block_regex.h" /** - * Check if the regex block is well formed, including all edges + * Check if the regex block is well formed, including all edges. * * @param block The start of the block. * @param size The size of the block. * @param xquery String describing the edge we are looking for. + * Can be NULL in case this is a put block. * * @return GNUNET_OK in case it's fine. - * GNUNET_NO in case the xquery is not found. + * GNUNET_NO in case the xquery exists and is not found (IRRELEVANT). * GNUNET_SYSERR if the block is invalid. */ int @@ -78,7 +79,13 @@ typedef int (*GNUNET_REGEX_EgdeIterator)(void *cls, * @param iterator Function to call on each edge in the block. * @param iter_cls Closure for the iterator. * - * @return GNUNET_SYSERR if an error has been encountered, GNUNET_OK otherwise + * @return GNUNET_SYSERR if an error has been encountered. + * GNUNET_OK if no error has been encountered. + * Note that if the iterator stops the iteration by returning + * GNUNET_NO, the block will no longer be checked for further errors. + * The return value will be GNUNET_OK meaning that no errors were + * found until the edge last notified to the iterator, but there might + * be errors in further edges. */ int GNUNET_REGEX_block_iterate (const struct RegexBlock *block, -- 2.25.1