/**
* @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"
#define LOG(kind,...) GNUNET_log_from (kind,"regex-bck",__VA_ARGS__)
+GNUNET_NETWORK_STRUCT_BEGIN
+
+/**
+ * @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;
+
+ /**
+ * Numer of edges parting from this state.
+ */
+ uint32_t n_edges GNUNET_PACKED;
+
+ /* char proof[n_proof] */
+ /* struct RegexEdge edges[n_edges] */
+};
+
+
+/**
+ * @brief A RegexBlock contains one or more of this struct in the payload.
+ */
+struct RegexEdge
+{
+ /**
+ * Destination of this edge.
+ */
+ struct GNUNET_HashCode key;
+
+ /**
+ * Length of the token towards the new state.
+ */
+ uint32_t n_token GNUNET_PACKED;
+
+ /* char token[n_token] */
+};
+
+
+GNUNET_NETWORK_STRUCT_END
+
+
+/**
+ * Test if this block is marked as being an accept state.
+ *
+ * @param block block to test
+ * @return GNUNET_YES if the block is accepting, GNUNET_NO if not
+ */
+int
+GNUNET_BLOCK_is_accepting (const struct RegexBlock *block)
+{
+ 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.
*/
int found;
- /**
- * Key of the block we are iterating (for debug purposes).
- */
- char *key;
};
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_ITERNAL_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 CheckEdgeContext ctx;
int res;
- struct regex_block_xquery_ctx ctx;
+ uint16_t len;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "* Checking block with xquery \"%s\"\n",
+ "Checking block with xquery `%s'\n",
NULL != xquery ? xquery : "NULL");
- if ( (GNUNET_YES == ntohl (block->accepting)) &&
- ( (NULL == xquery) || ('\0' == xquery[0]) )
- )
+ len = ntohs (block->proof_len);
+ if (size < sizeof (struct RegexBlock) + len)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK != REGEX_BLOCK_check_proof ((const char *) &block[1], len, query))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if ( (GNUNET_YES == ntohs (block->is_accepting)) &&
+ ( (NULL == xquery) || ('\0' == xquery[0]) ) )
return GNUNET_OK;
ctx.xquery = xquery;
ctx.found = GNUNET_NO;
- ctx.key = GNUNET_strdup (GNUNET_h2s (&block->key));
- res = REGEX_ITERNAL_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)
}
+/**
+ * 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 query where to store the key
+ * @return GNUNET_OK on success, GNUNET_SYSERR if the block is malformed
+ */
int
-REGEX_ITERNAL_block_iterate (const struct RegexBlock *block,
- size_t size,
- REGEX_ITERNAL_EgdeIterator iterator,
- void *iter_cls)
+REGEX_BLOCK_get_key (const struct RegexBlock *block,
+ size_t block_len,
+ struct GNUNET_HashCode *key)
+{
+ uint16_t len;
+
+ len = ntohs (block->proof_len);
+ if (block_len < sizeof (struct RegexBlock) + len)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_CRYPTO_hash (&block[1], 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 block.
+ * @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 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_BLOCK_iterate (const struct RegexBlock *block,
+ size_t size,
+ REGEX_INTERNAL_EgdeIterator iterator,
+ void *iter_cls)
{
struct RegexEdge *edge;
unsigned int n;
char *aux;
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_WARNING,
- "* Block is smaller than struct RegexBlock, END\n");
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
- n = ntohl (block->n_proof);
+ n = ntohs (block->proof_len);
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? */
{
- 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);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Start iterating block of size %u, proof %u, off %u edges %u\n",
+ size, ntohs (block->proof_len), offset, n);
/* aux always points at the end of the previous block */
for (i = 0; i < n; i++)
{
/* 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)
+ if ( (offset != size) && (SIZE_MAX != size) )
{
- LOG (GNUNET_ERROR_TYPE_DEBUG, "* Block processed, END OK\n");
- return GNUNET_OK;
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Construct a regex block to be stored in the DHT.
+ *
+ * @param proof proof string for the block
+ * @param num_edges number of edges in the block
+ * @param edges the edges of the block
+ * @param accepting is this an accepting state
+ * @param rsize set to the size of the returned block (OUT-only)
+ * @return the regex block, NULL on error
+ */
+struct RegexBlock *
+REGEX_BLOCK_create (const char *proof,
+ unsigned int num_edges,
+ const struct REGEX_BLOCK_Edge *edges,
+ int accepting,
+ size_t *rsize)
+{
+ struct RegexBlock *block;
+ struct RegexEdge *block_edge;
+ size_t size;
+ size_t len;
+ unsigned int i;
+ unsigned int offset;
+ char *aux;
+
+ len = strlen (proof);
+ if (len > UINT16_MAX)
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+ size = sizeof (struct RegexBlock) + len;
+ block = GNUNET_malloc (size);
+ block->proof_len = htons (len);
+ block->n_edges = htonl (num_edges);
+ block->is_accepting = htons (accepting);
+
+ /* Store the proof at the end of the block. */
+ aux = (char *) &block[1];
+ memcpy (aux, proof, len);
+ aux = &aux[len];
+
+ /* Store each edge in a variable length MeshEdge struct at the
+ * very end of the MeshRegexBlock structure.
+ */
+ for (i = 0; i < num_edges; i++)
+ {
+ /* aux points at the end of the last block */
+ len = strlen (edges[i].label);
+ size += sizeof (struct RegexEdge) + len;
+ // Calculate offset FIXME is this ok? use size instead?
+ offset = aux - (char *) block;
+ block = GNUNET_realloc (block, size);
+ aux = &((char *) block)[offset];
+ block_edge = (struct RegexEdge *) aux;
+ block_edge->key = edges[i].destination;
+ block_edge->n_token = htonl (len);
+ aux = (char *) &block_edge[1];
+ memcpy (aux, edges[i].label, len);
+ aux = &aux[len];
}
- LOG (GNUNET_ERROR_TYPE_WARNING,
- "* Size %u (%d), read %u END KO\n", size, size, offset);
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
+ *rsize = size;
+ return block;
}
+
/* end of regex_block_lib.c */