2 This file is part of GNUnet.
3 (C) 2012,2013 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
21 * @author Bartlomiej Polot
22 * @file regex/regex_block_lib.c
23 * @brief functions for manipulating non-accept blocks stored for
27 #include "regex_block_lib.h"
29 #define LOG(kind,...) GNUNET_log_from (kind,"regex-bck",__VA_ARGS__)
33 * Check if the given 'proof' matches the given 'key'.
35 * @param proof partial regex of a state
36 * @param proof_len number of bytes in 'proof'
37 * @param key hash of a state.
39 * @return GNUNET_OK if the proof is valid for the given key.
42 REGEX_BLOCK_check_proof (const char *proof,
44 const struct GNUNET_HashCode *key)
46 struct GNUNET_HashCode key_check;
48 if ( (NULL == proof) || (NULL == key))
50 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Proof check failed, was NULL.\n");
53 GNUNET_CRYPTO_hash (proof, proof_len, &key_check);
55 GNUNET_CRYPTO_hash_cmp (key, &key_check)) ? GNUNET_OK : GNUNET_NO;
60 * Struct to keep track of the xquery while iterating all the edges in a block.
62 struct CheckEdgeContext
65 * Xquery: string we are looking for.
70 * Has any edge matched the xquery so far? (GNUNET_OK / GNUNET_NO)
78 * Iterator over all edges in a block, checking for a presence of a given query.
80 * @param cls Closure, (xquery context).
81 * @param token Token that follows to next state.
82 * @param len Lenght of token.
83 * @param key Hash of next state.
85 * @return GNUNET_YES, to keep iterating
88 check_edge (void *cls,
91 const struct GNUNET_HashCode *key)
93 struct CheckEdgeContext *ctx = cls;
95 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
96 "edge %.*s [%u]: %s->%s\n",
97 (int) len, token, len, GNUNET_h2s(key));
98 if (NULL == ctx->xquery)
100 if (strlen (ctx->xquery) < len)
101 return GNUNET_YES; /* too long */
102 if (0 == strncmp (ctx->xquery, token, len))
103 ctx->found = GNUNET_OK;
104 return GNUNET_YES; /* keep checking for malformed data! */
109 * Check if the regex block is well formed, including all edges.
111 * @param block The start of the block.
112 * @param size The size of the block.
113 * @param query the query for the block
114 * @param xquery String describing the edge we are looking for.
115 * Can be NULL in case this is a put block.
117 * @return GNUNET_OK in case it's fine.
118 * GNUNET_NO in case the xquery exists and is not found (IRRELEVANT).
119 * GNUNET_SYSERR if the block is invalid.
122 REGEX_BLOCK_check (const struct RegexBlock *block,
124 const struct GNUNET_HashCode *query,
127 struct CheckEdgeContext ctx;
131 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
132 "Checking block with xquery `%s'\n",
133 NULL != xquery ? xquery : "NULL");
134 len = ntohs (block->proof_len);
135 if (size < sizeof (struct RegexBlock) + len)
138 return GNUNET_SYSERR;
140 if (GNUNET_OK != REGEX_BLOCK_check_proof ((const char *) &block[1], len, query))
143 return GNUNET_SYSERR;
145 if ( (GNUNET_YES == ntohs (block->is_accepting)) &&
146 ( (NULL == xquery) || ('\0' == xquery[0]) ) )
149 ctx.found = GNUNET_NO;
150 res = REGEX_BLOCK_iterate (block, size, &check_edge, &ctx);
151 if (GNUNET_SYSERR == res)
152 return GNUNET_SYSERR;
160 * Obtain the key that a particular block is to be stored under.
162 * @param block block to get the key from
163 * @param block_len number of bytes in block
164 * @param query where to store the key
165 * @return GNUNET_OK on success, GNUNET_SYSERR if the block is malformed
168 REGEX_BLOCK_get_key (const struct RegexBlock *block,
170 struct GNUNET_HashCode *key)
174 len = ntohs (block->proof_len);
175 if (block_len < sizeof (struct RegexBlock) + len)
178 return GNUNET_SYSERR;
180 GNUNET_CRYPTO_hash (&block[1], len, key);
186 * Iterate over all edges of a block of a regex state.
188 * @param block Block to iterate over.
189 * @param size Size of block.
190 * @param iterator Function to call on each edge in the block.
191 * @param iter_cls Closure for the iterator.
193 * @return GNUNET_SYSERR if an error has been encountered.
194 * GNUNET_OK if no error has been encountered.
195 * Note that if the iterator stops the iteration by returning
196 * GNUNET_NO, the block will no longer be checked for further errors.
197 * The return value will be GNUNET_OK meaning that no errors were
198 * found until the edge last notified to the iterator, but there might
199 * be errors in further edges.
202 REGEX_BLOCK_iterate (const struct RegexBlock *block,
204 REGEX_INTERNAL_EgdeIterator iterator,
207 struct RegexEdge *edge;
209 unsigned int n_token;
214 offset = sizeof (struct RegexBlock);
215 if (offset >= size) /* Is it safe to access the regex block? */
218 return GNUNET_SYSERR;
220 n = ntohs (block->proof_len);
222 if (offset >= size) /* Is it safe to access the regex proof? */
225 return GNUNET_SYSERR;
227 aux = (char *) &block[1]; /* Skip regex block */
228 aux = &aux[n]; /* Skip regex proof */
229 n = ntohl (block->n_edges);
230 LOG (GNUNET_ERROR_TYPE_DEBUG,
231 "Start iterating block of size %u, proof %u, off %u edges %u\n",
232 size, ntohs (block->proof_len), offset, n);
233 /* aux always points at the end of the previous block */
234 for (i = 0; i < n; i++)
236 offset += sizeof (struct RegexEdge);
237 LOG (GNUNET_ERROR_TYPE_DEBUG, "* Edge %u, off %u\n", i, offset);
238 if (offset >= size) /* Is it safe to access the next edge block? */
240 LOG (GNUNET_ERROR_TYPE_WARNING,
241 "* Size not enough for RegexEdge, END\n");
243 return GNUNET_SYSERR;
245 edge = (struct RegexEdge *) aux;
246 n_token = ntohl (edge->n_token);
248 LOG (GNUNET_ERROR_TYPE_DEBUG,
249 "* Token length %u, off %u\n", n_token, offset);
250 if (offset > size) /* Is it safe to access the edge token? */
252 LOG (GNUNET_ERROR_TYPE_WARNING,
253 "* Size not enough for edge token, END\n");
255 return GNUNET_SYSERR;
257 aux = (char *) &edge[1]; /* Skip edge block */
258 if (NULL != iterator)
259 if (GNUNET_NO == iterator (iter_cls, aux, n_token, &edge->key))
261 aux = &aux[n_token]; /* Skip edge token */
263 /* The total size should be exactly the size of (regex + all edges) blocks
264 * If size == -1, block is from cache and therefore previously checked and
265 * assumed correct. */
266 if ( (offset != size) && (SIZE_MAX != size) )
269 return GNUNET_SYSERR;
276 * Construct a regex block to be stored in the DHT.
278 * @param proof proof string for the block
279 * @param num_edges number of edges in the block
280 * @param edges the edges of the block
281 * @param accepting is this an accepting state
282 * @param rsize set to the size of the returned block (OUT-only)
283 * @return the regex block, NULL on error
286 REGEX_BLOCK_create (const char *proof,
287 unsigned int num_edges,
288 const struct REGEX_BLOCK_Edge *edges,
292 struct RegexBlock *block;
293 struct RegexEdge *block_edge;
300 len = strlen (proof);
301 if (len > UINT16_MAX)
306 size = sizeof (struct RegexBlock) + len;
307 block = GNUNET_malloc (size);
308 block->proof_len = htons (len);
309 block->n_edges = htonl (num_edges);
310 block->is_accepting = htons (accepting);
312 /* Store the proof at the end of the block. */
313 aux = (char *) &block[1];
314 memcpy (aux, proof, len);
317 /* Store each edge in a variable length MeshEdge struct at the
318 * very end of the MeshRegexBlock structure.
320 for (i = 0; i < num_edges; i++)
322 /* aux points at the end of the last block */
323 len = strlen (edges[i].label);
324 size += sizeof (struct RegexEdge) + len;
325 // Calculate offset FIXME is this ok? use size instead?
326 offset = aux - (char *) block;
327 block = GNUNET_realloc (block, size);
328 aux = &((char *) block)[offset];
329 block_edge = (struct RegexEdge *) aux;
330 block_edge->key = edges[i].destination;
331 block_edge->n_token = htonl (len);
332 aux = (char *) &block_edge[1];
333 memcpy (aux, edges[i].label, len);
341 /* end of regex_block_lib.c */