2 This file is part of GNUnet.
3 Copyright (C) 2012,2013 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
16 * @author Bartlomiej Polot
17 * @file regex/regex_block_lib.c
18 * @brief functions for manipulating non-accept blocks stored for
22 #include "regex_block_lib.h"
23 #include "gnunet_constants.h"
25 #define LOG(kind,...) GNUNET_log_from (kind,"regex-bck",__VA_ARGS__)
27 GNUNET_NETWORK_STRUCT_BEGIN
30 * Information for each edge.
35 * Index of the destination of this edge in the
36 * unique destinations array.
38 uint16_t destination_index GNUNET_PACKED;
41 * Number of bytes the token for this edge takes in the
44 uint16_t token_length GNUNET_PACKED;
49 * @brief Block to announce a regex state.
55 * Length of the proof regex string.
57 uint16_t proof_len GNUNET_PACKED;
60 * Is this state an accepting state?
62 int16_t is_accepting GNUNET_PACKED;
65 * Number of edges parting from this state.
67 uint16_t num_edges GNUNET_PACKED;
70 * Nubmer of unique destinations reachable from this state.
72 uint16_t num_destinations GNUNET_PACKED;
74 /* followed by 'struct GNUNET_HashCode[num_destinations]' */
76 /* followed by 'struct EdgeInfo[edge_destination_indices]' */
78 /* followed by 'char proof[n_proof]', NOT 0-terminated */
80 /* followed by 'char tokens[num_edges][edge_info[k].token_length]';
81 essentially all of the tokens one after the other in the
82 order of the edges; tokens are NOT 0-terminated */
87 GNUNET_NETWORK_STRUCT_END
91 * Test if this block is marked as being an accept state.
93 * @param block block to test
94 * @param size number of bytes in block
95 * @return #GNUNET_YES if the block is accepting, #GNUNET_NO if not
98 GNUNET_BLOCK_is_accepting (const struct RegexBlock *block,
101 if (size < sizeof (struct RegexBlock))
104 return GNUNET_SYSERR;
106 return ntohs (block->is_accepting);
111 * Check if the given 'proof' matches the given 'key'.
113 * @param proof partial regex of a state
114 * @param proof_len number of bytes in 'proof'
115 * @param key hash of a state.
116 * @return #GNUNET_OK if the proof is valid for the given key.
119 REGEX_BLOCK_check_proof (const char *proof,
121 const struct GNUNET_HashCode *key)
123 struct GNUNET_HashCode key_check;
125 if ( (NULL == proof) || (NULL == key))
127 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Proof check failed, was NULL.\n");
130 GNUNET_CRYPTO_hash (proof, proof_len, &key_check);
132 GNUNET_CRYPTO_hash_cmp (key, &key_check)) ? GNUNET_OK : GNUNET_NO;
137 * Struct to keep track of the xquery while iterating all the edges in a block.
139 struct CheckEdgeContext
142 * Xquery: string we are looking for.
147 * Has any edge matched the xquery so far? (GNUNET_OK / GNUNET_NO)
155 * Iterator over all edges in a block, checking for a presence of a given query.
157 * @param cls Closure, (xquery context).
158 * @param token Token that follows to next state.
159 * @param len Lenght of token.
160 * @param key Hash of next state.
162 * @return #GNUNET_YES, to keep iterating
165 check_edge (void *cls,
168 const struct GNUNET_HashCode *key)
170 struct CheckEdgeContext *ctx = cls;
172 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
173 "edge %.*s [%u]: %s\n",
178 if (NULL == ctx->xquery)
180 if (strlen (ctx->xquery) < len)
181 return GNUNET_YES; /* too long */
182 if (0 == strncmp (ctx->xquery, token, len))
183 ctx->found = GNUNET_OK;
184 return GNUNET_YES; /* keep checking for malformed data! */
189 * Check if the regex block is well formed, including all edges.
191 * @param block The start of the block.
192 * @param size The size of the block.
193 * @param query the query for the block
194 * @param xquery String describing the edge we are looking for.
195 * Can be NULL in case this is a put block.
196 * @return #GNUNET_OK in case it's fine.
197 * #GNUNET_NO in case the xquery exists and is not found (IRRELEVANT).
198 * #GNUNET_SYSERR if the block is invalid.
201 REGEX_BLOCK_check (const struct RegexBlock *block,
203 const struct GNUNET_HashCode *query,
206 struct GNUNET_HashCode key;
207 struct CheckEdgeContext ctx;
210 LOG (GNUNET_ERROR_TYPE_DEBUG,
213 REGEX_BLOCK_get_key (block, size,
217 return GNUNET_SYSERR;
222 sizeof (struct GNUNET_HashCode)))
225 return GNUNET_SYSERR;
227 if ( (GNUNET_YES == ntohs (block->is_accepting)) &&
228 ( (NULL == xquery) || ('\0' == xquery[0]) ) )
230 LOG (GNUNET_ERROR_TYPE_DEBUG,
231 " out! Is accepting: %u, xquery %p\n",
232 ntohs(block->is_accepting),
237 ctx.found = GNUNET_NO;
238 res = REGEX_BLOCK_iterate (block, size, &check_edge, &ctx);
239 if (GNUNET_SYSERR == res)
240 return GNUNET_SYSERR;
243 LOG (GNUNET_ERROR_TYPE_DEBUG, "Result %d\n", ctx.found);
249 * Obtain the key that a particular block is to be stored under.
251 * @param block block to get the key from
252 * @param block_len number of bytes in block
253 * @param key where to store the key
254 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the block is malformed
257 REGEX_BLOCK_get_key (const struct RegexBlock *block,
259 struct GNUNET_HashCode *key)
262 const struct GNUNET_HashCode *destinations;
263 const struct EdgeInfo *edges;
264 uint16_t num_destinations;
268 if (block_len < sizeof (struct RegexBlock))
271 return GNUNET_SYSERR;
273 num_destinations = ntohs (block->num_destinations);
274 num_edges = ntohs (block->num_edges);
275 len = ntohs (block->proof_len);
276 destinations = (const struct GNUNET_HashCode *) &block[1];
277 edges = (const struct EdgeInfo *) &destinations[num_destinations];
278 total = sizeof (struct RegexBlock) + num_destinations * sizeof (struct GNUNET_HashCode) + num_edges * sizeof (struct EdgeInfo) + len;
279 if (block_len < total)
282 return GNUNET_SYSERR;
284 GNUNET_CRYPTO_hash (&edges[num_edges], len, key);
290 * Iterate over all edges of a block of a regex state.
292 * @param block Block to iterate over.
293 * @param size Size of @a block.
294 * @param iterator Function to call on each edge in the block.
295 * @param iter_cls Closure for the @a iterator.
296 * @return #GNUNET_SYSERR if an error has been encountered.
297 * #GNUNET_OK if no error has been encountered.
298 * Note that if the iterator stops the iteration by returning
299 * #GNUNET_NO, the block will no longer be checked for further errors.
300 * The return value will be GNUNET_OK meaning that no errors were
301 * found until the edge last notified to the iterator, but there might
302 * be errors in further edges.
305 REGEX_BLOCK_iterate (const struct RegexBlock *block,
307 REGEX_INTERNAL_EgdeIterator iterator,
311 const struct GNUNET_HashCode *destinations;
312 const struct EdgeInfo *edges;
314 uint16_t num_destinations;
320 LOG (GNUNET_ERROR_TYPE_DEBUG, "Block iterate\n");
321 if (size < sizeof (struct RegexBlock))
324 return GNUNET_SYSERR;
326 num_destinations = ntohs (block->num_destinations);
327 num_edges = ntohs (block->num_edges);
328 len = ntohs (block->proof_len);
329 destinations = (const struct GNUNET_HashCode *) &block[1];
330 edges = (const struct EdgeInfo *) &destinations[num_destinations];
331 aux = (const char *) &edges[num_edges];
332 total = sizeof (struct RegexBlock) + num_destinations * sizeof (struct GNUNET_HashCode) + num_edges * sizeof (struct EdgeInfo) + len;
336 return GNUNET_SYSERR;
338 for (n=0;n<num_edges;n++)
339 total += ntohs (edges[n].token_length);
342 fprintf (stderr, "Expected %u, got %u\n",
344 (unsigned int) total);
346 return GNUNET_SYSERR;
349 LOG (GNUNET_ERROR_TYPE_DEBUG,
350 "Start iterating block of size %u, proof %u, off %u edges %u\n",
352 /* &aux[off] always points to our token */
353 for (n=0;n<num_edges;n++)
355 LOG (GNUNET_ERROR_TYPE_DEBUG,
356 "Edge %u/%u, off %u tokenlen %u (%.*s)\n",
358 ntohs (edges[n].token_length), ntohs (edges[n].token_length),
360 if (NULL != iterator)
361 if (GNUNET_NO == iterator (iter_cls,
363 ntohs (edges[n].token_length),
364 &destinations[ntohs (edges[n].destination_index)]))
366 off += ntohs (edges[n].token_length);
373 * Construct a regex block to be stored in the DHT.
375 * @param proof proof string for the block
376 * @param num_edges number of edges in the block
377 * @param edges the edges of the block
378 * @param accepting is this an accepting state
379 * @param rsize set to the size of the returned block (OUT-only)
380 * @return the regex block, NULL on error
383 REGEX_BLOCK_create (const char *proof,
384 unsigned int num_edges,
385 const struct REGEX_BLOCK_Edge *edges,
389 struct RegexBlock *block;
390 struct GNUNET_HashCode destinations[1024]; /* 1024 = 64k/64 bytes/key == absolute MAX */
391 uint16_t destination_indices[num_edges];
392 struct GNUNET_HashCode *dests;
393 struct EdgeInfo *edgeinfos;
398 unsigned int unique_destinations;
403 len = strlen (proof);
404 if (len > UINT16_MAX)
409 unique_destinations = 0;
410 total = sizeof (struct RegexBlock) + len;
411 for (i=0;i<num_edges;i++)
413 slen = strlen (edges[i].label);
414 if (slen > UINT16_MAX)
420 for (j=0;j<unique_destinations;j++)
421 if (0 == memcmp (&destinations[j],
422 &edges[i].destination,
423 sizeof (struct GNUNET_HashCode)))
430 destination_indices[i] = j;
431 if (j == unique_destinations)
432 destinations[unique_destinations++] = edges[i].destination;
434 total += num_edges * sizeof (struct EdgeInfo) + unique_destinations * sizeof (struct GNUNET_HashCode);
435 if (total >= GNUNET_CONSTANTS_MAX_BLOCK_SIZE)
440 block = GNUNET_malloc (total);
441 block->proof_len = htons (len);
442 block->is_accepting = htons (accepting);
443 block->num_edges = htons (num_edges);
444 block->num_destinations = htons (unique_destinations);
445 dests = (struct GNUNET_HashCode *) &block[1];
446 GNUNET_memcpy (dests, destinations, sizeof (struct GNUNET_HashCode) * unique_destinations);
447 edgeinfos = (struct EdgeInfo *) &dests[unique_destinations];
448 aux = (char *) &edgeinfos[num_edges];
450 GNUNET_memcpy (aux, proof, len);
451 for (i=0;i<num_edges;i++)
453 slen = strlen (edges[i].label);
454 edgeinfos[i].token_length = htons ((uint16_t) slen);
455 edgeinfos[i].destination_index = htons (destination_indices[i]);
456 GNUNET_memcpy (&aux[off],
466 /* end of regex_block_lib.c */