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.c831
1 files changed, 0 insertions, 831 deletions
diff --git a/src/regex/regex_internal_dht.c b/src/regex/regex_internal_dht.c
deleted file mode 100644
index 2248de1f1..000000000
--- a/src/regex/regex_internal_dht.c
+++ /dev/null
@@ -1,831 +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 key Key of the result.
376 * @param get_path Path of the get request.
377 * @param get_path_length Length of get_path.
378 * @param put_path Path of the put request.
379 * @param put_path_length Length of the put_path.
380 * @param type Type of the result.
381 * @param size Number of bytes in data.
382 * @param data Pointer to the result data.
383 */
384static void
385dht_get_string_accept_handler (void *cls, struct GNUNET_TIME_Absolute exp,
386 const struct GNUNET_HashCode *key,
387 const struct GNUNET_DHT_PathElement *get_path,
388 unsigned int get_path_length,
389 const struct GNUNET_DHT_PathElement *put_path,
390 unsigned int put_path_length,
391 enum GNUNET_BLOCK_Type type,
392 size_t size, const void *data)
393{
394 const struct RegexAcceptBlock *block = data;
395 struct RegexSearchContext *ctx = cls;
396 struct REGEX_INTERNAL_Search *info = ctx->info;
397
398 LOG (GNUNET_ERROR_TYPE_DEBUG,
399 "Regex result accept for %s (key %s)\n",
400 info->description, GNUNET_h2s (key));
401
402 GNUNET_STATISTICS_update (info->stats,
403 "# regex accepting blocks found",
404 1, GNUNET_NO);
405 GNUNET_STATISTICS_update (info->stats,
406 "# regex accepting block bytes found",
407 size, GNUNET_NO);
408 info->callback (info->callback_cls,
409 &block->peer,
410 get_path, get_path_length,
411 put_path, put_path_length);
412}
413
414
415/**
416 * Find a path to a peer that offers a regex service compatible
417 * with a given string.
418 *
419 * @param key The key of the accepting state.
420 * @param ctx Context containing info about the string, tunnel, etc.
421 */
422static void
423regex_find_path (const struct GNUNET_HashCode *key,
424 struct RegexSearchContext *ctx)
425{
426 struct GNUNET_DHT_GetHandle *get_h;
427
428 LOG (GNUNET_ERROR_TYPE_DEBUG,
429 "Accept state found, now searching for paths to %s\n",
430 GNUNET_h2s (key));
431 get_h = GNUNET_DHT_get_start (ctx->info->dht, /* handle */
432 GNUNET_BLOCK_TYPE_REGEX_ACCEPT, /* type */
433 key, /* key to search */
434 DHT_REPLICATION, /* replication level */
435 DHT_OPT | GNUNET_DHT_RO_RECORD_ROUTE,
436 NULL, /* xquery */ // FIXME BLOOMFILTER
437 0, /* xquery bits */ // FIXME BLOOMFILTER SIZE
438 &dht_get_string_accept_handler, ctx);
439 GNUNET_break (GNUNET_OK ==
440 GNUNET_CONTAINER_multihashmap_put (ctx->info->dht_get_handles,
441 key,
442 get_h,
443 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
444}
445
446
447/**
448 * Function to process DHT string to regex matching.
449 * Called on each result obtained for the DHT search.
450 *
451 * @param cls closure (search context)
452 * @param exp when will this value expire
453 * @param key key of the result
454 * @param get_path path of the get request (not used)
455 * @param get_path_length length of @a get_path (not used)
456 * @param put_path path of the put request (not used)
457 * @param put_path_length length of the @a put_path (not used)
458 * @param type type of the result
459 * @param size number of bytes in data
460 * @param data pointer to the result data
461 *
462 * TODO: re-issue the request after certain time? cancel after X results?
463 */
464static void
465dht_get_string_handler (void *cls, struct GNUNET_TIME_Absolute exp,
466 const struct GNUNET_HashCode *key,
467 const struct GNUNET_DHT_PathElement *get_path,
468 unsigned int get_path_length,
469 const struct GNUNET_DHT_PathElement *put_path,
470 unsigned int put_path_length,
471 enum GNUNET_BLOCK_Type type,
472 size_t size, const void *data)
473{
474 const struct RegexBlock *block = data;
475 struct RegexSearchContext *ctx = cls;
476 struct REGEX_INTERNAL_Search *info = ctx->info;
477 size_t len;
478 struct Result *copy;
479
480 LOG (GNUNET_ERROR_TYPE_INFO,
481 "DHT GET result for %s (%s)\n",
482 GNUNET_h2s (key), ctx->info->description);
483 copy = GNUNET_malloc (sizeof(struct Result) + size);
484 copy->size = size;
485 copy->data = &copy[1];
486 GNUNET_memcpy (&copy[1], block, size);
487 GNUNET_break (GNUNET_OK ==
488 GNUNET_CONTAINER_multihashmap_put (info->dht_get_results,
489 key, copy,
490 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
491 len = strlen (info->description);
492 if (len == ctx->position) // String processed
493 {
494 if (GNUNET_YES == GNUNET_BLOCK_is_accepting (block, size))
495 {
496 regex_find_path (key, ctx);
497 }
498 else
499 {
500 LOG (GNUNET_ERROR_TYPE_INFO, "block not accepting!\n");
501 /* FIXME REGEX this block not successful, wait for more? start timeout? */
502 }
503 return;
504 }
505 regex_next_edge (block, size, ctx);
506}
507
508
509/**
510 * Iterator over found existing cadet regex blocks that match an ongoing search.
511 *
512 * @param cls Closure (current context)-
513 * @param key Current key code (key for cached block).
514 * @param value Value in the hash map (cached RegexBlock).
515 * @return #GNUNET_YES: we should always continue to iterate.
516 */
517static int
518regex_result_iterator (void *cls,
519 const struct GNUNET_HashCode *key,
520 void *value)
521{
522 struct Result *result = value;
523 const struct RegexBlock *block = result->data;
524 struct RegexSearchContext *ctx = cls;
525
526 if ((GNUNET_YES ==
527 GNUNET_BLOCK_is_accepting (block, result->size)) &&
528 (ctx->position == strlen (ctx->info->description)))
529 {
530 LOG (GNUNET_ERROR_TYPE_INFO,
531 "Found accepting known block\n");
532 regex_find_path (key, ctx);
533 return GNUNET_YES; // We found an accept state!
534 }
535 LOG (GNUNET_ERROR_TYPE_DEBUG,
536 "* %lu, %lu, [%u]\n",
537 (unsigned long) ctx->position,
538 strlen (ctx->info->description),
539 GNUNET_BLOCK_is_accepting (block, result->size));
540 regex_next_edge (block, result->size, ctx);
541
542 GNUNET_STATISTICS_update (ctx->info->stats, "# regex cadet blocks iterated",
543 1, GNUNET_NO);
544
545 return GNUNET_YES;
546}
547
548
549/**
550 * Iterator over edges in a regex block retrieved from the DHT.
551 *
552 * @param cls Closure (context of the search).
553 * @param token Token that follows to next state.
554 * @param len Length of token.
555 * @param key Hash of next state.
556 * @return #GNUNET_YES if should keep iterating, #GNUNET_NO otherwise.
557 */
558static int
559regex_edge_iterator (void *cls,
560 const char *token,
561 size_t len,
562 const struct GNUNET_HashCode *key)
563{
564 struct RegexSearchContext *ctx = cls;
565 struct REGEX_INTERNAL_Search *info = ctx->info;
566 const char *current;
567 size_t current_len;
568
569 GNUNET_STATISTICS_update (info->stats, "# regex edges iterated",
570 1, GNUNET_NO);
571 current = &info->description[ctx->position];
572 current_len = strlen (info->description) - ctx->position;
573 if (len > current_len)
574 {
575 LOG (GNUNET_ERROR_TYPE_DEBUG, "Token too long, END\n");
576 return GNUNET_YES;
577 }
578 if (0 != strncmp (current, token, len))
579 {
580 LOG (GNUNET_ERROR_TYPE_DEBUG, "Token doesn't match, END\n");
581 return GNUNET_YES;
582 }
583
584 if (len > ctx->longest_match)
585 {
586 LOG (GNUNET_ERROR_TYPE_DEBUG, "Token is longer, KEEP\n");
587 ctx->longest_match = len;
588 ctx->hash = *key;
589 }
590 else
591 {
592 LOG (GNUNET_ERROR_TYPE_DEBUG, "Token is not longer, IGNORE\n");
593 }
594
595 LOG (GNUNET_ERROR_TYPE_DEBUG, "* End of regex edge iterator\n");
596 return GNUNET_YES;
597}
598
599
600/**
601 * Jump to the next edge, with the longest matching token.
602 *
603 * @param block Block found in the DHT.
604 * @param size Size of the block.
605 * @param ctx Context of the search.
606 */
607static void
608regex_next_edge (const struct RegexBlock *block,
609 size_t size,
610 struct RegexSearchContext *ctx)
611{
612 struct RegexSearchContext *new_ctx;
613 struct REGEX_INTERNAL_Search *info = ctx->info;
614 struct GNUNET_DHT_GetHandle *get_h;
615 struct GNUNET_HashCode *hash;
616 const char *rest;
617 int result;
618
619 LOG (GNUNET_ERROR_TYPE_DEBUG, "Next edge\n");
620 /* Find the longest match for the current string position,
621 * among tokens in the given block */
622 ctx->longest_match = 0;
623 result = REGEX_BLOCK_iterate (block, size,
624 &regex_edge_iterator, ctx);
625 GNUNET_break (GNUNET_OK == result);
626
627 /* Did anything match? */
628 if (0 == ctx->longest_match)
629 {
630 LOG (GNUNET_ERROR_TYPE_DEBUG,
631 "no match in block\n");
632 return;
633 }
634
635 hash = &ctx->hash;
636 new_ctx = GNUNET_new (struct RegexSearchContext);
637 new_ctx->info = info;
638 new_ctx->position = ctx->position + ctx->longest_match;
639 GNUNET_array_append (info->contexts, info->n_contexts, new_ctx);
640
641 /* Check whether we already have a DHT GET running for it */
642 if (GNUNET_YES ==
643 GNUNET_CONTAINER_multihashmap_contains (info->dht_get_handles, hash))
644 {
645 LOG (GNUNET_ERROR_TYPE_DEBUG,
646 "GET for %s running, END\n",
647 GNUNET_h2s (hash));
648 GNUNET_CONTAINER_multihashmap_get_multiple (info->dht_get_results,
649 hash,
650 &regex_result_iterator,
651 new_ctx);
652 return; /* We are already looking for it */
653 }
654
655 GNUNET_STATISTICS_update (info->stats, "# regex nodes traversed",
656 1, GNUNET_NO);
657
658 LOG (GNUNET_ERROR_TYPE_DEBUG,
659 "Following edges at %s for offset %u in `%s'\n",
660 GNUNET_h2s (hash),
661 (unsigned int) ctx->position,
662 info->description);
663 rest = &new_ctx->info->description[new_ctx->position];
664 get_h =
665 GNUNET_DHT_get_start (info->dht, /* handle */
666 GNUNET_BLOCK_TYPE_REGEX, /* type */
667 hash, /* key to search */
668 DHT_REPLICATION, /* replication level */
669 DHT_OPT,
670 rest, /* xquery */
671 strlen (rest) + 1, /* xquery bits */
672 &dht_get_string_handler, new_ctx);
673 if (GNUNET_OK !=
674 GNUNET_CONTAINER_multihashmap_put (info->dht_get_handles,
675 hash,
676 get_h,
677 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
678 {
679 GNUNET_break (0);
680 return;
681 }
682}
683
684
685/**
686 * Search for a peer offering a regex matching certain string in the DHT.
687 * The search runs until #REGEX_INTERNAL_search_cancel() is called, even if results
688 * are returned.
689 *
690 * @param dht An existing and valid DHT service handle.
691 * @param string String to match against the regexes in the DHT.
692 * @param callback Callback for found peers.
693 * @param callback_cls Closure for @c callback.
694 * @param stats Optional statistics handle to report usage. Can be NULL.
695 * @return Handle to stop search and free resources.
696 * Must be freed by calling #REGEX_INTERNAL_search_cancel().
697 */
698struct REGEX_INTERNAL_Search *
699REGEX_INTERNAL_search (struct GNUNET_DHT_Handle *dht,
700 const char *string,
701 REGEX_INTERNAL_Found callback,
702 void *callback_cls,
703 struct GNUNET_STATISTICS_Handle *stats)
704{
705 struct REGEX_INTERNAL_Search *h;
706 struct GNUNET_DHT_GetHandle *get_h;
707 struct RegexSearchContext *ctx;
708 struct GNUNET_HashCode key;
709 size_t size;
710 size_t len;
711
712 /* Initialize handle */
713 GNUNET_assert (NULL != dht);
714 GNUNET_assert (NULL != callback);
715 h = GNUNET_new (struct REGEX_INTERNAL_Search);
716 h->dht = dht;
717 h->description = GNUNET_strdup (string);
718 h->callback = callback;
719 h->callback_cls = callback_cls;
720 h->stats = stats;
721 h->dht_get_handles = GNUNET_CONTAINER_multihashmap_create (32, GNUNET_NO);
722 h->dht_get_results = GNUNET_CONTAINER_multihashmap_create (32, GNUNET_NO);
723
724 /* Initialize context */
725 len = strlen (string);
726 size = REGEX_INTERNAL_get_first_key (string, len, &key);
727 LOG (GNUNET_ERROR_TYPE_INFO,
728 "Initial key for `%s' is %s (based on `%.*s')\n",
729 string,
730 GNUNET_h2s (&key),
731 (int) size,
732 string);
733 ctx = GNUNET_new (struct RegexSearchContext);
734 ctx->position = size;
735 ctx->info = h;
736 GNUNET_array_append (h->contexts,
737 h->n_contexts,
738 ctx);
739 /* Start search in DHT */
740 get_h = GNUNET_DHT_get_start (h->dht, /* handle */
741 GNUNET_BLOCK_TYPE_REGEX, /* type */
742 &key, /* key to search */
743 DHT_REPLICATION, /* replication level */
744 DHT_OPT,
745 &h->description[size], /* xquery */
746 // FIXME add BLOOMFILTER to exclude filtered peers
747 len + 1 - size, /* xquery bits */
748 // FIXME add BLOOMFILTER SIZE
749 &dht_get_string_handler, ctx);
750 GNUNET_break (
751 GNUNET_OK ==
752 GNUNET_CONTAINER_multihashmap_put (h->dht_get_handles,
753 &key,
754 get_h,
755 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)
756 );
757
758 return h;
759}
760
761
762/**
763 * Iterator over hash map entries to cancel DHT GET requests after a
764 * successful connect_by_string.
765 *
766 * @param cls Closure (unused).
767 * @param key Current key code (unused).
768 * @param value Value in the hash map (get handle).
769 * @return #GNUNET_YES if we should continue to iterate,
770 * #GNUNET_NO if not.
771 */
772static int
773regex_cancel_dht_get (void *cls,
774 const struct GNUNET_HashCode *key,
775 void *value)
776{
777 struct GNUNET_DHT_GetHandle *h = value;
778
779 GNUNET_DHT_get_stop (h);
780 return GNUNET_YES;
781}
782
783
784/**
785 * Iterator over hash map entries to free CadetRegexBlocks stored during the
786 * search for connect_by_string.
787 *
788 * @param cls Closure (unused).
789 * @param key Current key code (unused).
790 * @param value CadetRegexBlock in the hash map.
791 * @return #GNUNET_YES if we should continue to iterate,
792 * #GNUNET_NO if not.
793 */
794static int
795regex_free_result (void *cls,
796 const struct GNUNET_HashCode *key,
797 void *value)
798{
799 GNUNET_free (value);
800 return GNUNET_YES;
801}
802
803
804/**
805 * Cancel an ongoing regex search in the DHT and free all resources.
806 *
807 * @param h the search context.
808 */
809void
810REGEX_INTERNAL_search_cancel (struct REGEX_INTERNAL_Search *h)
811{
812 unsigned int i;
813
814 GNUNET_free (h->description);
815 GNUNET_CONTAINER_multihashmap_iterate (h->dht_get_handles,
816 &regex_cancel_dht_get, NULL);
817 GNUNET_CONTAINER_multihashmap_iterate (h->dht_get_results,
818 &regex_free_result, NULL);
819 GNUNET_CONTAINER_multihashmap_destroy (h->dht_get_results);
820 GNUNET_CONTAINER_multihashmap_destroy (h->dht_get_handles);
821 if (0 < h->n_contexts)
822 {
823 for (i = 0; i < h->n_contexts; i++)
824 GNUNET_free (h->contexts[i]);
825 GNUNET_free (h->contexts);
826 }
827 GNUNET_free (h);
828}
829
830
831/* end of regex_internal_dht.c */