aboutsummaryrefslogtreecommitdiff
path: root/src/regex/regex_internal_dht.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2018-06-25 18:07:22 +0200
committerChristian Grothoff <christian@grothoff.org>2018-06-25 18:08:27 +0200
commit7da98cf076e9c5101244dfbbf8c3ddff045d298e (patch)
treedb4b4b28d0864cf5f7d424c40f1e7f4d945ff726 /src/regex/regex_internal_dht.c
parentb96052f1d3b8bb05f1868bd809fcb6e4f6569a4c (diff)
downloadgnunet-7da98cf076e9c5101244dfbbf8c3ddff045d298e.tar.gz
gnunet-7da98cf076e9c5101244dfbbf8c3ddff045d298e.zip
integrate dnsparser and dnsstub and tun with libgnunetutil
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 2555ef1df..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/**
19 * @file src/regex/regex_internal_dht.c
20 * @brief library to announce regexes in the network and match strings
21 * against published regexes.
22 * @author Bartlomiej Polot
23 */
24#include "platform.h"
25#include "regex_internal_lib.h"
26#include "regex_block_lib.h"
27#include "gnunet_dht_service.h"
28#include "gnunet_statistics_service.h"
29#include "gnunet_constants.h"
30#include "gnunet_signatures.h"
31
32
33#define LOG(kind,...) GNUNET_log_from (kind,"regex-dht",__VA_ARGS__)
34
35/**
36 * DHT replication level to use.
37 */
38#define DHT_REPLICATION 5
39
40/**
41 * DHT record lifetime to use.
42 */
43#define DHT_TTL GNUNET_TIME_UNIT_HOURS
44
45/**
46 * DHT options to set.
47 */
48#define DHT_OPT GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE
49
50
51/**
52 * Handle to store cached data about a regex announce.
53 */
54struct REGEX_INTERNAL_Announcement
55{
56 /**
57 * DHT handle to use, must be initialized externally.
58 */
59 struct GNUNET_DHT_Handle *dht;
60
61 /**
62 * Regular expression.
63 */
64 const char *regex;
65
66 /**
67 * Automaton representation of the regex (expensive to build).
68 */
69 struct REGEX_INTERNAL_Automaton *dfa;
70
71 /**
72 * Our private key.
73 */
74 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
75
76 /**
77 * Optional statistics handle to report usage. Can be NULL.
78 */
79 struct GNUNET_STATISTICS_Handle *stats;
80};
81
82
83/**
84 * Regex callback iterator to store own service description in the DHT.
85 *
86 * @param cls closure.
87 * @param key hash for current state.
88 * @param proof proof for current state.
89 * @param accepting #GNUNET_YES if this is an accepting state, #GNUNET_NO if not.
90 * @param num_edges number of edges leaving current state.
91 * @param edges edges leaving current state.
92 */
93static void
94regex_iterator (void *cls,
95 const struct GNUNET_HashCode *key,
96 const char *proof,
97 int accepting,
98 unsigned int num_edges,
99 const struct REGEX_BLOCK_Edge *edges)
100{
101 struct REGEX_INTERNAL_Announcement *h = cls;
102 struct RegexBlock *block;
103 size_t size;
104 unsigned int i;
105
106 LOG (GNUNET_ERROR_TYPE_INFO,
107 "DHT PUT for state %s with proof `%s' and %u edges:\n",
108 GNUNET_h2s (key),
109 proof,
110 num_edges);
111 for (i = 0; i < num_edges; i++)
112 {
113 LOG (GNUNET_ERROR_TYPE_INFO,
114 "Edge %u `%s' towards %s\n",
115 i,
116 edges[i].label,
117 GNUNET_h2s (&edges[i].destination));
118 }
119 if (GNUNET_YES == accepting)
120 {
121 struct RegexAcceptBlock ab;
122
123 LOG (GNUNET_ERROR_TYPE_INFO,
124 "State %s is accepting, putting own id\n",
125 GNUNET_h2s (key));
126 size = sizeof (struct RegexAcceptBlock);
127 ab.purpose.size = ntohl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
128 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
129 sizeof (struct GNUNET_HashCode));
130 ab.purpose.purpose = ntohl (GNUNET_SIGNATURE_PURPOSE_REGEX_ACCEPT);
131 ab.expiration_time = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_DHT_MAX_EXPIRATION));
132 ab.key = *key;
133 GNUNET_CRYPTO_eddsa_key_get_public (h->priv,
134 &ab.peer.public_key);
135 GNUNET_assert (GNUNET_OK ==
136 GNUNET_CRYPTO_eddsa_sign (h->priv,
137 &ab.purpose,
138 &ab.signature));
139
140 GNUNET_STATISTICS_update (h->stats, "# regex accepting blocks stored",
141 1, GNUNET_NO);
142 GNUNET_STATISTICS_update (h->stats, "# regex accepting block bytes stored",
143 sizeof (struct RegexAcceptBlock), GNUNET_NO);
144 (void)
145 GNUNET_DHT_put (h->dht, key,
146 DHT_REPLICATION,
147 DHT_OPT | GNUNET_DHT_RO_RECORD_ROUTE,
148 GNUNET_BLOCK_TYPE_REGEX_ACCEPT,
149 size,
150 &ab,
151 GNUNET_TIME_relative_to_absolute (DHT_TTL),
152 NULL, NULL);
153 }
154 block = REGEX_BLOCK_create (proof,
155 num_edges,
156 edges,
157 accepting,
158 &size);
159 if (NULL == block)
160 return;
161 (void) GNUNET_DHT_put (h->dht,
162 key,
163 DHT_REPLICATION,
164 DHT_OPT,
165 GNUNET_BLOCK_TYPE_REGEX,
166 size,
167 block,
168 GNUNET_TIME_relative_to_absolute (DHT_TTL),
169 NULL,
170 NULL);
171 GNUNET_STATISTICS_update (h->stats,
172 "# regex blocks stored",
173 1,
174 GNUNET_NO);
175 GNUNET_STATISTICS_update (h->stats,
176 "# regex block bytes stored",
177 size,
178 GNUNET_NO);
179 GNUNET_free (block);
180}
181
182
183/**
184 * Announce a regular expression: put all states of the automaton in the DHT.
185 * Does not free resources, must call #REGEX_INTERNAL_announce_cancel() for that.
186 *
187 * @param dht An existing and valid DHT service handle. CANNOT be NULL.
188 * @param priv our private key, must remain valid until the announcement is cancelled
189 * @param regex Regular expression to announce.
190 * @param compression How many characters per edge can we squeeze?
191 * @param stats Optional statistics handle to report usage. Can be NULL.
192 * @return Handle to reuse o free cached resources.
193 * Must be freed by calling #REGEX_INTERNAL_announce_cancel().
194 */
195struct REGEX_INTERNAL_Announcement *
196REGEX_INTERNAL_announce (struct GNUNET_DHT_Handle *dht,
197 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
198 const char *regex,
199 uint16_t compression,
200 struct GNUNET_STATISTICS_Handle *stats)
201{
202 struct REGEX_INTERNAL_Announcement *h;
203
204 GNUNET_assert (NULL != dht);
205 h = GNUNET_new (struct REGEX_INTERNAL_Announcement);
206 h->regex = regex;
207 h->dht = dht;
208 h->stats = stats;
209 h->priv = priv;
210 h->dfa = REGEX_INTERNAL_construct_dfa (regex, strlen (regex), compression);
211 REGEX_INTERNAL_reannounce (h);
212 return h;
213}
214
215
216/**
217 * Announce again a regular expression previously announced.
218 * Does use caching to speed up process.
219 *
220 * @param h Handle returned by a previous #REGEX_INTERNAL_announce call().
221 */
222void
223REGEX_INTERNAL_reannounce (struct REGEX_INTERNAL_Announcement *h)
224{
225 GNUNET_assert (NULL != h->dfa); /* make sure to call announce first */
226 LOG (GNUNET_ERROR_TYPE_INFO,
227 "REGEX_INTERNAL_reannounce: %s\n",
228 h->regex);
229 REGEX_INTERNAL_iterate_reachable_edges (h->dfa,
230 &regex_iterator,
231 h);
232}
233
234
235/**
236 * Clear all cached data used by a regex announce.
237 * Does not close DHT connection.
238 *
239 * @param h Handle returned by a previous #REGEX_INTERNAL_announce() call.
240 */
241void
242REGEX_INTERNAL_announce_cancel (struct REGEX_INTERNAL_Announcement *h)
243{
244 REGEX_INTERNAL_automaton_destroy (h->dfa);
245 GNUNET_free (h);
246}
247
248
249/******************************************************************************/
250
251
252/**
253 * Struct to keep state of running searches that have consumed a part of
254 * the inital string.
255 */
256struct RegexSearchContext
257{
258 /**
259 * Part of the description already consumed by
260 * this particular search branch.
261 */
262 size_t position;
263
264 /**
265 * Information about the search.
266 */
267 struct REGEX_INTERNAL_Search *info;
268
269 /**
270 * We just want to look for one edge, the longer the better.
271 * Keep its length.
272 */
273 unsigned int longest_match;
274
275 /**
276 * Destination hash of the longest match.
277 */
278 struct GNUNET_HashCode hash;
279};
280
281
282/**
283 * Type of values in `dht_get_results`.
284 */
285struct Result
286{
287 /**
288 * Number of bytes in data.
289 */
290 size_t size;
291
292 /**
293 * The raw result data.
294 */
295 const void *data;
296};
297
298
299/**
300 * Struct to keep information of searches of services described by a regex
301 * using a user-provided string service description.
302 */
303struct REGEX_INTERNAL_Search
304{
305 /**
306 * DHT handle to use, must be initialized externally.
307 */
308 struct GNUNET_DHT_Handle *dht;
309
310 /**
311 * Optional statistics handle to report usage. Can be NULL.
312 */
313 struct GNUNET_STATISTICS_Handle *stats;
314
315 /**
316 * User provided description of the searched service.
317 */
318 char *description;
319
320 /**
321 * Running DHT GETs.
322 */
323 struct GNUNET_CONTAINER_MultiHashMap *dht_get_handles;
324
325 /**
326 * Results from running DHT GETs, values are of type
327 * 'struct Result'.
328 */
329 struct GNUNET_CONTAINER_MultiHashMap *dht_get_results;
330
331 /**
332 * Contexts, for each running DHT GET. Free all on end of search.
333 */
334 struct RegexSearchContext **contexts;
335
336 /**
337 * Number of contexts (branches/steps in search).
338 */
339 unsigned int n_contexts;
340
341 /**
342 * @param callback Callback for found peers.
343 */
344 REGEX_INTERNAL_Found callback;
345
346 /**
347 * @param callback_cls Closure for @c callback.
348 */
349 void *callback_cls;
350};
351
352
353/**
354 * Jump to the next edge, with the longest matching token.
355 *
356 * @param block Block found in the DHT.
357 * @param size Size of the block.
358 * @param ctx Context of the search.
359 */
360static void
361regex_next_edge (const struct RegexBlock *block,
362 size_t size,
363 struct RegexSearchContext *ctx);
364
365
366/**
367 * Function to process DHT string to regex matching.
368 * Called on each result obtained for the DHT search.
369 *
370 * @param cls Closure (search context).
371 * @param exp When will this value expire.
372 * @param key Key of the result.
373 * @param get_path Path of the get request.
374 * @param get_path_length Lenght of get_path.
375 * @param put_path Path of the put request.
376 * @param put_path_length Length of the put_path.
377 * @param type Type of the result.
378 * @param size Number of bytes in data.
379 * @param data Pointer to the result data.
380 */
381static void
382dht_get_string_accept_handler (void *cls, struct GNUNET_TIME_Absolute exp,
383 const struct GNUNET_HashCode *key,
384 const struct GNUNET_PeerIdentity *get_path,
385 unsigned int get_path_length,
386 const struct GNUNET_PeerIdentity *put_path,
387 unsigned int put_path_length,
388 enum GNUNET_BLOCK_Type type,
389 size_t size, const void *data)
390{
391 const struct RegexAcceptBlock *block = data;
392 struct RegexSearchContext *ctx = cls;
393 struct REGEX_INTERNAL_Search *info = ctx->info;
394
395 LOG (GNUNET_ERROR_TYPE_DEBUG,
396 "Regex result accept for %s (key %s)\n",
397 info->description, GNUNET_h2s(key));
398
399 GNUNET_STATISTICS_update (info->stats,
400 "# regex accepting blocks found",
401 1, GNUNET_NO);
402 GNUNET_STATISTICS_update (info->stats,
403 "# regex accepting block bytes found",
404 size, GNUNET_NO);
405 info->callback (info->callback_cls,
406 &block->peer,
407 get_path, get_path_length,
408 put_path, put_path_length);
409}
410
411
412/**
413 * Find a path to a peer that offers a regex service compatible
414 * with a given string.
415 *
416 * @param key The key of the accepting state.
417 * @param ctx Context containing info about the string, tunnel, etc.
418 */
419static void
420regex_find_path (const struct GNUNET_HashCode *key,
421 struct RegexSearchContext *ctx)
422{
423 struct GNUNET_DHT_GetHandle *get_h;
424
425 LOG (GNUNET_ERROR_TYPE_DEBUG,
426 "Accept state found, now searching for paths to %s\n",
427 GNUNET_h2s (key),
428 (unsigned int) ctx->position);
429 get_h = GNUNET_DHT_get_start (ctx->info->dht, /* handle */
430 GNUNET_BLOCK_TYPE_REGEX_ACCEPT, /* type */
431 key, /* key to search */
432 DHT_REPLICATION, /* replication level */
433 DHT_OPT | GNUNET_DHT_RO_RECORD_ROUTE,
434 NULL, /* xquery */ // FIXME BLOOMFILTER
435 0, /* xquery bits */ // FIXME BLOOMFILTER SIZE
436 &dht_get_string_accept_handler, ctx);
437 GNUNET_break (GNUNET_OK ==
438 GNUNET_CONTAINER_multihashmap_put(ctx->info->dht_get_handles,
439 key,
440 get_h,
441 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
442}
443
444
445/**
446 * Function to process DHT string to regex matching.
447 * Called on each result obtained for the DHT search.
448 *
449 * @param cls closure (search context)
450 * @param exp when will this value expire
451 * @param key key of the result
452 * @param get_path path of the get request (not used)
453 * @param get_path_length length of @a get_path (not used)
454 * @param put_path path of the put request (not used)
455 * @param put_path_length length of the @a put_path (not used)
456 * @param type type of the result
457 * @param size number of bytes in data
458 * @param data pointer to the result data
459 *
460 * TODO: re-issue the request after certain time? cancel after X results?
461 */
462static void
463dht_get_string_handler (void *cls, struct GNUNET_TIME_Absolute exp,
464 const struct GNUNET_HashCode *key,
465 const struct GNUNET_PeerIdentity *get_path,
466 unsigned int get_path_length,
467 const struct GNUNET_PeerIdentity *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 "* %u, %u, [%u]\n",
535 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 Lenght 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 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 */