- use proper signedness
[oweals/gnunet.git] / src / regex / regex_internal_dht.c
index e7259edcc7a36e0fdc972b9309d676693aeb1325..f7d383406d9a5361a2fd0fd7b03333fe568d9945 100644 (file)
 #include "regex_block_lib.h"
 #include "gnunet_dht_service.h"
 #include "gnunet_statistics_service.h"
+#include "gnunet_constants.h"
+#include "gnunet_signatures.h"
+
 
 #define LOG(kind,...) GNUNET_log_from (kind,"regex-dht",__VA_ARGS__)
 
-/* FIXME: OPTION (API, CONFIG) */
 #define DHT_REPLICATION 5
 #define DHT_TTL         GNUNET_TIME_UNIT_HOURS
-#define DEBUG_DHT       GNUNET_NO
-
-#if DEBUG_DHT
-#define DHT_OPT         GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE | GNUNET_DHT_RO_RECORD_ROUTE
-#else
 #define DHT_OPT         GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE
-#endif
 
+
+/**
+ * Handle to store cached data about a regex announce.
+ */
 struct REGEX_INTERNAL_Announcement
 {
   /**
@@ -60,9 +60,9 @@ struct REGEX_INTERNAL_Announcement
   struct REGEX_INTERNAL_Automaton* dfa;
 
   /**
-   * Identity under which to announce the regex.
+   * Our private key.
    */
-  struct GNUNET_PeerIdentity id;
+  const struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
 
   /**
    * Optional statistics handle to report usage. Can be NULL.
@@ -92,47 +92,67 @@ regex_iterator (void *cls,
   struct REGEX_INTERNAL_Announcement *h = cls;
   struct RegexBlock *block;
   size_t size;
+  unsigned int i;
 
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
+  LOG (GNUNET_ERROR_TYPE_INFO,
        "DHT PUT for state %s with proof `%s' and %u edges\n",
        GNUNET_h2s (key),
        proof,
        num_edges);
+  for (i = 0; i < num_edges; i++)
+  {
+    LOG (GNUNET_ERROR_TYPE_INFO,
+         "  edge %s towards %s (%s)\n",
+         edges[i].label,
+         GNUNET_h2s (&edges[i].destination),
+         proof);
+  }
   if (GNUNET_YES == accepting)
   {
-    struct RegexAccept block;
+    struct RegexAcceptBlock ab;
 
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
+    LOG (GNUNET_ERROR_TYPE_INFO,
          "State %s is accepting, putting own id\n",
-         GNUNET_h2s(key));
-    size = sizeof (block);
-    block.key = *key;
-    block.id = h->id;
+         GNUNET_h2s (key));
+    size = sizeof (struct RegexAcceptBlock);
+    ab.purpose.size = ntohl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
+                             sizeof (struct GNUNET_TIME_AbsoluteNBO) +
+                             sizeof (struct GNUNET_HashCode));
+    ab.purpose.purpose = ntohl (GNUNET_SIGNATURE_PURPOSE_REGEX_ACCEPT);
+    ab.expiration_time = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_DHT_MAX_EXPIRATION));
+    ab.key = *key;
+    GNUNET_CRYPTO_eddsa_key_get_public (h->priv,
+                                                   &ab.peer.public_key);
+    GNUNET_assert (GNUNET_OK ==
+                   GNUNET_CRYPTO_eddsa_sign (h->priv,
+                                           &ab.purpose,
+                                           &ab.signature));
+
     GNUNET_STATISTICS_update (h->stats, "# regex accepting blocks stored",
                               1, GNUNET_NO);
     GNUNET_STATISTICS_update (h->stats, "# regex accepting block bytes stored",
-                              sizeof (block), GNUNET_NO);
+                              sizeof (struct RegexAcceptBlock), GNUNET_NO);
     (void)
     GNUNET_DHT_put (h->dht, key,
                     DHT_REPLICATION,
                     DHT_OPT | GNUNET_DHT_RO_RECORD_ROUTE,
                     GNUNET_BLOCK_TYPE_REGEX_ACCEPT,
                     size,
-                    &block,
+                    &ab,
                     GNUNET_TIME_relative_to_absolute (DHT_TTL),
                     DHT_TTL,
                     NULL, NULL);
   }
   block = REGEX_BLOCK_create (proof,
-                             num_edges, edges,
-                             accepting,
-                             &size);
+                              num_edges, edges,
+                              accepting,
+                              &size);
   (void)
   GNUNET_DHT_put (h->dht, key,
                   DHT_REPLICATION,
                   DHT_OPT,
-                  GNUNET_BLOCK_TYPE_REGEX, 
-                 size, block,
+                  GNUNET_BLOCK_TYPE_REGEX,
+                  size, block,
                   GNUNET_TIME_relative_to_absolute (DHT_TTL),
                   DHT_TTL,
                   NULL, NULL);
@@ -144,39 +164,63 @@ regex_iterator (void *cls,
 }
 
 
+/**
+ * Announce a regular expression: put all states of the automaton in the DHT.
+ * Does not free resources, must call REGEX_INTERNAL_announce_cancel for that.
+ *
+ * @param dht An existing and valid DHT service handle. CANNOT be NULL.
+ * @param priv our private key, must remain valid until the announcement is cancelled
+ * @param regex Regular expression to announce.
+ * @param compression How many characters per edge can we squeeze?
+ * @param stats Optional statistics handle to report usage. Can be NULL.
+ *
+ * @return Handle to reuse o free cached resources.
+ *         Must be freed by calling REGEX_INTERNAL_announce_cancel.
+ */
 struct REGEX_INTERNAL_Announcement *
 REGEX_INTERNAL_announce (struct GNUNET_DHT_Handle *dht,
-                       const struct GNUNET_PeerIdentity *id,
-                       const char *regex,
-                       uint16_t compression,
-                       struct GNUNET_STATISTICS_Handle *stats)
+                        const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
+                        const char *regex,
+                        uint16_t compression,
+                        struct GNUNET_STATISTICS_Handle *stats)
 {
   struct REGEX_INTERNAL_Announcement *h;
 
   GNUNET_assert (NULL != dht);
-  h = GNUNET_malloc (sizeof (struct REGEX_INTERNAL_Announcement));
+  h = GNUNET_new (struct REGEX_INTERNAL_Announcement);
   h->regex = regex;
   h->dht = dht;
   h->stats = stats;
-  h->id = *id;
-  h->dfa = REGEX_INTERNAL_construct_dfa (regex,
-                                       strlen (regex),
-                                       compression);
+  h->priv = priv;
+  h->dfa = REGEX_INTERNAL_construct_dfa (regex, strlen (regex), compression);
   REGEX_INTERNAL_reannounce (h);
   return h;
 }
 
 
+/**
+ * Announce again a regular expression previously announced.
+ * Does use caching to speed up process.
+ *
+ * @param h Handle returned by a previous REGEX_INTERNAL_announce call.
+ */
 void
 REGEX_INTERNAL_reannounce (struct REGEX_INTERNAL_Announcement *h)
 {
   GNUNET_assert (NULL != h->dfa); /* make sure to call announce first */
-  LOG (GNUNET_ERROR_TYPE_INFO, "REGEX_INTERNAL_reannounce: %.60s\n", h->regex);
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  full: %s\n", h->regex);
-  REGEX_INTERNAL_iterate_all_edges (h->dfa, &regex_iterator, h);
+  LOG (GNUNET_ERROR_TYPE_INFO,
+       "REGEX_INTERNAL_reannounce: %s\n",
+       h->regex);
+  REGEX_INTERNAL_iterate_reachable_edges (h->dfa, &regex_iterator, h);
 }
 
 
+/**
+ * Clear all cached data used by a regex announce.
+ * Does not close DHT connection.
+ *
+ * @param h Handle returned by a previous REGEX_INTERNAL_announce call.
+ */
 void
 REGEX_INTERNAL_announce_cancel (struct REGEX_INTERNAL_Announcement *h)
 {
@@ -194,71 +238,89 @@ REGEX_INTERNAL_announce_cancel (struct REGEX_INTERNAL_Announcement *h)
  */
 struct RegexSearchContext
 {
-    /**
-     * Part of the description already consumed by
-     * this particular search branch.
-     */
+  /**
+   * Part of the description already consumed by
+   * this particular search branch.
+   */
   size_t position;
 
-    /**
-     * Information about the search.
-     */
+  /**
+   * Information about the search.
+   */
   struct REGEX_INTERNAL_Search *info;
 
-    /**
-     * We just want to look for one edge, the longer the better.
-     * Keep its length.
-     */
+  /**
+   * We just want to look for one edge, the longer the better.
+   * Keep its length.
+   */
   unsigned int longest_match;
 
-    /**
-     * Destination hash of the longest match.
-     */
+  /**
+   * Destination hash of the longest match.
+   */
   struct GNUNET_HashCode hash;
 };
 
 
+/**
+ * Type of values in 'dht_get_results'.
+ */
+struct Result
+{
+  /**
+   * Number of bytes in data.
+   */
+  size_t size;
+
+  /**
+   * The raw result data.
+   */
+  const void *data;
+};
+
+
 /**
  * Struct to keep information of searches of services described by a regex
  * using a user-provided string service description.
  */
 struct REGEX_INTERNAL_Search
 {
-    /**
-     * DHT handle to use, must be initialized externally.
-     */
+  /**
+   * DHT handle to use, must be initialized externally.
+   */
   struct GNUNET_DHT_Handle *dht;
 
-    /**
-     * Optional statistics handle to report usage. Can be NULL.
-     */
+  /**
+   * Optional statistics handle to report usage. Can be NULL.
+   */
   struct GNUNET_STATISTICS_Handle *stats;
 
-    /**
-     * User provided description of the searched service.
-     */
+  /**
+   * User provided description of the searched service.
+   */
   char *description;
 
-    /**
-     * Running DHT GETs.
-     */
+  /**
+   * Running DHT GETs.
+   */
   struct GNUNET_CONTAINER_MultiHashMap *dht_get_handles;
 
-    /**
-     * Results from running DHT GETs.
-     */
+  /**
+   * Results from running DHT GETs, values are of type
+   * 'struct Result'.
+   */
   struct GNUNET_CONTAINER_MultiHashMap *dht_get_results;
 
-    /**
-     * Contexts, for each running DHT GET. Free all on end of search.
-     */
+  /**
+   * Contexts, for each running DHT GET. Free all on end of search.
+   */
   struct RegexSearchContext **contexts;
 
-    /**
-     * Number of contexts (branches/steps in search).
-     */
+  /**
+   * Number of contexts (branches/steps in search).
+   */
   unsigned int n_contexts;
-  
+
   /**
    * @param callback Callback for found peers.
    */
@@ -271,15 +333,12 @@ struct REGEX_INTERNAL_Search
 };
 
 
-
 /**
  * Jump to the next edge, with the longest matching token.
  *
  * @param block Block found in the DHT.
  * @param size Size of the block.
  * @param ctx Context of the search.
- *
- * @return GNUNET_YES if should keep iterating, GNUNET_NO otherwise.
  */
 static void
 regex_next_edge (const struct RegexBlock *block,
@@ -304,7 +363,7 @@ regex_next_edge (const struct RegexBlock *block,
  */
 static void
 dht_get_string_accept_handler (void *cls, struct GNUNET_TIME_Absolute exp,
-                               const struct GNUNET_HashCode * key,
+                               const struct GNUNET_HashCode *key,
                                const struct GNUNET_PeerIdentity *get_path,
                                unsigned int get_path_length,
                                const struct GNUNET_PeerIdentity *put_path,
@@ -312,21 +371,22 @@ dht_get_string_accept_handler (void *cls, struct GNUNET_TIME_Absolute exp,
                                enum GNUNET_BLOCK_Type type,
                                size_t size, const void *data)
 {
-  const struct RegexAccept *block = data;
+  const struct RegexAcceptBlock *block = data;
   struct RegexSearchContext *ctx = cls;
   struct REGEX_INTERNAL_Search *info = ctx->info;
 
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Got regex results from DHT!\n");
-  LOG (GNUNET_ERROR_TYPE_INFO, "   accept for %s (key %s)\n",
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Regex result accept for %s (key %s)\n",
        info->description, GNUNET_h2s(key));
 
-  GNUNET_STATISTICS_update (info->stats, "# regex accepting blocks found",
+  GNUNET_STATISTICS_update (info->stats,
+                           "# regex accepting blocks found",
                             1, GNUNET_NO);
-  GNUNET_STATISTICS_update (info->stats, "# regex accepting block bytes found",
+  GNUNET_STATISTICS_update (info->stats,
+                           "# regex accepting block bytes found",
                             size, GNUNET_NO);
-
   info->callback (info->callback_cls,
-                  &block->id,
+                  &block->peer,
                   get_path, get_path_length,
                   put_path, put_path_length);
 }
@@ -335,7 +395,7 @@ dht_get_string_accept_handler (void *cls, struct GNUNET_TIME_Absolute exp,
 /**
  * Find a path to a peer that offers a regex servcie compatible
  * with a given string.
- * 
+ *
  * @param key The key of the accepting state.
  * @param ctx Context containing info about the string, tunnel, etc.
  */
@@ -345,8 +405,9 @@ regex_find_path (const struct GNUNET_HashCode *key,
 {
   struct GNUNET_DHT_GetHandle *get_h;
 
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Found peer by service\n");
-  LOG (GNUNET_ERROR_TYPE_INFO, "   find accept for %s\n", GNUNET_h2s (key));
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "regex finds path for %s\n",
+       GNUNET_h2s (key));
   get_h = GNUNET_DHT_get_start (ctx->info->dht,    /* handle */
                                 GNUNET_BLOCK_TYPE_REGEX_ACCEPT, /* type */
                                 key,     /* key to search */
@@ -393,40 +454,24 @@ dht_get_string_handler (void *cls, struct GNUNET_TIME_Absolute exp,
   const struct RegexBlock *block = data;
   struct RegexSearchContext *ctx = cls;
   struct REGEX_INTERNAL_Search *info = ctx->info;
-  void *copy;
   size_t len;
-  char *datastore;
-
-#if DEBUG_DHT
-  if ( (NULL != put_path) && 
-       (0 != put_path_length) )
-  {
-    datastore = GNUNET_strdup (GNUNET_i2s (&put_path[put_path_length - 1]));
-  }
-  else
-  {
-    GNUNET_asprintf (&datastore, "?? %u/%u", put_path_length, get_path_length);
-  }
-#else
-  datastore = GNUNET_strdup ("N/A");
-#endif
-
-  LOG (GNUNET_ERROR_TYPE_INFO, " DHT GET result for %s (%s) at %s\n",
-       GNUNET_h2s (key), ctx->info->description, datastore);
-  GNUNET_free (datastore);
-
-  copy = GNUNET_malloc (size);
-  memcpy (copy, data, size);
-  GNUNET_break (
-    GNUNET_OK ==
-    GNUNET_CONTAINER_multihashmap_put (info->dht_get_results,
-                                       key, copy,
-                                       GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)
-               );
+  struct Result *copy;
+
+  LOG (GNUNET_ERROR_TYPE_INFO,
+       "DHT GET result for %s (%s)\n",
+       GNUNET_h2s (key), ctx->info->description);
+  copy = GNUNET_malloc (sizeof (struct Result) + size);
+  copy->size = size;
+  copy->data = &copy[1];
+  memcpy (&copy[1], block, size);
+  GNUNET_break (GNUNET_OK ==
+               GNUNET_CONTAINER_multihashmap_put (info->dht_get_results,
+                                                  key, copy,
+                                                  GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
   len = strlen (info->description);
   if (len == ctx->position) // String processed
   {
-    if (GNUNET_YES == ntohs (block->is_accepting))
+    if (GNUNET_YES == GNUNET_BLOCK_is_accepting (block, size))
     {
       regex_find_path (key, ctx);
     }
@@ -454,21 +499,25 @@ regex_result_iterator (void *cls,
                        const struct GNUNET_HashCode * key,
                        void *value)
 {
-  struct RegexBlock *block = value;
+  struct Result *result = value;
+  const struct RegexBlock *block = result->data;
   struct RegexSearchContext *ctx = cls;
 
-  if (GNUNET_YES == ntohs (block->is_accepting) &&
-      ctx->position == strlen (ctx->info->description))
+  if ( (GNUNET_YES ==
+       GNUNET_BLOCK_is_accepting (block, result->size)) &&
+       (ctx->position == strlen (ctx->info->description)) )
   {
-    LOG (GNUNET_ERROR_TYPE_INFO, " * Found accepting known block\n");
+    LOG (GNUNET_ERROR_TYPE_INFO,
+        "Found accepting known block\n");
     regex_find_path (key, ctx);
     return GNUNET_YES; // We found an accept state!
   }
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "* %u, %u, [%u]\n",
-       ctx->position, strlen(ctx->info->description),
-       ntohs (block->is_accepting));
-
-  regex_next_edge (block, SIZE_MAX, ctx);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "* %u, %u, [%u]\n",
+       ctx->position,
+       strlen (ctx->info->description),
+       GNUNET_BLOCK_is_accepting (block, result->size));
+  regex_next_edge (block, result->size, ctx);
 
   GNUNET_STATISTICS_update (ctx->info->stats, "# regex mesh blocks iterated",
                             1, GNUNET_NO);
@@ -500,37 +549,28 @@ regex_edge_iterator (void *cls,
 
   GNUNET_STATISTICS_update (info->stats, "# regex edges iterated",
                             1, GNUNET_NO);
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "*    Start of regex edge iterator\n");
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "*     descr : %s\n", info->description);
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "*     posit : %u\n", ctx->position);
   current = &info->description[ctx->position];
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "*     currt : %s\n", current);
   current_len = strlen (info->description) - ctx->position;
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "*     ctlen : %u\n", current_len);
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "*     tklen : %u\n", len);
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "*     token : %.*s\n", len, token);
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "*     nextk : %s\n", GNUNET_h2s(key));
   if (len > current_len)
   {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "*     Token too long, END\n");
-    return GNUNET_YES; // Token too long, wont match
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "Token too long, END\n");
+    return GNUNET_YES;
   }
   if (0 != strncmp (current, token, len))
   {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "*     Token doesn't match, END\n");
-    return GNUNET_YES; // Token doesn't match
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "Token doesn't match, END\n");
+    return GNUNET_YES;
   }
 
   if (len > ctx->longest_match)
   {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "*     Token is longer, KEEP\n");
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "Token is longer, KEEP\n");
     ctx->longest_match = len;
     ctx->hash = *key;
   }
   else
   {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "*     Token is not longer, IGNORE\n");
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "Token is not longer, IGNORE\n");
   }
 
   LOG (GNUNET_ERROR_TYPE_DEBUG, "*    End of regex edge iterator\n");
@@ -544,8 +584,6 @@ regex_edge_iterator (void *cls,
  * @param block Block found in the DHT.
  * @param size Size of the block.
  * @param ctx Context of the search.
- *
- * @return GNUNET_YES if should keep iterating, GNUNET_NO otherwise.
  */
 static void
 regex_next_edge (const struct RegexBlock *block,
@@ -559,22 +597,24 @@ regex_next_edge (const struct RegexBlock *block,
   const char *rest;
   int result;
 
-  /* Find the longest match for the current string position, 
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "Next edge\n");
+  /* Find the longest match for the current string position,
    * among tokens in the given block */
   ctx->longest_match = 0;
   result = REGEX_BLOCK_iterate (block, size,
-                                       &regex_edge_iterator, ctx);
+                                &regex_edge_iterator, ctx);
   GNUNET_break (GNUNET_OK == result);
 
   /* Did anything match? */
   if (0 == ctx->longest_match)
   {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  no match in block\n");
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+        "no match in block\n");
     return;
   }
 
   hash = &ctx->hash;
-  new_ctx = GNUNET_malloc (sizeof (struct RegexSearchContext));
+  new_ctx = GNUNET_new (struct RegexSearchContext);
   new_ctx->info = info;
   new_ctx->position = ctx->position + ctx->longest_match;
   GNUNET_array_append (info->contexts, info->n_contexts, new_ctx);
@@ -583,7 +623,8 @@ regex_next_edge (const struct RegexBlock *block,
   if (GNUNET_YES ==
       GNUNET_CONTAINER_multihashmap_contains (info->dht_get_handles, hash))
   {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "*     GET for %s running, END\n",
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+        "GET for %s running, END\n",
          GNUNET_h2s (hash));
     GNUNET_CONTAINER_multihashmap_get_multiple (info->dht_get_results,
                                                 hash,
@@ -595,19 +636,18 @@ regex_next_edge (const struct RegexBlock *block,
   GNUNET_STATISTICS_update (info->stats, "# regex nodes traversed",
                             1, GNUNET_NO);
 
-  /* Start search in DHT */
-  LOG (GNUNET_ERROR_TYPE_INFO, "   looking for %s\n", GNUNET_h2s (hash));
+  LOG (GNUNET_ERROR_TYPE_INFO,
+       "looking for %s\n",
+       GNUNET_h2s (hash));
   rest = &new_ctx->info->description[new_ctx->position];
-  get_h = 
+  get_h =
       GNUNET_DHT_get_start (info->dht,    /* handle */
                             GNUNET_BLOCK_TYPE_REGEX, /* type */
                             hash,     /* key to search */
                             DHT_REPLICATION, /* replication level */
                             DHT_OPT,
                             rest, /* xquery */
-                            // FIXME add BLOOMFILTER to exclude filtered peers
-                            strlen(rest) + 1,     /* xquery bits */
-                            // FIXME add BLOOMFILTER SIZE
+                            strlen (rest) + 1,     /* xquery bits */
                             &dht_get_string_handler, new_ctx);
   if (GNUNET_OK !=
       GNUNET_CONTAINER_multihashmap_put(info->dht_get_handles,
@@ -621,6 +661,20 @@ regex_next_edge (const struct RegexBlock *block,
 }
 
 
+/**
+ * Search for a peer offering a regex matching certain string in the DHT.
+ * The search runs until REGEX_INTERNAL_search_cancel is called, even if results
+ * are returned.
+ *
+ * @param dht An existing and valid DHT service handle.
+ * @param string String to match against the regexes in the DHT.
+ * @param callback Callback for found peers.
+ * @param callback_cls Closure for @c callback.
+ * @param stats Optional statistics handle to report usage. Can be NULL.
+ *
+ * @return Handle to stop search and free resources.
+ *         Must be freed by calling REGEX_INTERNAL_search_cancel.
+ */
 struct REGEX_INTERNAL_Search *
 REGEX_INTERNAL_search (struct GNUNET_DHT_Handle *dht,
                      const char *string,
@@ -639,7 +693,7 @@ REGEX_INTERNAL_search (struct GNUNET_DHT_Handle *dht,
   LOG (GNUNET_ERROR_TYPE_INFO, "REGEX_INTERNAL_search: %s\n", string);
   GNUNET_assert (NULL != dht);
   GNUNET_assert (NULL != callback);
-  h = GNUNET_malloc (sizeof (struct REGEX_INTERNAL_Search));
+  h = GNUNET_new (struct REGEX_INTERNAL_Search);
   h->dht = dht;
   h->description = GNUNET_strdup (string);
   h->callback = callback;
@@ -651,12 +705,17 @@ REGEX_INTERNAL_search (struct GNUNET_DHT_Handle *dht,
   /* Initialize context */
   len = strlen (string);
   size = REGEX_INTERNAL_get_first_key (string, len, &key);
-  ctx = GNUNET_malloc (sizeof (struct RegexSearchContext));
+  LOG (GNUNET_ERROR_TYPE_INFO,
+       "  initial key for %s: %s (%.*s)\n",
+       string, GNUNET_h2s (&key), size, string);
+  ctx = GNUNET_new (struct RegexSearchContext);
   ctx->position = size;
   ctx->info = h;
   GNUNET_array_append (h->contexts, h->n_contexts, ctx);
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  consumed %u bits out of %u\n", size, len);
-  LOG (GNUNET_ERROR_TYPE_INFO, "   looking for %s\n", GNUNET_h2s (&key));
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "consumed %u bits out of %u, now looking for %s\n",
+       size, len,
+       GNUNET_h2s (&key));
 
   /* Start search in DHT */
   get_h = GNUNET_DHT_get_start (h->dht,    /* handle */