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