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