fix bad free
[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      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  */
54 struct 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  */
93 static void
94 regex_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  */
195 struct REGEX_INTERNAL_Announcement *
196 REGEX_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  */
222 void
223 REGEX_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  */
241 void
242 REGEX_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  */
256 struct 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  */
285 struct 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  */
303 struct 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  */
360 static void
361 regex_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  */
381 static void
382 dht_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  */
419 static void
420 regex_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  */
462 static void
463 dht_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  */
515 static int
516 regex_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  */
556 static int
557 regex_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  */
605 static void
606 regex_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  */
696 struct REGEX_INTERNAL_Search *
697 REGEX_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  */
770 static int
771 regex_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  */
792 static int
793 regex_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  */
807 void
808 REGEX_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 */