aboutsummaryrefslogtreecommitdiff
path: root/src/regex/regex_internal_dht.c
diff options
context:
space:
mode:
authorMartin Schanzenbach <schanzen@gnunet.org>2023-10-19 09:03:33 +0200
committerMartin Schanzenbach <schanzen@gnunet.org>2023-10-19 09:03:33 +0200
commit7f72b05249f6ac663cee7a033f3cac5d9400ede7 (patch)
treed15cec717aa9568adc1876ec1b717cf18596e1f6 /src/regex/regex_internal_dht.c
parent5ae8ee063302cc6c1fc7b74328af46a11cb02cdc (diff)
downloadgnunet-7f72b05249f6ac663cee7a033f3cac5d9400ede7.tar.gz
gnunet-7f72b05249f6ac663cee7a033f3cac5d9400ede7.zip
BUILD: Move regex/dns to service
Diffstat (limited to 'src/regex/regex_internal_dht.c')
-rw-r--r--src/regex/regex_internal_dht.c829
1 files changed, 0 insertions, 829 deletions
diff --git a/src/regex/regex_internal_dht.c b/src/regex/regex_internal_dht.c
deleted file mode 100644
index bda979edb..000000000
--- a/src/regex/regex_internal_dht.c
+++ /dev/null
@@ -1,829 +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
219void
220REGEX_INTERNAL_reannounce (struct REGEX_INTERNAL_Announcement *h)
221{
222 GNUNET_assert (NULL != h->dfa); /* make sure to call announce first */
223 LOG (GNUNET_ERROR_TYPE_INFO,
224 "REGEX_INTERNAL_reannounce: %s\n",
225 h->regex);
226 REGEX_INTERNAL_iterate_reachable_edges (h->dfa,
227 &regex_iterator,
228 h);
229}
230
231
232/**
233 * Clear all cached data used by a regex announce.
234 * Does not close DHT connection.
235 *
236 * @param h Handle returned by a previous #REGEX_INTERNAL_announce() call.
237 */
238void
239REGEX_INTERNAL_announce_cancel (struct REGEX_INTERNAL_Announcement *h)
240{
241 REGEX_INTERNAL_automaton_destroy (h->dfa);
242 GNUNET_free (h);
243}
244
245
246/******************************************************************************/
247
248
249/**
250 * Struct to keep state of running searches that have consumed a part of
251 * the initial string.
252 */
253struct RegexSearchContext
254{
255 /**
256 * Part of the description already consumed by
257 * this particular search branch.
258 */
259 size_t position;
260
261 /**
262 * Information about the search.
263 */
264 struct REGEX_INTERNAL_Search *info;
265
266 /**
267 * We just want to look for one edge, the longer the better.
268 * Keep its length.
269 */
270 unsigned int longest_match;
271
272 /**
273 * Destination hash of the longest match.
274 */
275 struct GNUNET_HashCode hash;
276};
277
278
279/**
280 * Type of values in `dht_get_results`.
281 */
282struct Result
283{
284 /**
285 * Number of bytes in data.
286 */
287 size_t size;
288
289 /**
290 * The raw result data.
291 */
292 const void *data;
293};
294
295
296/**
297 * Struct to keep information of searches of services described by a regex
298 * using a user-provided string service description.
299 */
300struct REGEX_INTERNAL_Search
301{
302 /**
303 * DHT handle to use, must be initialized externally.
304 */
305 struct GNUNET_DHT_Handle *dht;
306
307 /**
308 * Optional statistics handle to report usage. Can be NULL.
309 */
310 struct GNUNET_STATISTICS_Handle *stats;
311
312 /**
313 * User provided description of the searched service.
314 */
315 char *description;
316
317 /**
318 * Running DHT GETs.
319 */
320 struct GNUNET_CONTAINER_MultiHashMap *dht_get_handles;
321
322 /**
323 * Results from running DHT GETs, values are of type
324 * 'struct Result'.
325 */
326 struct GNUNET_CONTAINER_MultiHashMap *dht_get_results;
327
328 /**
329 * Contexts, for each running DHT GET. Free all on end of search.
330 */
331 struct RegexSearchContext **contexts;
332
333 /**
334 * Number of contexts (branches/steps in search).
335 */
336 unsigned int n_contexts;
337
338 /**
339 * @param callback Callback for found peers.
340 */
341 REGEX_INTERNAL_Found callback;
342
343 /**
344 * @param callback_cls Closure for @c callback.
345 */
346 void *callback_cls;
347};
348
349
350/**
351 * Jump to the next edge, with the longest matching token.
352 *
353 * @param block Block found in the DHT.
354 * @param size Size of the block.
355 * @param ctx Context of the search.
356 */
357static void
358regex_next_edge (const struct RegexBlock *block,
359 size_t size,
360 struct RegexSearchContext *ctx);
361
362
363/**
364 * Function to process DHT string to regex matching.
365 * Called on each result obtained for the DHT search.
366 *
367 * @param cls Closure (search context).
368 * @param exp When will this value expire.
369 * @param trunc_peer truncated peer, or NULL if none was truncated
370 * @param key Key of the result.
371 * @param get_path Path of the get request.
372 * @param get_path_length Length of get_path.
373 * @param put_path Path of the put request.
374 * @param put_path_length Length of the put_path.
375 * @param type Type of the result.
376 * @param size Number of bytes in data.
377 * @param data Pointer to the result data.
378 */
379static void
380dht_get_string_accept_handler (void *cls, struct GNUNET_TIME_Absolute exp,
381 const struct GNUNET_HashCode *key,
382 const struct GNUNET_PeerIdentity *trunc_peer,
383 const struct GNUNET_DHT_PathElement *get_path,
384 unsigned int get_path_length,
385 const struct GNUNET_DHT_PathElement *put_path,
386 unsigned int put_path_length,
387 enum GNUNET_BLOCK_Type type,
388 size_t size, const void *data)
389{
390 const struct RegexAcceptBlock *block = data;
391 struct RegexSearchContext *ctx = cls;
392 struct REGEX_INTERNAL_Search *info = ctx->info;
393
394 LOG (GNUNET_ERROR_TYPE_DEBUG,
395 "Regex result accept for %s (key %s)\n",
396 info->description, GNUNET_h2s (key));
397
398 GNUNET_STATISTICS_update (info->stats,
399 "# regex accepting blocks found",
400 1, GNUNET_NO);
401 GNUNET_STATISTICS_update (info->stats,
402 "# regex accepting block bytes found",
403 size, GNUNET_NO);
404 info->callback (info->callback_cls,
405 &block->peer,
406 get_path, get_path_length,
407 put_path, put_path_length);
408}
409
410
411/**
412 * Find a path to a peer that offers a regex service compatible
413 * with a given string.
414 *
415 * @param key The key of the accepting state.
416 * @param ctx Context containing info about the string, tunnel, etc.
417 */
418static void
419regex_find_path (const struct GNUNET_HashCode *key,
420 struct RegexSearchContext *ctx)
421{
422 struct GNUNET_DHT_GetHandle *get_h;
423
424 LOG (GNUNET_ERROR_TYPE_DEBUG,
425 "Accept state found, now searching for paths to %s\n",
426 GNUNET_h2s (key));
427 get_h = GNUNET_DHT_get_start (ctx->info->dht, /* handle */
428 GNUNET_BLOCK_TYPE_REGEX_ACCEPT, /* type */
429 key, /* key to search */
430 DHT_REPLICATION, /* replication level */
431 DHT_OPT | GNUNET_DHT_RO_RECORD_ROUTE,
432 NULL, /* xquery */ // FIXME BLOOMFILTER
433 0, /* xquery bits */ // FIXME BLOOMFILTER SIZE
434 &dht_get_string_accept_handler, ctx);
435 GNUNET_break (GNUNET_OK ==
436 GNUNET_CONTAINER_multihashmap_put (ctx->info->dht_get_handles,
437 key,
438 get_h,
439 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
440}
441
442
443/**
444 * Function to process DHT string to regex matching.
445 * Called on each result obtained for the DHT search.
446 *
447 * @param cls closure (search context)
448 * @param exp when will this value expire
449 * @param key key of the result
450 * @param trunc_peer NULL if not truncated
451 * @param get_path path of the get request (not used)
452 * @param get_path_length length of @a get_path (not used)
453 * @param put_path path of the put request (not used)
454 * @param put_path_length length of the @a put_path (not used)
455 * @param type type of the result
456 * @param size number of bytes in data
457 * @param data pointer to the result data
458 *
459 * TODO: re-issue the request after certain time? cancel after X results?
460 */
461static void
462dht_get_string_handler (void *cls, struct GNUNET_TIME_Absolute exp,
463 const struct GNUNET_HashCode *key,
464 const struct GNUNET_PeerIdentity *trunc_peer,
465 const struct GNUNET_DHT_PathElement *get_path,
466 unsigned int get_path_length,
467 const struct GNUNET_DHT_PathElement *put_path,
468 unsigned int put_path_length,
469 enum GNUNET_BLOCK_Type type,
470 size_t size, const void *data)
471{
472 const struct RegexBlock *block = data;
473 struct RegexSearchContext *ctx = cls;
474 struct REGEX_INTERNAL_Search *info = ctx->info;
475 size_t len;
476 struct Result *copy;
477
478 LOG (GNUNET_ERROR_TYPE_INFO,
479 "DHT GET result for %s (%s)\n",
480 GNUNET_h2s (key), ctx->info->description);
481 copy = GNUNET_malloc (sizeof(struct Result) + size);
482 copy->size = size;
483 copy->data = &copy[1];
484 GNUNET_memcpy (&copy[1], block, size);
485 GNUNET_break (GNUNET_OK ==
486 GNUNET_CONTAINER_multihashmap_put (info->dht_get_results,
487 key, copy,
488 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
489 len = strlen (info->description);
490 if (len == ctx->position) // String processed
491 {
492 if (GNUNET_YES == GNUNET_BLOCK_is_accepting (block, size))
493 {
494 regex_find_path (key, ctx);
495 }
496 else
497 {
498 LOG (GNUNET_ERROR_TYPE_INFO, "block not accepting!\n");
499 /* FIXME REGEX this block not successful, wait for more? start timeout? */
500 }
501 return;
502 }
503 regex_next_edge (block, size, ctx);
504}
505
506
507/**
508 * Iterator over found existing cadet regex blocks that match an ongoing search.
509 *
510 * @param cls Closure (current context)-
511 * @param key Current key code (key for cached block).
512 * @param value Value in the hash map (cached RegexBlock).
513 * @return #GNUNET_YES: we should always continue to iterate.
514 */
515static int
516regex_result_iterator (void *cls,
517 const struct GNUNET_HashCode *key,
518 void *value)
519{
520 struct Result *result = value;
521 const struct RegexBlock *block = result->data;
522 struct RegexSearchContext *ctx = cls;
523
524 if ((GNUNET_YES ==
525 GNUNET_BLOCK_is_accepting (block, result->size)) &&
526 (ctx->position == strlen (ctx->info->description)))
527 {
528 LOG (GNUNET_ERROR_TYPE_INFO,
529 "Found accepting known block\n");
530 regex_find_path (key, ctx);
531 return GNUNET_YES; // We found an accept state!
532 }
533 LOG (GNUNET_ERROR_TYPE_DEBUG,
534 "* %lu, %lu, [%u]\n",
535 (unsigned long) ctx->position,
536 strlen (ctx->info->description),
537 GNUNET_BLOCK_is_accepting (block, result->size));
538 regex_next_edge (block, result->size, ctx);
539
540 GNUNET_STATISTICS_update (ctx->info->stats, "# regex cadet blocks iterated",
541 1, GNUNET_NO);
542
543 return GNUNET_YES;
544}
545
546
547/**
548 * Iterator over edges in a regex block retrieved from the DHT.
549 *
550 * @param cls Closure (context of the search).
551 * @param token Token that follows to next state.
552 * @param len Length of token.
553 * @param key Hash of next state.
554 * @return #GNUNET_YES if should keep iterating, #GNUNET_NO otherwise.
555 */
556static int
557regex_edge_iterator (void *cls,
558 const char *token,
559 size_t len,
560 const struct GNUNET_HashCode *key)
561{
562 struct RegexSearchContext *ctx = cls;
563 struct REGEX_INTERNAL_Search *info = ctx->info;
564 const char *current;
565 size_t current_len;
566
567 GNUNET_STATISTICS_update (info->stats, "# regex edges iterated",
568 1, GNUNET_NO);
569 current = &info->description[ctx->position];
570 current_len = strlen (info->description) - ctx->position;
571 if (len > current_len)
572 {
573 LOG (GNUNET_ERROR_TYPE_DEBUG, "Token too long, END\n");
574 return GNUNET_YES;
575 }
576 if (0 != strncmp (current, token, len))
577 {
578 LOG (GNUNET_ERROR_TYPE_DEBUG, "Token doesn't match, END\n");
579 return GNUNET_YES;
580 }
581
582 if (len > ctx->longest_match)
583 {
584 LOG (GNUNET_ERROR_TYPE_DEBUG, "Token is longer, KEEP\n");
585 ctx->longest_match = len;
586 ctx->hash = *key;
587 }
588 else
589 {
590 LOG (GNUNET_ERROR_TYPE_DEBUG, "Token is not longer, IGNORE\n");
591 }
592
593 LOG (GNUNET_ERROR_TYPE_DEBUG, "* End of regex edge iterator\n");
594 return GNUNET_YES;
595}
596
597
598/**
599 * Jump to the next edge, with the longest matching token.
600 *
601 * @param block Block found in the DHT.
602 * @param size Size of the block.
603 * @param ctx Context of the search.
604 */
605static void
606regex_next_edge (const struct RegexBlock *block,
607 size_t size,
608 struct RegexSearchContext *ctx)
609{
610 struct RegexSearchContext *new_ctx;
611 struct REGEX_INTERNAL_Search *info = ctx->info;
612 struct GNUNET_DHT_GetHandle *get_h;
613 struct GNUNET_HashCode *hash;
614 const char *rest;
615 int result;
616
617 LOG (GNUNET_ERROR_TYPE_DEBUG, "Next edge\n");
618 /* Find the longest match for the current string position,
619 * among tokens in the given block */
620 ctx->longest_match = 0;
621 result = REGEX_BLOCK_iterate (block, size,
622 &regex_edge_iterator, ctx);
623 GNUNET_break (GNUNET_OK == result);
624
625 /* Did anything match? */
626 if (0 == ctx->longest_match)
627 {
628 LOG (GNUNET_ERROR_TYPE_DEBUG,
629 "no match in block\n");
630 return;
631 }
632
633 hash = &ctx->hash;
634 new_ctx = GNUNET_new (struct RegexSearchContext);
635 new_ctx->info = info;
636 new_ctx->position = ctx->position + ctx->longest_match;
637 GNUNET_array_append (info->contexts, info->n_contexts, new_ctx);
638
639 /* Check whether we already have a DHT GET running for it */
640 if (GNUNET_YES ==
641 GNUNET_CONTAINER_multihashmap_contains (info->dht_get_handles, hash))
642 {
643 LOG (GNUNET_ERROR_TYPE_DEBUG,
644 "GET for %s running, END\n",
645 GNUNET_h2s (hash));
646 GNUNET_CONTAINER_multihashmap_get_multiple (info->dht_get_results,
647 hash,
648 &regex_result_iterator,
649 new_ctx);
650 return; /* We are already looking for it */
651 }
652
653 GNUNET_STATISTICS_update (info->stats, "# regex nodes traversed",
654 1, GNUNET_NO);
655
656 LOG (GNUNET_ERROR_TYPE_DEBUG,
657 "Following edges at %s for offset %u in `%s'\n",
658 GNUNET_h2s (hash),
659 (unsigned int) ctx->position,
660 info->description);
661 rest = &new_ctx->info->description[new_ctx->position];
662 get_h =
663 GNUNET_DHT_get_start (info->dht, /* handle */
664 GNUNET_BLOCK_TYPE_REGEX, /* type */
665 hash, /* key to search */
666 DHT_REPLICATION, /* replication level */
667 DHT_OPT,
668 rest, /* xquery */
669 strlen (rest) + 1, /* xquery bits */
670 &dht_get_string_handler, new_ctx);
671 if (GNUNET_OK !=
672 GNUNET_CONTAINER_multihashmap_put (info->dht_get_handles,
673 hash,
674 get_h,
675 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
676 {
677 GNUNET_break (0);
678 return;
679 }
680}
681
682
683/**
684 * Search for a peer offering a regex matching certain string in the DHT.
685 * The search runs until #REGEX_INTERNAL_search_cancel() is called, even if results
686 * are returned.
687 *
688 * @param dht An existing and valid DHT service handle.
689 * @param string String to match against the regexes in the DHT.
690 * @param callback Callback for found peers.
691 * @param callback_cls Closure for @c callback.
692 * @param stats Optional statistics handle to report usage. Can be NULL.
693 * @return Handle to stop search and free resources.
694 * Must be freed by calling #REGEX_INTERNAL_search_cancel().
695 */
696struct REGEX_INTERNAL_Search *
697REGEX_INTERNAL_search (struct GNUNET_DHT_Handle *dht,
698 const char *string,
699 REGEX_INTERNAL_Found callback,
700 void *callback_cls,
701 struct GNUNET_STATISTICS_Handle *stats)
702{
703 struct REGEX_INTERNAL_Search *h;
704 struct GNUNET_DHT_GetHandle *get_h;
705 struct RegexSearchContext *ctx;
706 struct GNUNET_HashCode key;
707 size_t size;
708 size_t len;
709
710 /* Initialize handle */
711 GNUNET_assert (NULL != dht);
712 GNUNET_assert (NULL != callback);
713 h = GNUNET_new (struct REGEX_INTERNAL_Search);
714 h->dht = dht;
715 h->description = GNUNET_strdup (string);
716 h->callback = callback;
717 h->callback_cls = callback_cls;
718 h->stats = stats;
719 h->dht_get_handles = GNUNET_CONTAINER_multihashmap_create (32, GNUNET_NO);
720 h->dht_get_results = GNUNET_CONTAINER_multihashmap_create (32, GNUNET_NO);
721
722 /* Initialize context */
723 len = strlen (string);
724 size = REGEX_INTERNAL_get_first_key (string, len, &key);
725 LOG (GNUNET_ERROR_TYPE_INFO,
726 "Initial key for `%s' is %s (based on `%.*s')\n",
727 string,
728 GNUNET_h2s (&key),
729 (int) size,
730 string);
731 ctx = GNUNET_new (struct RegexSearchContext);
732 ctx->position = size;
733 ctx->info = h;
734 GNUNET_array_append (h->contexts,
735 h->n_contexts,
736 ctx);
737 /* Start search in DHT */
738 get_h = GNUNET_DHT_get_start (h->dht, /* handle */
739 GNUNET_BLOCK_TYPE_REGEX, /* type */
740 &key, /* key to search */
741 DHT_REPLICATION, /* replication level */
742 DHT_OPT,
743 &h->description[size], /* xquery */
744 // FIXME add BLOOMFILTER to exclude filtered peers
745 len + 1 - size, /* xquery bits */
746 // FIXME add BLOOMFILTER SIZE
747 &dht_get_string_handler, ctx);
748 GNUNET_break (
749 GNUNET_OK ==
750 GNUNET_CONTAINER_multihashmap_put (h->dht_get_handles,
751 &key,
752 get_h,
753 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)
754 );
755
756 return h;
757}
758
759
760/**
761 * Iterator over hash map entries to cancel DHT GET requests after a
762 * successful connect_by_string.
763 *
764 * @param cls Closure (unused).
765 * @param key Current key code (unused).
766 * @param value Value in the hash map (get handle).
767 * @return #GNUNET_YES if we should continue to iterate,
768 * #GNUNET_NO if not.
769 */
770static int
771regex_cancel_dht_get (void *cls,
772 const struct GNUNET_HashCode *key,
773 void *value)
774{
775 struct GNUNET_DHT_GetHandle *h = value;
776
777 GNUNET_DHT_get_stop (h);
778 return GNUNET_YES;
779}
780
781
782/**
783 * Iterator over hash map entries to free CadetRegexBlocks stored during the
784 * search for connect_by_string.
785 *
786 * @param cls Closure (unused).
787 * @param key Current key code (unused).
788 * @param value CadetRegexBlock in the hash map.
789 * @return #GNUNET_YES if we should continue to iterate,
790 * #GNUNET_NO if not.
791 */
792static int
793regex_free_result (void *cls,
794 const struct GNUNET_HashCode *key,
795 void *value)
796{
797 GNUNET_free (value);
798 return GNUNET_YES;
799}
800
801
802/**
803 * Cancel an ongoing regex search in the DHT and free all resources.
804 *
805 * @param h the search context.
806 */
807void
808REGEX_INTERNAL_search_cancel (struct REGEX_INTERNAL_Search *h)
809{
810 unsigned int i;
811
812 GNUNET_free (h->description);
813 GNUNET_CONTAINER_multihashmap_iterate (h->dht_get_handles,
814 &regex_cancel_dht_get, NULL);
815 GNUNET_CONTAINER_multihashmap_iterate (h->dht_get_results,
816 &regex_free_result, NULL);
817 GNUNET_CONTAINER_multihashmap_destroy (h->dht_get_results);
818 GNUNET_CONTAINER_multihashmap_destroy (h->dht_get_handles);
819 if (0 < h->n_contexts)
820 {
821 for (i = 0; i < h->n_contexts; i++)
822 GNUNET_free (h->contexts[i]);
823 GNUNET_free (h->contexts);
824 }
825 GNUNET_free (h);
826}
827
828
829/* end of regex_internal_dht.c */