-remove trailing whitespace
[oweals/gnunet.git] / src / gns / gnunet-service-gns_resolver.c
index 2ab3c9a8881713ef0dbaf423491308023776677c..ff07a6cf07727a59e14e7ea0e1689aafe89f0907 100644 (file)
@@ -41,6 +41,7 @@
 #include "gnunet_resolver_service.h"
 #include "gnunet_revocation_service.h"
 #include "gnunet_dnsparser_lib.h"
+#include "gnunet_tun_lib.h"
 #include "gnunet_gns_service.h"
 #include "gns.h"
 #include "gnunet-service-gns_resolver.h"
@@ -100,6 +101,16 @@ struct AuthorityChain
    */
   char *label;
 
+  /**
+   * label/name suggested for shortening to the authority
+   */
+  char *suggested_shortening_label;
+
+  /**
+   * Do we already try to shorten this authority?
+   */
+  int shortening_started;
+
   /**
    * #GNUNET_YES if the authority was a GNS authority,
    * #GNUNET_NO if the authority was a DNS authority.
@@ -445,6 +456,10 @@ static struct CacheOps *co_head;
  */
 static struct CacheOps *co_tail;
 
+/**
+ * Use namecache
+ */
+static int use_cache;
 
 /**
  * Global configuration.
@@ -1075,11 +1090,8 @@ handle_gns_cname_result (struct GNS_ResolverHandle *rh,
     ac->gns_authority = GNUNET_YES;
     ac->authority_info.gns_authority = rh->ac_tail->authority_info.gns_authority;
     ac->label = resolver_lookup_get_next_label (rh);
-    /* tigger shortening */
-    if (NULL != rh->shorten_key)
-      GNS_shorten_start (rh->ac_tail->label,
-                        &ac->authority_info.gns_authority,
-                        rh->shorten_key);
+    ac->suggested_shortening_label = NULL;
+    ac->shortening_started = GNUNET_NO;
     /* add AC to tail */
     GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
                                      rh->ac_tail,
@@ -1328,6 +1340,7 @@ handle_gns_resolution_result (void *cls,
 {
   struct GNS_ResolverHandle *rh = cls;
   struct AuthorityChain *ac;
+  struct AuthorityChain *shorten_ac;
   unsigned int i;
   char *cname;
   struct VpnContext *vpn_ctx;
@@ -1342,7 +1355,7 @@ handle_gns_resolution_result (void *cls,
   struct GNUNET_GNSRECORD_Data rd_new[rd_count];
   unsigned int rd_off;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
              "Resolution succeeded for `%s' in zone %s, got %u records\n",
              rh->ac_tail->label,
              GNUNET_GNSRECORD_z2s (&rh->ac_tail->authority_info.gns_authority),
@@ -1384,7 +1397,7 @@ handle_gns_resolution_result (void *cls,
        case GNUNET_GNSRECORD_TYPE_VPN:
          {
            af = (GNUNET_DNSPARSER_TYPE_A == rh->record_type) ? AF_INET : AF_INET6;
-           if (sizeof (struct GNUNET_TUN_GnsVpnRecord) <
+           if (sizeof (struct GNUNET_TUN_GnsVpnRecord) >
                rd[i].data_size)
            {
              GNUNET_break_op (0);
@@ -1401,19 +1414,26 @@ handle_gns_resolution_result (void *cls,
              GNS_resolver_lookup_cancel (rh);
              return;
            }
-           GNUNET_CRYPTO_hash (vname,
-                               strlen (vname), // FIXME: +1?
-                               &vhash);
+           GNUNET_TUN_service_name_to_hash (vname,
+                                             &vhash);
+            GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                        "Attempting VPN allocation for %s-%s (AF: %d, proto %d)\n",
+                        GNUNET_i2s (&vpn->peer),
+                        vname,
+                        (int) af,
+                        (int) ntohs (vpn->proto));
            vpn_ctx = GNUNET_new (struct VpnContext);
            rh->vpn_ctx = vpn_ctx;
            vpn_ctx->rh = rh;
            vpn_ctx->rd_data_size = GNUNET_GNSRECORD_records_get_size (rd_count,
                                                                       rd);
            vpn_ctx->rd_data = GNUNET_malloc (vpn_ctx->rd_data_size);
-           (void) GNUNET_GNSRECORD_records_serialize (rd_count,
-                                                      rd,
-                                                      vpn_ctx->rd_data_size,
-                                                      vpn_ctx->rd_data);
+            vpn_ctx->rd_count = rd_count;
+           GNUNET_assert (vpn_ctx->rd_data_size ==
+                           GNUNET_GNSRECORD_records_serialize (rd_count,
+                                                               rd,
+                                                               vpn_ctx->rd_data_size,
+                                                               vpn_ctx->rd_data));
            vpn_ctx->vpn_request = GNUNET_VPN_redirect_to_peer (vpn_handle,
                                                                af,
                                                                ntohs (vpn->proto),
@@ -1421,7 +1441,7 @@ handle_gns_resolution_result (void *cls,
                                                                &vhash,
                                                                GNUNET_TIME_relative_to_absolute (VPN_TIMEOUT),
                                                                &vpn_allocation_cb,
-                                                               rh);
+                                                               vpn_ctx);
            return;
          }
        case GNUNET_GNSRECORD_TYPE_GNS2DNS:
@@ -1433,13 +1453,14 @@ handle_gns_resolution_result (void *cls,
          }
        default:
          break;
-       }
-      }
-    }
+       } /* end: switch */
+      } /* end: for rd */
+    } /* end: name_resolution_pos */
     /* convert relative names in record values to absolute names,
        using 'scratch' array for memory allocations */
     scratch_off = 0;
     rd_off = 0;
+    shorten_ac = rh->ac_tail;
     for (i=0;i<rd_count;i++)
     {
       rd_new[rd_off] = rd[i];
@@ -1598,6 +1619,21 @@ handle_gns_resolution_result (void *cls,
            GNUNET_DNSPARSER_free_srv (srv);
        }
        break;
+
+      case GNUNET_GNSRECORD_TYPE_NICK:
+        {
+          const char *nick;
+          nick = rd[i].data;
+          if ((rd[i].data_size > 0) &&
+              (nick[rd[i].data_size -1] != '\0'))
+          {
+            GNUNET_break_op (0);
+            break;
+          }
+          if (NULL == shorten_ac->suggested_shortening_label)
+            shorten_ac->suggested_shortening_label = GNUNET_strdup (nick);
+          break;
+        }
       case GNUNET_GNSRECORD_TYPE_PKEY:
         {
          struct GNUNET_CRYPTO_EcdsaPublicKey pub;
@@ -1608,14 +1644,6 @@ handle_gns_resolution_result (void *cls,
            break;
          }
          memcpy (&pub, rd[i].data, rd[i].data_size);
-
-          /* tigger shortening */
-          if (NULL != rh->shorten_key)
-          {
-            GNS_shorten_start (rh->ac_tail->label,
-                               &pub,
-                               rh->shorten_key);
-          }
           rd_off++;
           if (GNUNET_GNSRECORD_TYPE_PKEY != rh->record_type)
           {
@@ -1627,6 +1655,8 @@ handle_gns_resolution_result (void *cls,
             ac->gns_authority = GNUNET_YES;
             ac->authority_info.gns_authority = pub;
             ac->label = GNUNET_strdup (GNUNET_GNS_MASTERZONE_STR);
+            ac->suggested_shortening_label = NULL;
+            ac->shortening_started = GNUNET_NO;
             GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
                                               rh->ac_tail,
                                               ac);
@@ -1646,7 +1676,24 @@ handle_gns_resolution_result (void *cls,
       default:
        rd_off++;
        break;
-      }
+      } /* end: switch */
+    } /* end: for rd_count */
+
+    /* trigger shortening */
+    if ((NULL != rh->shorten_key) &&
+        (NULL != shorten_ac) &&
+        (GNUNET_NO == shorten_ac->shortening_started) &&
+        (NULL != shorten_ac->suggested_shortening_label))
+    {
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                    "Start shortening for label `%s' based on nick `%s'\n",
+                    shorten_ac->label,
+                    shorten_ac->suggested_shortening_label);
+        shorten_ac->shortening_started = GNUNET_YES;
+        GNS_shorten_start (shorten_ac->label,
+                         shorten_ac->suggested_shortening_label,
+                         &shorten_ac->authority_info.gns_authority,
+                         rh->shorten_key);
     }
 
     /* yes, we are done, return result */
@@ -1678,15 +1725,12 @@ handle_gns_resolution_result (void *cls,
       ac = GNUNET_new (struct AuthorityChain);
       ac->rh = rh;
       ac->gns_authority = GNUNET_YES;
+      ac->suggested_shortening_label = NULL;
+      ac->shortening_started = GNUNET_NO;
       memcpy (&ac->authority_info.gns_authority,
              rd[i].data,
              sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
       ac->label = resolver_lookup_get_next_label (rh);
-      /* tigger shortening */
-      if (NULL != rh->shorten_key)
-       GNS_shorten_start (rh->ac_tail->label,
-                          &ac->authority_info.gns_authority,
-                          rh->shorten_key);
       /* add AC to tail */
       GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
                                        rh->ac_tail,
@@ -1882,7 +1926,7 @@ handle_dht_response (void *cls,
   }
   /* Cache well-formed blocks */
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Caching response from the DHT in namestore\n");
+             "Caching response from the DHT in namecache\n");
   co = GNUNET_new (struct CacheOps);
   co->namecache_qe_cache = GNUNET_NAMECACHE_block_cache (namecache_handle,
                                                         block,
@@ -1895,57 +1939,152 @@ handle_dht_response (void *cls,
 
 
 /**
- * Process a record that was stored in the namestore.
+ * Initiate a DHT query for a set of GNS records.
+ *
+ * @param rh resolution handle
+ * @param query key to use in the DHT lookup
+ */
+static void
+start_dht_request (struct GNS_ResolverHandle *rh,
+                   const struct GNUNET_HashCode *query)
+{
+  struct GNS_ResolverHandle *rx;
+
+  GNUNET_assert (NULL == rh->get_handle);
+  rh->get_handle = GNUNET_DHT_get_start (dht_handle,
+                                         GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
+                                         query,
+                                         DHT_GNS_REPLICATION_LEVEL,
+                                         GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
+                                         NULL, 0,
+                                         &handle_dht_response, rh);
+  rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
+                                                    rh,
+                                                    GNUNET_TIME_absolute_get ().abs_value_us);
+  if (GNUNET_CONTAINER_heap_get_size (dht_lookup_heap) > max_allowed_background_queries)
+  {
+    /* fail longest-standing DHT request */
+    rx = GNUNET_CONTAINER_heap_peek (dht_lookup_heap);
+    GNUNET_assert (NULL != rx);
+    rx->proc (rx->proc_cls, 0, NULL);
+    GNS_resolver_lookup_cancel (rx);
+  }
+}
+
+
+/**
+ * Process a records that were decrypted from a block that we
+ * got from the namecache.  If the desired record type is not
+ * included, we should query the DHT.  Otherwise, we should
+ * simply call #handle_gns_resolution_result().
  *
  * @param cls closure with the `struct GNS_ResolverHandle`
- * @param block block that was stored in the namestore
+ * @param rd_count number of entries in @a rd array
+ * @param rd array of records with data to store
  */
 static void
-handle_namestore_block_response (void *cls,
+handle_gns_namecache_resolution_result (void *cls,
+                                        unsigned int rd_count,
+                                        const struct GNUNET_GNSRECORD_Data *rd)
+{
+  struct GNS_ResolverHandle *rh = cls;
+  unsigned int i;
+  int found;
+
+  found = GNUNET_NO;
+  for (i=0;i<rd_count;i++)
+  {
+    if (rd[i].record_type == rh->record_type)
+    {
+      found = GNUNET_YES;
+      break;
+    }
+    switch (rd[i].record_type)
+    {
+    case GNUNET_GNSRECORD_TYPE_VPN:
+      if ( (GNUNET_DNSPARSER_TYPE_A == rh->record_type) ||
+           (GNUNET_DNSPARSER_TYPE_AAAA == rh->record_type) )
+      {
+        found = GNUNET_YES;
+        break;
+      }
+      break;
+    case GNUNET_DNSPARSER_TYPE_CNAME:
+    case GNUNET_GNSRECORD_TYPE_PKEY:
+    case GNUNET_GNSRECORD_TYPE_GNS2DNS:
+      /* delegations always count as 'found' */
+      found = GNUNET_YES;
+      break;
+    default:
+      break;
+    }
+  }
+  if (GNUNET_YES == found)
+  {
+    handle_gns_resolution_result (rh,
+                                  rd_count,
+                                  rd);
+  }
+  else
+  {
+    /* try DHT */
+    struct AuthorityChain *ac = rh->ac_tail;
+    const char *label = ac->label;
+    const struct GNUNET_CRYPTO_EcdsaPublicKey *auth = &ac->authority_info.gns_authority;
+    struct GNUNET_HashCode query;
+
+    GNUNET_GNSRECORD_query_from_public_key (auth,
+                                            label,
+                                            &query);
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Starting DHT lookup for `%s' in zone `%s' under key `%s'\n",
+                ac->label,
+                GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority),
+                GNUNET_h2s (&query));
+    start_dht_request (rh, &query);
+  }
+}
+
+
+/**
+ * Process a record that was stored in the namecache.
+ *
+ * @param cls closure with the `struct GNS_ResolverHandle`
+ * @param block block that was stored in the namecache
+ */
+static void
+handle_namecache_block_response (void *cls,
                                 const struct GNUNET_GNSRECORD_Block *block)
 {
   struct GNS_ResolverHandle *rh = cls;
-  struct GNS_ResolverHandle *rx;
   struct AuthorityChain *ac = rh->ac_tail;
   const char *label = ac->label;
   const struct GNUNET_CRYPTO_EcdsaPublicKey *auth = &ac->authority_info.gns_authority;
   struct GNUNET_HashCode query;
 
-  GNUNET_GNSRECORD_query_from_public_key (auth,
-                                         label,
-                                         &query);
   GNUNET_assert (NULL != rh->namecache_qe);
   rh->namecache_qe = NULL;
   if ( (GNUNET_NO == rh->only_cached) &&
        ( (NULL == block) ||
         (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (block->expiration_time)).rel_value_us) ) )
   {
-    /* Namestore knows nothing; try DHT lookup */
+    /* namecache knows nothing; try DHT lookup */
+    GNUNET_GNSRECORD_query_from_public_key (auth,
+                                            label,
+                                            &query);
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-               "Starting DHT lookup for `%s' in zone %s\n",
-               ac->label,
-               GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
-    GNUNET_assert (NULL == rh->get_handle);
-    rh->get_handle = GNUNET_DHT_get_start (dht_handle,
-                                          GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
-                                          &query,
-                                          DHT_GNS_REPLICATION_LEVEL,
-                                          GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
-                                          NULL, 0,
-                                          &handle_dht_response, rh);
-    rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
-                                                     rh,
-                                                     GNUNET_TIME_absolute_get ().abs_value_us);
-    if (GNUNET_CONTAINER_heap_get_size (dht_lookup_heap) > max_allowed_background_queries)
-    {
-      /* fail longest-standing DHT request */
-      rx = GNUNET_CONTAINER_heap_peek (dht_lookup_heap);
-      GNUNET_assert (NULL != rx);
-      rx->proc (rx->proc_cls, 0, NULL);
-      GNS_resolver_lookup_cancel (rx);
-    }
+                "Starting DHT lookup for `%s' in zone `%s' under key `%s'\n",
+                ac->label,
+                GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority),
+                GNUNET_h2s (&query));
+    start_dht_request (rh, &query);
     return;
   }
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Received result from namecache for label `%s'\n",
+              ac->label);
+
   if ( (NULL == block) ||
        (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (block->expiration_time)).rel_value_us) )
   {
@@ -1962,24 +2101,32 @@ handle_namestore_block_response (void *cls,
       GNUNET_GNSRECORD_block_decrypt (block,
                                      auth,
                                      label,
-                                     &handle_gns_resolution_result,
+                                     &handle_gns_namecache_resolution_result,
                                      rh))
   {
     GNUNET_break_op (0); /* block was ill-formed */
-    rh->proc (rh->proc_cls, 0, NULL);
-    GNS_resolver_lookup_cancel (rh);
+    /* try DHT instead */
+    GNUNET_GNSRECORD_query_from_public_key (auth,
+                                            label,
+                                            &query);
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Starting DHT lookup for `%s' in zone `%s' under key `%s'\n",
+                ac->label,
+                GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority),
+                GNUNET_h2s (&query));
+    start_dht_request (rh, &query);
     return;
   }
 }
 
 
 /**
- * Lookup tail of our authority chain in the namestore.
+ * Lookup tail of our authority chain in the namecache.
  *
  * @param rh query we are processing
  */
 static void
-recursive_gns_resolution_namestore (struct GNS_ResolverHandle *rh)
+recursive_gns_resolution_namecache (struct GNS_ResolverHandle *rh)
 {
   struct AuthorityChain *ac = rh->ac_tail;
   struct GNUNET_HashCode query;
@@ -1991,11 +2138,18 @@ recursive_gns_resolution_namestore (struct GNS_ResolverHandle *rh)
   GNUNET_GNSRECORD_query_from_public_key (&ac->authority_info.gns_authority,
                                          ac->label,
                                          &query);
-  rh->namecache_qe = GNUNET_NAMECACHE_lookup_block (namecache_handle,
+  if (GNUNET_YES == use_cache)
+  {
+    rh->namecache_qe = GNUNET_NAMECACHE_lookup_block (namecache_handle,
                                                    &query,
-                                                   &handle_namestore_block_response,
+                                                   &handle_namecache_block_response,
                                                    rh);
-  GNUNET_assert (NULL != rh->namecache_qe);
+    GNUNET_assert (NULL != rh->namecache_qe);
+  }
+  else
+  {
+    start_dht_request (rh, &query);
+  }
 }
 
 
@@ -2022,7 +2176,7 @@ handle_revocation_result (void *cls,
     GNS_resolver_lookup_cancel (rh);
     return;
   }
-  recursive_gns_resolution_namestore (rh);
+  recursive_gns_resolution_namecache (rh);
 }
 
 
@@ -2179,6 +2333,7 @@ start_resolver_lookup (struct GNS_ResolverHandle *rh)
   ac = GNUNET_new (struct AuthorityChain);
   ac->rh = rh;
   ac->label = resolver_lookup_get_next_label (rh);
+  ac->suggested_shortening_label = NULL;
   if (NULL == ac->label)
     /* name was just "gnu", so we default to label '+' */
     ac->label = GNUNET_strdup (GNUNET_GNS_MASTERZONE_STR);
@@ -2262,6 +2417,7 @@ GNS_resolver_lookup_cancel (struct GNS_ResolverHandle *rh)
                                 rh->ac_tail,
                                 ac);
     GNUNET_free (ac->label);
+    GNUNET_free_non_null (ac->suggested_shortening_label);
     GNUNET_free (ac);
   }
   if (NULL != rh->g2dc)
@@ -2362,6 +2518,13 @@ GNS_resolver_init (struct GNUNET_NAMECACHE_Handle *nc,
   dht_lookup_heap =
     GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
   max_allowed_background_queries = max_bg_queries;
+  if (GNUNET_SYSERR == (use_cache = GNUNET_CONFIGURATION_get_value_yesno (c,
+                                             "gns",
+                                             "USE_CACHE")))
+    use_cache = GNUNET_YES;
+  if (GNUNET_NO == use_cache)
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Namecache disabled\n");
+
   if (GNUNET_OK !=
       GNUNET_CONFIGURATION_get_value_string (c,
                                             "gns",