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