aboutsummaryrefslogtreecommitdiff
path: root/src/regex/regex_internal_dht.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/regex/regex_internal_dht.c')
-rw-r--r--src/regex/regex_internal_dht.c835
1 files changed, 0 insertions, 835 deletions
diff --git a/src/regex/regex_internal_dht.c b/src/regex/regex_internal_dht.c
deleted file mode 100644
index e578fba2c..000000000
--- a/src/regex/regex_internal_dht.c
+++ /dev/null
@@ -1,835 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2012, 2015 GNUnet e.V.
4
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.
9
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.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file src/regex/regex_internal_dht.c
22 * @brief library to announce regexes in the network and match strings
23 * against published regexes.
24 * @author Bartlomiej Polot
25 */
26#include "platform.h"
27#include "regex_internal_lib.h"
28#include "regex_block_lib.h"
29#include "gnunet_dht_service.h"
30#include "gnunet_statistics_service.h"
31#include "gnunet_constants.h"
32#include "gnunet_signatures.h"
33
34
35#define LOG(kind, ...) GNUNET_log_from (kind, "regex-dht", __VA_ARGS__)
36
37/**
38 * DHT replication level to use.
39 */
40#define DHT_REPLICATION 5
41
42/**
43 * DHT record lifetime to use.
44 */
45#define DHT_TTL GNUNET_TIME_UNIT_HOURS
46
47/**
48 * DHT options to set.
49 */
50#define DHT_OPT GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE
51
52
53/**
54 * Handle to store cached data about a regex announce.
55 */
56struct REGEX_INTERNAL_Announcement
57{
58 /**
59 * DHT handle to use, must be initialized externally.
60 */
61 struct GNUNET_DHT_Handle *dht;
62
63 /**
64 * Regular expression.
65 */
66 const char *regex;
67
68 /**
69 * Automaton representation of the regex (expensive to build).
70 */
71 struct REGEX_INTERNAL_Automaton *dfa;
72
73 /**
74 * Our private key.
75 */
76 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
77
78 /**
79 * Optional statistics handle to report usage. Can be NULL.
80 */
81 struct GNUNET_STATISTICS_Handle *stats;
82};
83
84
85/**
86 * Regex callback iterator to store own service description in the DHT.
87 *
88 * @param cls closure.
89 * @param key hash for current state.
90 * @param proof proof for current state.
91 * @param accepting #GNUNET_YES if this is an accepting state, #GNUNET_NO if not.
92 * @param num_edges number of edges leaving current state.
93 * @param edges edges leaving current state.
94 */
95static void
96regex_iterator (void *cls,
97 const struct GNUNET_HashCode *key,
98 const char *proof,
99 int accepting,
100 unsigned int num_edges,
101 const struct REGEX_BLOCK_Edge *edges)
102{
103 struct REGEX_INTERNAL_Announcement *h = cls;
104 struct RegexBlock *block;
105 size_t size;
106 unsigned int i;
107
108 LOG (GNUNET_ERROR_TYPE_INFO,
109 "DHT PUT for state %s with proof `%s' and %u edges:\n",
110 GNUNET_h2s (key),
111 proof,
112 num_edges);
113 for (i = 0; i < num_edges; i++)
114 {
115 LOG (GNUNET_ERROR_TYPE_INFO,
116 "Edge %u `%s' towards %s\n",
117 i,
118 edges[i].label,
119 GNUNET_h2s (&edges[i].destination));
120 }
121 if (GNUNET_YES == accepting)
122 {
123 struct RegexAcceptBlock ab;
124
125 LOG (GNUNET_ERROR_TYPE_INFO,
126 "State %s is accepting, putting own id\n",
127 GNUNET_h2s (key));
128 size = sizeof(struct RegexAcceptBlock);
129 ab.purpose.size = ntohl (sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose)
130 + sizeof(struct GNUNET_TIME_AbsoluteNBO)
131 + sizeof(struct GNUNET_HashCode));
132 ab.purpose.purpose = ntohl (GNUNET_SIGNATURE_PURPOSE_REGEX_ACCEPT);
133 ab.expiration_time = GNUNET_TIME_absolute_hton (
134 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_DHT_MAX_EXPIRATION));
135 ab.key = *key;
136 GNUNET_CRYPTO_eddsa_key_get_public (h->priv,
137 &ab.peer.public_key);
138 GNUNET_assert (GNUNET_OK ==
139 GNUNET_CRYPTO_eddsa_sign_ (h->priv,
140 &ab.purpose,
141 &ab.signature));
142
143 GNUNET_STATISTICS_update (h->stats, "# regex accepting blocks stored",
144 1, GNUNET_NO);
145 GNUNET_STATISTICS_update (h->stats, "# regex accepting block bytes stored",
146 sizeof(struct RegexAcceptBlock), GNUNET_NO);
147 (void)
148 GNUNET_DHT_put (h->dht, key,
149 DHT_REPLICATION,
150 DHT_OPT | GNUNET_DHT_RO_RECORD_ROUTE,
151 GNUNET_BLOCK_TYPE_REGEX_ACCEPT,
152 size,
153 &ab,
154 GNUNET_TIME_relative_to_absolute (DHT_TTL),
155 NULL, NULL);
156 }
157 block = REGEX_BLOCK_create (proof,
158 num_edges,
159 edges,
160 accepting,
161 &size);
162 if (NULL == block)
163 return;
164 (void) GNUNET_DHT_put (h->dht,
165 key,
166 DHT_REPLICATION,
167 DHT_OPT,
168 GNUNET_BLOCK_TYPE_REGEX,
169 size,
170 block,
171 GNUNET_TIME_relative_to_absolute (DHT_TTL),
172 NULL,
173 NULL);
174 GNUNET_STATISTICS_update (h->stats,
175 "# regex blocks stored",
176 1,
177 GNUNET_NO);
178 GNUNET_STATISTICS_update (h->stats,
179 "# regex block bytes stored",
180 size,
181 GNUNET_NO);
182 GNUNET_free (block);
183}
184
185
186/**
187 * Announce a regular expression: put all states of the automaton in the DHT.
188 * Does not free resources, must call #REGEX_INTERNAL_announce_cancel() for that.
189 *
190 * @param dht An existing and valid DHT service handle. CANNOT be NULL.
191 * @param priv our private key, must remain valid until the announcement is cancelled
192 * @param regex Regular expression to announce.
193 * @param compression How many characters per edge can we squeeze?
194 * @param stats Optional statistics handle to report usage. Can be NULL.
195 * @return Handle to reuse o free cached resources.
196 * Must be freed by calling #REGEX_INTERNAL_announce_cancel().
197 */
198struct REGEX_INTERNAL_Announcement *
199REGEX_INTERNAL_announce (struct GNUNET_DHT_Handle *dht,
200 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
201 const char *regex,
202 uint16_t compression,
203 struct GNUNET_STATISTICS_Handle *stats)
204{
205 struct REGEX_INTERNAL_Announcement *h;
206
207 GNUNET_assert (NULL != dht);
208 h = GNUNET_new (struct REGEX_INTERNAL_Announcement);
209 h->regex = regex;
210 h->dht = dht;
211 h->stats = stats;
212 h->priv = priv;
213 h->dfa = REGEX_INTERNAL_construct_dfa (regex, strlen (regex), compression);
214 REGEX_INTERNAL_reannounce (h);
215 return h;
216}
217
218
219/**
220 * Announce again a regular expression previously announced.
221 * Does use caching to speed up process.
222 *
223 * @param h Handle returned by a previous #REGEX_INTERNAL_announce call().
224 */
225void
226REGEX_INTERNAL_reannounce (struct REGEX_INTERNAL_Announcement *h)
227{
228 GNUNET_assert (NULL != h->dfa); /* make sure to call announce first */
229 LOG (GNUNET_ERROR_TYPE_INFO,
230 "REGEX_INTERNAL_reannounce: %s\n",
231 h->regex);
232 REGEX_INTERNAL_iterate_reachable_edges (h->dfa,
233 &regex_iterator,
234 h);
235}
236
237
238/**
239 * Clear all cached data used by a regex announce.
240 * Does not close DHT connection.
241 *
242 * @param h Handle returned by a previous #REGEX_INTERNAL_announce() call.
243 */
244void
245REGEX_INTERNAL_announce_cancel (struct REGEX_INTERNAL_Announcement *h)
246{
247 REGEX_INTERNAL_automaton_destroy (h->dfa);
248 GNUNET_free (h);
249}
250
251
252/******************************************************************************/
253
254
255/**
256 * Struct to keep state of running searches that have consumed a part of
257 * the initial string.
258 */
259struct RegexSearchContext
260{
261 /**
262 * Part of the description already consumed by
263 * this particular search branch.
264 */
265 size_t position;
266
267 /**
268 * Information about the search.
269 */
270 struct REGEX_INTERNAL_Search *info;
271
272 /**
273 * We just want to look for one edge, the longer the better.
274 * Keep its length.
275 */
276 unsigned int longest_match;
277
278 /**
279 * Destination hash of the longest match.
280 */
281 struct GNUNET_HashCode hash;
282};
283
284
285/**
286 * Type of values in `dht_get_results`.
287 */
288struct Result
289{
290 /**
291 * Number of bytes in data.
292 */
293 size_t size;
294
295 /**
296 * The raw result data.
297 */
298 const void *data;
299};
300
301
302/**
303 * Struct to keep information of searches of services described by a regex
304 * using a user-provided string service description.
305 */
306struct REGEX_INTERNAL_Search
307{
308 /**
309 * DHT handle to use, must be initialized externally.
310 */
311 struct GNUNET_DHT_Handle *dht;
312
313 /**
314 * Optional statistics handle to report usage. Can be NULL.
315 */
316 struct GNUNET_STATISTICS_Handle *stats;
317
318 /**
319 * User provided description of the searched service.
320 */
321 char *description;
322
323 /**
324 * Running DHT GETs.
325 */
326 struct GNUNET_CONTAINER_MultiHashMap *dht_get_handles;
327
328 /**
329 * Results from running DHT GETs, values are of type
330 * 'struct Result'.
331 */
332 struct GNUNET_CONTAINER_MultiHashMap *dht_get_results;
333
334 /**
335 * Contexts, for each running DHT GET. Free all on end of search.
336 */
337 struct RegexSearchContext **contexts;
338
339 /**
340 * Number of contexts (branches/steps in search).
341 */
342 unsigned int n_contexts;
343
344 /**
345 * @param callback Callback for found peers.
346 */
347 REGEX_INTERNAL_Found callback;
348
349 /**
350 * @param callback_cls Closure for @c callback.
351 */
352 void *callback_cls;
353};
354
355
356/**
357 * Jump to the next edge, with the longest matching token.
358 *
359 * @param block Block found in the DHT.
360 * @param size Size of the block.
361 * @param ctx Context of the search.
362 */
363static void
364regex_next_edge (const struct RegexBlock *block,
365 size_t size,
366 struct RegexSearchContext *ctx);
367
368
369/**
370 * Function to process DHT string to regex matching.
371 * Called on each result obtained for the DHT search.
372 *
373 * @param cls Closure (search context).
374 * @param exp When will this value expire.
375 * @param trunc_peer truncated peer, or NULL if none was truncated
376 * @param key Key of the result.
377 * @param get_path Path of the get request.
378 * @param get_path_length Length of get_path.
379 * @param put_path Path of the put request.
380 * @param put_path_length Length of the put_path.
381 * @param type Type of the result.
382 * @param size Number of bytes in data.
383 * @param data Pointer to the result data.
384 */
385static void
386dht_get_string_accept_handler (void *cls, struct GNUNET_TIME_Absolute exp,
387 const struct GNUNET_HashCode *key,
388 const struct GNUNET_PeerIdentity *trunc_peer,
389 const struct GNUNET_DHT_PathElement *get_path,
390 unsigned int get_path_length,
391 const struct GNUNET_DHT_PathElement *put_path,
392 unsigned int put_path_length,
393 enum GNUNET_BLOCK_Type type,
394 size_t size, const void *data)
395{
396 const struct RegexAcceptBlock *block = data;
397 struct RegexSearchContext *ctx = cls;
398 struct REGEX_INTERNAL_Search *info = ctx->info;
399
400 LOG (GNUNET_ERROR_TYPE_DEBUG,
401 "Regex result accept for %s (key %s)\n",
402 info->description, GNUNET_h2s (key));
403
404 GNUNET_STATISTICS_update (info->stats,
405 "# regex accepting blocks found",
406 1, GNUNET_NO);
407 GNUNET_STATISTICS_update (info->stats,
408 "# regex accepting block bytes found",
409 size, GNUNET_NO);
410 info->callback (info->callback_cls,
411 &block->peer,
412 get_path, get_path_length,
413 put_path, put_path_length);
414}
415
416
417/**
418 * Find a path to a peer that offers a regex service compatible
419 * with a given string.
420 *
421 * @param key The key of the accepting state.
422 * @param ctx Context containing info about the string, tunnel, etc.
423 */
424static void
425regex_find_path (const struct GNUNET_HashCode *key,
426 struct RegexSearchContext *ctx)
427{
428 struct GNUNET_DHT_GetHandle *get_h;
429
430 LOG (GNUNET_ERROR_TYPE_DEBUG,
431 "Accept state found, now searching for paths to %s\n",
432 GNUNET_h2s (key));
433 get_h = GNUNET_DHT_get_start (ctx->info->dht, /* handle */
434 GNUNET_BLOCK_TYPE_REGEX_ACCEPT, /* type */
435 key, /* key to search */
436 DHT_REPLICATION, /* replication level */
437 DHT_OPT | GNUNET_DHT_RO_RECORD_ROUTE,
438 NULL, /* xquery */ // FIXME BLOOMFILTER
439 0, /* xquery bits */ // FIXME BLOOMFILTER SIZE
440 &dht_get_string_accept_handler, ctx);
441 GNUNET_break (GNUNET_OK ==
442 GNUNET_CONTAINER_multihashmap_put (ctx->info->dht_get_handles,
443 key,
444 get_h,
445 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
446}
447
448
449/**
450 * Function to process DHT string to regex matching.
451 * Called on each result obtained for the DHT search.
452 *
453 * @param cls closure (search context)
454 * @param exp when will this value expire
455 * @param key key of the result
456 * @param trunc_peer NULL if not truncated
457 * @param get_path path of the get request (not used)
458 * @param get_path_length length of @a get_path (not used)
459 * @param put_path path of the put request (not used)
460 * @param put_path_length length of the @a put_path (not used)
461 * @param type type of the result
462 * @param size number of bytes in data
463 * @param data pointer to the result data
464 *
465 * TODO: re-issue the request after certain time? cancel after X results?
466 */
467static void
468dht_get_string_handler (void *cls, struct GNUNET_TIME_Absolute exp,
469 const struct GNUNET_HashCode *key,
470 const struct GNUNET_PeerIdentity *trunc_peer,
471 const struct GNUNET_DHT_PathElement *get_path,
472 unsigned int get_path_length,
473 const struct GNUNET_DHT_PathElement *put_path,
474 unsigned int put_path_length,
475 enum GNUNET_BLOCK_Type type,
476 size_t size, const void *data)
477{
478 const struct RegexBlock *block = data;
479 struct RegexSearchContext *ctx = cls;
480 struct REGEX_INTERNAL_Search *info = ctx->info;
481 size_t len;
482 struct Result *copy;
483
484 LOG (GNUNET_ERROR_TYPE_INFO,
485 "DHT GET result for %s (%s)\n",
486 GNUNET_h2s (key), ctx->info->description);
487 copy = GNUNET_malloc (sizeof(struct Result) + size);
488 copy->size = size;
489 copy->data = &copy[1];
490 GNUNET_memcpy (&copy[1], block, size);
491 GNUNET_break (GNUNET_OK ==
492 GNUNET_CONTAINER_multihashmap_put (info->dht_get_results,
493 key, copy,
494 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
495 len = strlen (info->description);
496 if (len == ctx->position) // String processed
497 {
498 if (GNUNET_YES == GNUNET_BLOCK_is_accepting (block, size))
499 {
500 regex_find_path (key, ctx);
501 }
502 else
503 {
504 LOG (GNUNET_ERROR_TYPE_INFO, "block not accepting!\n");
505 /* FIXME REGEX this block not successful, wait for more? start timeout? */
506 }
507 return;
508 }
509 regex_next_edge (block, size, ctx);
510}
511
512
513/**
514 * Iterator over found existing cadet regex blocks that match an ongoing search.
515 *
516 * @param cls Closure (current context)-
517 * @param key Current key code (key for cached block).
518 * @param value Value in the hash map (cached RegexBlock).
519 * @return #GNUNET_YES: we should always continue to iterate.
520 */
521static int
522regex_result_iterator (void *cls,
523 const struct GNUNET_HashCode *key,
524 void *value)
525{
526 struct Result *result = value;
527 const struct RegexBlock *block = result->data;
528 struct RegexSearchContext *ctx = cls;
529
530 if ((GNUNET_YES ==
531 GNUNET_BLOCK_is_accepting (block, result->size)) &&
532 (ctx->position == strlen (ctx->info->description)))
533 {
534 LOG (GNUNET_ERROR_TYPE_INFO,
535 "Found accepting known block\n");
536 regex_find_path (key, ctx);
537 return GNUNET_YES; // We found an accept state!
538 }
539 LOG (GNUNET_ERROR_TYPE_DEBUG,
540 "* %lu, %lu, [%u]\n",
541 (unsigned long) ctx->position,
542 strlen (ctx->info->description),
543 GNUNET_BLOCK_is_accepting (block, result->size));
544 regex_next_edge (block, result->size, ctx);
545
546 GNUNET_STATISTICS_update (ctx->info->stats, "# regex cadet blocks iterated",
547 1, GNUNET_NO);
548
549 return GNUNET_YES;
550}
551
552
553/**
554 * Iterator over edges in a regex block retrieved from the DHT.
555 *
556 * @param cls Closure (context of the search).
557 * @param token Token that follows to next state.
558 * @param len Length of token.
559 * @param key Hash of next state.
560 * @return #GNUNET_YES if should keep iterating, #GNUNET_NO otherwise.
561 */
562static int
563regex_edge_iterator (void *cls,
564 const char *token,
565 size_t len,
566 const struct GNUNET_HashCode *key)
567{
568 struct RegexSearchContext *ctx = cls;
569 struct REGEX_INTERNAL_Search *info = ctx->info;
570 const char *current;
571 size_t current_len;
572
573 GNUNET_STATISTICS_update (info->stats, "# regex edges iterated",
574 1, GNUNET_NO);
575 current = &info->description[ctx->position];
576 current_len = strlen (info->description) - ctx->position;
577 if (len > current_len)
578 {
579 LOG (GNUNET_ERROR_TYPE_DEBUG, "Token too long, END\n");
580 return GNUNET_YES;
581 }
582 if (0 != strncmp (current, token, len))
583 {
584 LOG (GNUNET_ERROR_TYPE_DEBUG, "Token doesn't match, END\n");
585 return GNUNET_YES;
586 }
587
588 if (len > ctx->longest_match)
589 {
590 LOG (GNUNET_ERROR_TYPE_DEBUG, "Token is longer, KEEP\n");
591 ctx->longest_match = len;
592 ctx->hash = *key;
593 }
594 else
595 {
596 LOG (GNUNET_ERROR_TYPE_DEBUG, "Token is not longer, IGNORE\n");
597 }
598
599 LOG (GNUNET_ERROR_TYPE_DEBUG, "* End of regex edge iterator\n");
600 return GNUNET_YES;
601}
602
603
604/**
605 * Jump to the next edge, with the longest matching token.
606 *
607 * @param block Block found in the DHT.
608 * @param size Size of the block.
609 * @param ctx Context of the search.
610 */
611static void
612regex_next_edge (const struct RegexBlock *block,
613 size_t size,
614 struct RegexSearchContext *ctx)
615{
616 struct RegexSearchContext *new_ctx;
617 struct REGEX_INTERNAL_Search *info = ctx->info;
618 struct GNUNET_DHT_GetHandle *get_h;
619 struct GNUNET_HashCode *hash;
620 const char *rest;
621 int result;
622
623 LOG (GNUNET_ERROR_TYPE_DEBUG, "Next edge\n");
624 /* Find the longest match for the current string position,
625 * among tokens in the given block */
626 ctx->longest_match = 0;
627 result = REGEX_BLOCK_iterate (block, size,
628 &regex_edge_iterator, ctx);
629 GNUNET_break (GNUNET_OK == result);
630
631 /* Did anything match? */
632 if (0 == ctx->longest_match)
633 {
634 LOG (GNUNET_ERROR_TYPE_DEBUG,
635 "no match in block\n");
636 return;
637 }
638
639 hash = &ctx->hash;
640 new_ctx = GNUNET_new (struct RegexSearchContext);
641 new_ctx->info = info;
642 new_ctx->position = ctx->position + ctx->longest_match;
643 GNUNET_array_append (info->contexts, info->n_contexts, new_ctx);
644
645 /* Check whether we already have a DHT GET running for it */
646 if (GNUNET_YES ==
647 GNUNET_CONTAINER_multihashmap_contains (info->dht_get_handles, hash))
648 {
649 LOG (GNUNET_ERROR_TYPE_DEBUG,
650 "GET for %s running, END\n",
651 GNUNET_h2s (hash));
652 GNUNET_CONTAINER_multihashmap_get_multiple (info->dht_get_results,
653 hash,
654 &regex_result_iterator,
655 new_ctx);
656 return; /* We are already looking for it */
657 }
658
659 GNUNET_STATISTICS_update (info->stats, "# regex nodes traversed",
660 1, GNUNET_NO);
661
662 LOG (GNUNET_ERROR_TYPE_DEBUG,
663 "Following edges at %s for offset %u in `%s'\n",
664 GNUNET_h2s (hash),
665 (unsigned int) ctx->position,
666 info->description);
667 rest = &new_ctx->info->description[new_ctx->position];
668 get_h =
669 GNUNET_DHT_get_start (info->dht, /* handle */
670 GNUNET_BLOCK_TYPE_REGEX, /* type */
671 hash, /* key to search */
672 DHT_REPLICATION, /* replication level */
673 DHT_OPT,
674 rest, /* xquery */
675 strlen (rest) + 1, /* xquery bits */
676 &dht_get_string_handler, new_ctx);
677 if (GNUNET_OK !=
678 GNUNET_CONTAINER_multihashmap_put (info->dht_get_handles,
679 hash,
680 get_h,
681 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
682 {
683 GNUNET_break (0);
684 return;
685 }
686}
687
688
689/**
690 * Search for a peer offering a regex matching certain string in the DHT.
691 * The search runs until #REGEX_INTERNAL_search_cancel() is called, even if results
692 * are returned.
693 *
694 * @param dht An existing and valid DHT service handle.
695 * @param string String to match against the regexes in the DHT.
696 * @param callback Callback for found peers.
697 * @param callback_cls Closure for @c callback.
698 * @param stats Optional statistics handle to report usage. Can be NULL.
699 * @return Handle to stop search and free resources.
700 * Must be freed by calling #REGEX_INTERNAL_search_cancel().
701 */
702struct REGEX_INTERNAL_Search *
703REGEX_INTERNAL_search (struct GNUNET_DHT_Handle *dht,
704 const char *string,
705 REGEX_INTERNAL_Found callback,
706 void *callback_cls,
707 struct GNUNET_STATISTICS_Handle *stats)
708{
709 struct REGEX_INTERNAL_Search *h;
710 struct GNUNET_DHT_GetHandle *get_h;
711 struct RegexSearchContext *ctx;
712 struct GNUNET_HashCode key;
713 size_t size;
714 size_t len;
715
716 /* Initialize handle */
717 GNUNET_assert (NULL != dht);
718 GNUNET_assert (NULL != callback);
719 h = GNUNET_new (struct REGEX_INTERNAL_Search);
720 h->dht = dht;
721 h->description = GNUNET_strdup (string);
722 h->callback = callback;
723 h->callback_cls = callback_cls;
724 h->stats = stats;
725 h->dht_get_handles = GNUNET_CONTAINER_multihashmap_create (32, GNUNET_NO);
726 h->dht_get_results = GNUNET_CONTAINER_multihashmap_create (32, GNUNET_NO);
727
728 /* Initialize context */
729 len = strlen (string);
730 size = REGEX_INTERNAL_get_first_key (string, len, &key);
731 LOG (GNUNET_ERROR_TYPE_INFO,
732 "Initial key for `%s' is %s (based on `%.*s')\n",
733 string,
734 GNUNET_h2s (&key),
735 (int) size,
736 string);
737 ctx = GNUNET_new (struct RegexSearchContext);
738 ctx->position = size;
739 ctx->info = h;
740 GNUNET_array_append (h->contexts,
741 h->n_contexts,
742 ctx);
743 /* Start search in DHT */
744 get_h = GNUNET_DHT_get_start (h->dht, /* handle */
745 GNUNET_BLOCK_TYPE_REGEX, /* type */
746 &key, /* key to search */
747 DHT_REPLICATION, /* replication level */
748 DHT_OPT,
749 &h->description[size], /* xquery */
750 // FIXME add BLOOMFILTER to exclude filtered peers
751 len + 1 - size, /* xquery bits */
752 // FIXME add BLOOMFILTER SIZE
753 &dht_get_string_handler, ctx);
754 GNUNET_break (
755 GNUNET_OK ==
756 GNUNET_CONTAINER_multihashmap_put (h->dht_get_handles,
757 &key,
758 get_h,
759 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)
760 );
761
762 return h;
763}
764
765
766/**
767 * Iterator over hash map entries to cancel DHT GET requests after a
768 * successful connect_by_string.
769 *
770 * @param cls Closure (unused).
771 * @param key Current key code (unused).
772 * @param value Value in the hash map (get handle).
773 * @return #GNUNET_YES if we should continue to iterate,
774 * #GNUNET_NO if not.
775 */
776static int
777regex_cancel_dht_get (void *cls,
778 const struct GNUNET_HashCode *key,
779 void *value)
780{
781 struct GNUNET_DHT_GetHandle *h = value;
782
783 GNUNET_DHT_get_stop (h);
784 return GNUNET_YES;
785}
786
787
788/**
789 * Iterator over hash map entries to free CadetRegexBlocks stored during the
790 * search for connect_by_string.
791 *
792 * @param cls Closure (unused).
793 * @param key Current key code (unused).
794 * @param value CadetRegexBlock in the hash map.
795 * @return #GNUNET_YES if we should continue to iterate,
796 * #GNUNET_NO if not.
797 */
798static int
799regex_free_result (void *cls,
800 const struct GNUNET_HashCode *key,
801 void *value)
802{
803 GNUNET_free (value);
804 return GNUNET_YES;
805}
806
807
808/**
809 * Cancel an ongoing regex search in the DHT and free all resources.
810 *
811 * @param h the search context.
812 */
813void
814REGEX_INTERNAL_search_cancel (struct REGEX_INTERNAL_Search *h)
815{
816 unsigned int i;
817
818 GNUNET_free (h->description);
819 GNUNET_CONTAINER_multihashmap_iterate (h->dht_get_handles,
820 &regex_cancel_dht_get, NULL);
821 GNUNET_CONTAINER_multihashmap_iterate (h->dht_get_results,
822 &regex_free_result, NULL);
823 GNUNET_CONTAINER_multihashmap_destroy (h->dht_get_results);
824 GNUNET_CONTAINER_multihashmap_destroy (h->dht_get_handles);
825 if (0 < h->n_contexts)
826 {
827 for (i = 0; i < h->n_contexts; i++)
828 GNUNET_free (h->contexts[i]);
829 GNUNET_free (h->contexts);
830 }
831 GNUNET_free (h);
832}
833
834
835/* end of regex_internal_dht.c */