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"
28 #include "gnunet_constants.h"
30 #define LOG(kind,...) GNUNET_log_from (kind,"regex-bck",__VA_ARGS__)
32 GNUNET_NETWORK_STRUCT_BEGIN
35 * Information for each edge.
40 * Index of the destination of this edge in the
41 * unique destinations array.
43 uint16_t destination_index GNUNET_PACKED;
46 * Number of bytes the token for this edge takes in the
49 uint16_t token_length GNUNET_PACKED;
54 * @brief Block to announce a regex state.
60 * Length of the proof regex string.
62 uint16_t proof_len GNUNET_PACKED;
65 * Is this state an accepting state?
67 int16_t is_accepting GNUNET_PACKED;
70 * Number of edges parting from this state.
72 uint16_t num_edges GNUNET_PACKED;
75 * Nubmer of unique destinations reachable from this state.
77 uint16_t num_destinations GNUNET_PACKED;
79 /* followed by 'struct GNUNET_HashCode[num_destinations]' */
81 /* followed by 'struct EdgeInfo[edge_destination_indices]' */
83 /* followed by 'char proof[n_proof]', NOT 0-terminated */
85 /* followed by 'char tokens[num_edges][edge_info[k].token_length]';
86 essentially all of the tokens one after the other in the
87 order of the edges; tokens are NOT 0-terminated */
92 GNUNET_NETWORK_STRUCT_END
96 * Test if this block is marked as being an accept state.
98 * @param block block to test
99 * @return GNUNET_YES if the block is accepting, GNUNET_NO if not
102 GNUNET_BLOCK_is_accepting (const struct RegexBlock *block)
104 return ntohs (block->is_accepting);
109 * Check if the given 'proof' matches the given 'key'.
111 * @param proof partial regex of a state
112 * @param proof_len number of bytes in 'proof'
113 * @param key hash of a state.
115 * @return GNUNET_OK if the proof is valid for the given key.
118 REGEX_BLOCK_check_proof (const char *proof,
120 const struct GNUNET_HashCode *key)
122 struct GNUNET_HashCode key_check;
124 if ( (NULL == proof) || (NULL == key))
126 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Proof check failed, was NULL.\n");
129 GNUNET_CRYPTO_hash (proof, proof_len, &key_check);
131 GNUNET_CRYPTO_hash_cmp (key, &key_check)) ? GNUNET_OK : GNUNET_NO;
136 * Struct to keep track of the xquery while iterating all the edges in a block.
138 struct CheckEdgeContext
141 * Xquery: string we are looking for.
146 * Has any edge matched the xquery so far? (GNUNET_OK / GNUNET_NO)
154 * Iterator over all edges in a block, checking for a presence of a given query.
156 * @param cls Closure, (xquery context).
157 * @param token Token that follows to next state.
158 * @param len Lenght of token.
159 * @param key Hash of next state.
161 * @return GNUNET_YES, to keep iterating
164 check_edge (void *cls,
167 const struct GNUNET_HashCode *key)
169 struct CheckEdgeContext *ctx = cls;
171 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
172 "edge %.*s [%u]: %s->%s\n",
173 (int) len, token, len, GNUNET_h2s(key));
174 if (NULL == ctx->xquery)
176 if (strlen (ctx->xquery) < len)
177 return GNUNET_YES; /* too long */
178 if (0 == strncmp (ctx->xquery, token, len))
179 ctx->found = GNUNET_OK;
180 return GNUNET_YES; /* keep checking for malformed data! */
185 * Check if the regex block is well formed, including all edges.
187 * @param block The start of the block.
188 * @param size The size of the block.
189 * @param query the query for the block
190 * @param xquery String describing the edge we are looking for.
191 * Can be NULL in case this is a put block.
193 * @return GNUNET_OK in case it's fine.
194 * GNUNET_NO in case the xquery exists and is not found (IRRELEVANT).
195 * GNUNET_SYSERR if the block is invalid.
198 REGEX_BLOCK_check (const struct RegexBlock *block,
200 const struct GNUNET_HashCode *query,
203 struct GNUNET_HashCode key;
204 struct CheckEdgeContext ctx;
208 REGEX_BLOCK_get_key (block, size,
212 return GNUNET_SYSERR;
214 if (0 != memcmp (&key,
216 sizeof (struct GNUNET_HashCode)))
219 return GNUNET_SYSERR;
221 if ( (GNUNET_YES == ntohs (block->is_accepting)) &&
222 ( (NULL == xquery) || ('\0' == xquery[0]) ) )
225 ctx.found = GNUNET_NO;
226 res = REGEX_BLOCK_iterate (block, size, &check_edge, &ctx);
227 if (GNUNET_SYSERR == res)
228 return GNUNET_SYSERR;
236 * Obtain the key that a particular block is to be stored under.
238 * @param block block to get the key from
239 * @param block_len number of bytes in block
240 * @param query where to store the key
241 * @return GNUNET_OK on success, GNUNET_SYSERR if the block is malformed
244 REGEX_BLOCK_get_key (const struct RegexBlock *block,
246 struct GNUNET_HashCode *key)
249 const struct GNUNET_HashCode *destinations;
250 const struct EdgeInfo *edges;
251 uint16_t num_destinations;
255 if (block_len < sizeof (struct RegexBlock))
258 return GNUNET_SYSERR;
260 num_destinations = ntohs (block->num_destinations);
261 num_edges = ntohs (block->num_edges);
262 len = ntohs (block->proof_len);
263 destinations = (const struct GNUNET_HashCode *) &block[1];
264 edges = (const struct EdgeInfo *) &destinations[num_destinations];
265 total = sizeof (struct RegexBlock) + num_destinations * sizeof (struct GNUNET_HashCode) + num_edges + sizeof (struct EdgeInfo) + len;
266 if (block_len < total)
269 return GNUNET_SYSERR;
271 GNUNET_CRYPTO_hash (&edges[num_edges], len, key);
277 * Iterate over all edges of a block of a regex state.
279 * @param block Block to iterate over.
280 * @param size Size of block.
281 * @param iterator Function to call on each edge in the block.
282 * @param iter_cls Closure for the iterator.
284 * @return GNUNET_SYSERR if an error has been encountered.
285 * GNUNET_OK if no error has been encountered.
286 * Note that if the iterator stops the iteration by returning
287 * GNUNET_NO, the block will no longer be checked for further errors.
288 * The return value will be GNUNET_OK meaning that no errors were
289 * found until the edge last notified to the iterator, but there might
290 * be errors in further edges.
293 REGEX_BLOCK_iterate (const struct RegexBlock *block,
295 REGEX_INTERNAL_EgdeIterator iterator,
299 const struct GNUNET_HashCode *destinations;
300 const struct EdgeInfo *edges;
302 uint16_t num_destinations;
308 if (size < sizeof (struct RegexBlock))
311 return GNUNET_SYSERR;
313 num_destinations = ntohs (block->num_destinations);
314 num_edges = ntohs (block->num_edges);
315 len = ntohs (block->proof_len);
316 destinations = (const struct GNUNET_HashCode *) &block[1];
317 edges = (const struct EdgeInfo *) &destinations[num_destinations];
318 aux = (const char *) &edges[num_edges];
319 total = sizeof (struct RegexBlock) + num_destinations * sizeof (struct GNUNET_HashCode) + num_edges + sizeof (struct EdgeInfo) + len;
323 return GNUNET_SYSERR;
325 for (n=0;n<num_edges;n++)
326 total += ntohs (edges[n].token_length);
330 return GNUNET_SYSERR;
333 LOG (GNUNET_ERROR_TYPE_DEBUG,
334 "Start iterating block of size %u, proof %u, off %u edges %u\n",
336 /* &aux[off] always points to our token */
337 for (n=0;n<num_edges;n++)
339 LOG (GNUNET_ERROR_TYPE_DEBUG,
340 "Edge %u, off %u tokenlen %u\n", n, off,
341 ntohs (edges[n].token_length));
342 if (NULL != iterator)
343 if (GNUNET_NO == iterator (iter_cls,
345 ntohs (edges[n].token_length),
346 &destinations[ntohs (edges[n].destination_index)]))
348 off += ntohs (edges[n].token_length);
355 * Construct a regex block to be stored in the DHT.
357 * @param proof proof string for the block
358 * @param num_edges number of edges in the block
359 * @param edges the edges of the block
360 * @param accepting is this an accepting state
361 * @param rsize set to the size of the returned block (OUT-only)
362 * @return the regex block, NULL on error
365 REGEX_BLOCK_create (const char *proof,
366 unsigned int num_edges,
367 const struct REGEX_BLOCK_Edge *edges,
371 struct RegexBlock *block;
372 struct GNUNET_HashCode destinations[1024]; /* 1024 = 64k/64 bytes/key == absolute MAX */
373 uint16_t destination_indices[num_edges];
374 struct GNUNET_HashCode *dests;
375 struct EdgeInfo *edgeinfos;
380 unsigned int unique_destinations;
385 len = strlen (proof);
386 if (len > UINT16_MAX)
391 unique_destinations = 0;
392 total = sizeof (struct RegexBlock) + len;
393 for (i=0;i<num_edges;i++)
395 slen = strlen (edges[i].label);
396 if (len > UINT16_MAX)
402 for (j=0;j<unique_destinations;j++)
403 if (0 == memcmp (&destinations[j],
404 &edges[i].destination,
405 sizeof (struct GNUNET_HashCode)))
412 destination_indices[i] = j;
413 if (j == unique_destinations)
414 destinations[unique_destinations++] = edges[i].destination;
416 total += num_edges * sizeof (struct EdgeInfo) + unique_destinations * sizeof (struct GNUNET_HashCode);
417 if (total >= GNUNET_CONSTANTS_MAX_BLOCK_SIZE)
422 block = GNUNET_malloc (total);
423 block->proof_len = htons (len);
424 block->is_accepting = htons (accepting);
425 block->num_edges = htons (num_edges);
426 block->num_destinations = htons (unique_destinations);
427 dests = (struct GNUNET_HashCode *) &block[1];
428 memcpy (dests, destinations, sizeof (struct GNUNET_HashCode) * unique_destinations);
429 edgeinfos = (struct EdgeInfo *) &dests[unique_destinations];
430 aux = (char *) &edgeinfos[num_edges];
432 memcpy (aux, proof, len);
433 for (i=0;i<num_edges;i++)
435 slen = strlen (edges[i].label);
436 edgeinfos[i].token_length = htons ((uint16_t) slen);
437 edgeinfos[i].destination_index = htons (destination_indices[i]);
448 /* end of regex_block_lib.c */