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