X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fregex%2Fregex_block_lib.c;h=782827d5db0424782f393d9557293fe01f3410d8;hb=f1ca38573f22205e28ac482efebe463696c9c2c7;hp=63b673fbe8607ab7ebe59793a0c822935ffbd3cf;hpb=566b7539fcaf9c455da665cb641016d2cfbb1b47;p=oweals%2Fgnunet.git diff --git a/src/regex/regex_block_lib.c b/src/regex/regex_block_lib.c index 63b673fbe..782827d5d 100644 --- a/src/regex/regex_block_lib.c +++ b/src/regex/regex_block_lib.c @@ -20,16 +20,128 @@ /** * @author Bartlomiej Polot * @file regex/regex_block_lib.c + * @brief functions for manipulating non-accept blocks stored for + * regex in the DHT */ #include "platform.h" #include "regex_block_lib.h" +#include "gnunet_constants.h" #define LOG(kind,...) GNUNET_log_from (kind,"regex-bck",__VA_ARGS__) +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Information for each edge. + */ +struct EdgeInfo +{ + /** + * Index of the destination of this edge in the + * unique destinations array. + */ + uint16_t destination_index GNUNET_PACKED; + + /** + * Number of bytes the token for this edge takes in the + * token area. + */ + uint16_t token_length GNUNET_PACKED; +}; + + +/** + * @brief Block to announce a regex state. + */ +struct RegexBlock +{ + + /** + * Length of the proof regex string. + */ + uint16_t proof_len GNUNET_PACKED; + + /** + * Is this state an accepting state? + */ + int16_t is_accepting GNUNET_PACKED; + + /** + * Number of edges parting from this state. + */ + uint16_t num_edges GNUNET_PACKED; + + /** + * Nubmer of unique destinations reachable from this state. + */ + uint16_t num_destinations GNUNET_PACKED; + + /* followed by 'struct GNUNET_HashCode[num_destinations]' */ + + /* followed by 'struct EdgeInfo[edge_destination_indices]' */ + + /* followed by 'char proof[n_proof]', NOT 0-terminated */ + + /* followed by 'char tokens[num_edges][edge_info[k].token_length]'; + essentially all of the tokens one after the other in the + order of the edges; tokens are NOT 0-terminated */ + +}; + + +GNUNET_NETWORK_STRUCT_END + + +/** + * Test if this block is marked as being an accept state. + * + * @param block block to test + * @param size number of bytes in block + * @return #GNUNET_YES if the block is accepting, #GNUNET_NO if not + */ +int +GNUNET_BLOCK_is_accepting (const struct RegexBlock *block, + size_t size) +{ + if (size < sizeof (struct RegexBlock)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + return ntohs (block->is_accepting); +} + + +/** + * Check if the given 'proof' matches the given 'key'. + * + * @param proof partial regex of a state + * @param proof_len number of bytes in 'proof' + * @param key hash of a state. + * @return #GNUNET_OK if the proof is valid for the given key. + */ +int +REGEX_BLOCK_check_proof (const char *proof, + size_t proof_len, + const struct GNUNET_HashCode *key) +{ + struct GNUNET_HashCode key_check; + + if ( (NULL == proof) || (NULL == key)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Proof check failed, was NULL.\n"); + return GNUNET_NO; + } + GNUNET_CRYPTO_hash (proof, proof_len, &key_check); + return (0 == + GNUNET_CRYPTO_hash_cmp (key, &key_check)) ? GNUNET_OK : GNUNET_NO; +} + + /** * Struct to keep track of the xquery while iterating all the edges in a block. */ -struct regex_block_xquery_ctx +struct CheckEdgeContext { /** * Xquery: string we are looking for. @@ -41,10 +153,6 @@ struct regex_block_xquery_ctx */ int found; - /** - * Key of the block we are iterating (for debug purposes). - */ - char *key; }; @@ -55,7 +163,7 @@ struct regex_block_xquery_ctx * @param token Token that follows to next state. * @param len Lenght of token. * @param key Hash of next state. - * + * * @return GNUNET_YES, to keep iterating */ static int @@ -64,142 +172,295 @@ check_edge (void *cls, size_t len, const struct GNUNET_HashCode *key) { - struct regex_block_xquery_ctx *ctx = cls; - - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " edge %.*s [%u]: %s->%s\n", - (int) len, token, len, ctx->key, GNUNET_h2s(key)); + struct CheckEdgeContext *ctx = cls; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "edge %.*s [%u]: %s->%s\n", + (int) len, token, len, GNUNET_h2s(key)); if (NULL == ctx->xquery) return GNUNET_YES; if (strlen (ctx->xquery) < len) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " too long!\n"); - return GNUNET_YES; - } + return GNUNET_YES; /* too long */ if (0 == strncmp (ctx->xquery, token, len)) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " OK!\n"); ctx->found = GNUNET_OK; - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " KO!\n"); - } - return GNUNET_YES; /* keep checking for malformed data! */ } +/** + * 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 query the query for 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 exists and is not found (IRRELEVANT). + * #GNUNET_SYSERR if the block is invalid. + */ int -REGEX_INTERNAL_block_check (const struct RegexBlock *block, - size_t size, - const char *xquery) +REGEX_BLOCK_check (const struct RegexBlock *block, + size_t size, + const struct GNUNET_HashCode *query, + const char *xquery) { + struct GNUNET_HashCode key; + struct CheckEdgeContext ctx; int res; - struct regex_block_xquery_ctx ctx; - 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]) ) - ) + LOG (GNUNET_ERROR_TYPE_DEBUG, "Block check\n"); + if (GNUNET_OK != + REGEX_BLOCK_get_key (block, size, + &key)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (NULL != query && + 0 != memcmp (&key, + query, + sizeof (struct GNUNET_HashCode))) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if ( (GNUNET_YES == ntohs (block->is_accepting)) && + ( (NULL == xquery) || ('\0' == xquery[0]) ) ) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + " out! Is accepting: %u, xquery %p\n", + ntohs(block->is_accepting), xquery); return GNUNET_OK; + } ctx.xquery = xquery; ctx.found = GNUNET_NO; - ctx.key = GNUNET_strdup (GNUNET_h2s (&block->key)); - res = REGEX_INTERNAL_block_iterate (block, size, &check_edge, &ctx); - GNUNET_free (ctx.key); + res = REGEX_BLOCK_iterate (block, size, &check_edge, &ctx); if (GNUNET_SYSERR == res) return GNUNET_SYSERR; if (NULL == xquery) return GNUNET_YES; + LOG (GNUNET_ERROR_TYPE_DEBUG, "Result %d\n", ctx.found); return ctx.found; } +/** + * Obtain the key that a particular block is to be stored under. + * + * @param block block to get the key from + * @param block_len number of bytes in block + * @param key where to store the key + * @return #GNUNET_OK on success, #GNUNET_SYSERR if the block is malformed + */ +int +REGEX_BLOCK_get_key (const struct RegexBlock *block, + size_t block_len, + struct GNUNET_HashCode *key) +{ + uint16_t len; + const struct GNUNET_HashCode *destinations; + const struct EdgeInfo *edges; + uint16_t num_destinations; + uint16_t num_edges; + size_t total; + + if (block_len < sizeof (struct RegexBlock)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + num_destinations = ntohs (block->num_destinations); + num_edges = ntohs (block->num_edges); + len = ntohs (block->proof_len); + destinations = (const struct GNUNET_HashCode *) &block[1]; + edges = (const struct EdgeInfo *) &destinations[num_destinations]; + total = sizeof (struct RegexBlock) + num_destinations * sizeof (struct GNUNET_HashCode) + num_edges * sizeof (struct EdgeInfo) + len; + if (block_len < total) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + GNUNET_CRYPTO_hash (&edges[num_edges], len, key); + return GNUNET_OK; +} + + +/** + * Iterate over all edges of a block of a regex state. + * + * @param block Block to iterate over. + * @param size Size of @a block. + * @param iterator Function to call on each edge in the block. + * @param iter_cls Closure for the @a iterator. + * @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 -REGEX_INTERNAL_block_iterate (const struct RegexBlock *block, - size_t size, - REGEX_INTERNAL_EgdeIterator iterator, - void *iter_cls) +REGEX_BLOCK_iterate (const struct RegexBlock *block, + size_t size, + REGEX_INTERNAL_EgdeIterator iterator, + void *iter_cls) { - struct RegexEdge *edge; + uint16_t len; + const struct GNUNET_HashCode *destinations; + const struct EdgeInfo *edges; + const char *aux; + uint16_t num_destinations; + uint16_t num_edges; + size_t total; unsigned int n; - unsigned int n_token; - unsigned int i; - size_t offset; - char *aux; + size_t off; - offset = sizeof (struct RegexBlock); - 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? */ + LOG (GNUNET_ERROR_TYPE_DEBUG, "Block iterate\n"); + if (size < sizeof (struct RegexBlock)) { - LOG (GNUNET_ERROR_TYPE_WARNING, - "* Block is smaller than struct RegexBlock, END\n"); GNUNET_break_op (0); return GNUNET_SYSERR; } - n = ntohl (block->n_proof); - 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? */ + num_destinations = ntohs (block->num_destinations); + num_edges = ntohs (block->num_edges); + len = ntohs (block->proof_len); + destinations = (const struct GNUNET_HashCode *) &block[1]; + edges = (const struct EdgeInfo *) &destinations[num_destinations]; + aux = (const char *) &edges[num_edges]; + total = sizeof (struct RegexBlock) + num_destinations * sizeof (struct GNUNET_HashCode) + num_edges * sizeof (struct EdgeInfo) + len; + if (size < total) { - 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 */ - n = ntohl (block->n_edges); - LOG (GNUNET_ERROR_TYPE_DEBUG, "* Edges: %u\n", n); - /* aux always points at the end of the previous block */ - for (i = 0; i < n; i++) + for (n=0;n UINT16_MAX) + { + GNUNET_break (0); + return NULL; + } + unique_destinations = 0; + total = sizeof (struct RegexBlock) + len; + for (i=0;i= size) /* Is it safe to access the next edge block? */ + slen = strlen (edges[i].label); + if (slen > UINT16_MAX) { - LOG (GNUNET_ERROR_TYPE_WARNING, - "* Size not enough for RegexEdge, END\n"); - GNUNET_break_op (0); - return GNUNET_SYSERR; + GNUNET_break (0); + return NULL; } - edge = (struct RegexEdge *) aux; - n_token = ntohl (edge->n_token); - offset += n_token; - LOG (GNUNET_ERROR_TYPE_DEBUG, - "* Token length %u, off %u\n", n_token, offset); - if (offset > size) /* Is it safe to access the edge token? */ + total += slen; + for (j=0;j= 1024) { - LOG (GNUNET_ERROR_TYPE_WARNING, - "* Size not enough for edge token, END\n"); - GNUNET_break_op (0); - return GNUNET_SYSERR; + GNUNET_break (0); + return NULL; } - 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 */ + destination_indices[i] = j; + if (j == unique_destinations) + destinations[unique_destinations++] = edges[i].destination; } - /* 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) + total += num_edges * sizeof (struct EdgeInfo) + unique_destinations * sizeof (struct GNUNET_HashCode); + if (total >= GNUNET_CONSTANTS_MAX_BLOCK_SIZE) { - LOG (GNUNET_ERROR_TYPE_DEBUG, "* Block processed, END OK\n"); - return GNUNET_OK; + GNUNET_break (0); + return NULL; + } + block = GNUNET_malloc (total); + block->proof_len = htons (len); + block->is_accepting = htons (accepting); + block->num_edges = htons (num_edges); + block->num_destinations = htons (unique_destinations); + dests = (struct GNUNET_HashCode *) &block[1]; + memcpy (dests, destinations, sizeof (struct GNUNET_HashCode) * unique_destinations); + edgeinfos = (struct EdgeInfo *) &dests[unique_destinations]; + aux = (char *) &edgeinfos[num_edges]; + off = len; + memcpy (aux, proof, len); + for (i=0;i