-bump name to 97
[oweals/gnunet.git] / src / mesh / gnunet-service-mesh_dht.c
index 710b95f45e42ae72abaca237d706b6154779faa7..3beb2da8a85bc3bebe822a8a8166badfd44ccb4d 100644 (file)
 #include "gnunet_util_lib.h"
 
 #include "gnunet_dht_service.h"
+#include "gnunet_statistics_service.h"
 
+#include "mesh_path.h"
 #include "gnunet-service-mesh_dht.h"
 #include "gnunet-service-mesh_peer.h"
 
-#define MESH_DEBUG_DHT          GNUNET_NO
+#define LOG(level, ...) GNUNET_log_from (level,"mesh-dht",__VA_ARGS__)
 
-#if MESH_DEBUG_DHT
-#define DEBUG_DHT(...) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
-#else
-#define DEBUG_DHT(...)
-#endif
 
 /******************************************************************************/
 /********************************   STRUCTS  **********************************/
 /******************************************************************************/
 
+/**
+ * Handle for DHT searches.
+ */
+struct GMD_search_handle
+{
+  /** DHT_GET handle. */
+  struct GNUNET_DHT_GetHandle *dhtget;
+
+  /** Provided callback to call when a path is found. */
+  GMD_search_callback callback;
 
+  /** Provided closure. */
+  void *cls;
+};
 
 
 /******************************************************************************/
 /*******************************   GLOBALS  ***********************************/
 /******************************************************************************/
 
+/**
+ * Global handle to the statistics service.
+ */
+extern struct GNUNET_STATISTICS_Handle *stats;
+
 /**
  * Handle to use DHT.
  */
@@ -66,10 +81,15 @@ static unsigned long long dht_replication_level;
  */
 static GNUNET_SCHEDULER_TaskIdentifier announce_id_task;
 
+/**
+ * Own ID (short value).
+ */
+static GNUNET_PEER_Id short_id;
+
 /**
  * Own ID (full value).
  */
-static struct GNUNET_PeerIdentity *id;
+static struct GNUNET_PeerIdentity *full_id;
 
 /**
  * Own private key.
@@ -82,6 +102,130 @@ static struct GNUNET_CRYPTO_EccPrivateKey *private_key;
 /******************************************************************************/
 
 
+/**
+ * Build a PeerPath from the paths returned from the DHT, reversing the paths
+ * to obtain a local peer -> destination path and interning the peer ids.
+ *
+ * @return Newly allocated and created path
+ */
+static struct MeshPeerPath *
+path_build_from_dht (const struct GNUNET_PeerIdentity *get_path,
+                     unsigned int get_path_length,
+                     const struct GNUNET_PeerIdentity *put_path,
+                     unsigned int put_path_length)
+{
+  struct MeshPeerPath *p;
+  GNUNET_PEER_Id id;
+  int i;
+
+  p = path_new (1);
+  p->peers[0] = myid;
+  GNUNET_PEER_change_rc (myid, 1);
+  i = get_path_length;
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "   GET has %d hops.\n", i);
+  for (i--; i >= 0; i--)
+  {
+    id = GNUNET_PEER_intern (&get_path[i]);
+    if (p->length > 0 && id == p->peers[p->length - 1])
+    {
+      LOG (GNUNET_ERROR_TYPE_DEBUG, "   Optimizing 1 hop out.\n");
+      GNUNET_PEER_change_rc (id, -1);
+    }
+    else
+    {
+      LOG (GNUNET_ERROR_TYPE_DEBUG, "   Adding from GET: %s.\n",
+                  GNUNET_i2s (&get_path[i]));
+      p->length++;
+      p->peers = GNUNET_realloc (p->peers, sizeof (GNUNET_PEER_Id) * p->length);
+      p->peers[p->length - 1] = id;
+    }
+  }
+  i = put_path_length;
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "   PUT has %d hops.\n", i);
+  for (i--; i >= 0; i--)
+  {
+    id = GNUNET_PEER_intern (&put_path[i]);
+    if (id == myid)
+    {
+      /* PUT path went through us, so discard the path up until now and start
+       * from here to get a much shorter (and loop-free) path.
+       */
+      path_destroy (p);
+      p = path_new (0);
+    }
+    if (p->length > 0 && id == p->peers[p->length - 1])
+    {
+      LOG (GNUNET_ERROR_TYPE_DEBUG, "   Optimizing 1 hop out.\n");
+      GNUNET_PEER_change_rc (id, -1);
+    }
+    else
+    {
+      LOG (GNUNET_ERROR_TYPE_DEBUG, "   Adding from PUT: %s.\n",
+                  GNUNET_i2s (&put_path[i]));
+      p->length++;
+      p->peers = GNUNET_realloc (p->peers, sizeof (GNUNET_PEER_Id) * p->length);
+      p->peers[p->length - 1] = id;
+    }
+  }
+#if MESH_DEBUG
+  if (get_path_length > 0)
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "   (first of GET: %s)\n",
+                GNUNET_i2s (&get_path[0]));
+  if (put_path_length > 0)
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "   (first of PUT: %s)\n",
+                GNUNET_i2s (&put_path[0]));
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "   In total: %d hops\n",
+              p->length);
+  for (i = 0; i < p->length; i++)
+  {
+    struct GNUNET_PeerIdentity peer_id;
+
+    GNUNET_PEER_resolve (p->peers[i], &peer_id);
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "       %u: %s\n", p->peers[i],
+                GNUNET_i2s (&peer_id));
+  }
+#endif
+  return p;
+}
+
+
+/**
+ * Function to process paths received for a new peer addition. The recorded
+ * paths form the initial tunnel, which can be optimized later.
+ * Called on each result obtained for the DHT search.
+ *
+ * @param cls closure
+ * @param exp when will this value expire
+ * @param key key of the result
+ * @param get_path path of the get request
+ * @param get_path_length lenght of get_path
+ * @param put_path path of the put request
+ * @param put_path_length length of the put_path
+ * @param type type of the result
+ * @param size number of bytes in data
+ * @param data pointer to the result data
+ */
+static void
+dht_get_id_handler (void *cls, struct GNUNET_TIME_Absolute exp,
+                    const struct GNUNET_HashCode * key,
+                    const struct GNUNET_PeerIdentity *get_path,
+                    unsigned int get_path_length,
+                    const struct GNUNET_PeerIdentity *put_path,
+                    unsigned int put_path_length, enum GNUNET_BLOCK_Type type,
+                    size_t size, const void *data)
+{
+  struct GMD_search_handle *h = cls;
+  struct MeshPeerPath *p;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "Got results!\n");
+  p = path_build_from_dht (get_path, get_path_length,
+                           put_path, put_path_length);
+  h->callback (h->cls, p);
+  path_destroy (p);
+  return;
+}
+
+
 /**
  * Periodically announce self id in the DHT
  *
@@ -99,14 +243,13 @@ announce_id (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
     announce_id_task = GNUNET_SCHEDULER_NO_TASK;
     return;
   }
+
   /* TODO
    * - Set data expiration in function of X
    * - Adapt X to churn
    */
-  DEBUG_DHT ("DHT_put for ID %s started.\n", GNUNET_i2s (&my_full_id));
-
-  block.id = my_full_id;
-  GNUNET_CRYPTO_hash (&my_full_id, sizeof (struct GNUNET_PeerIdentity), &phash);
+  block.id = *full_id;
+  GNUNET_CRYPTO_hash (full_id, sizeof (struct GNUNET_PeerIdentity), &phash);
   GNUNET_DHT_put (dht_handle,   /* DHT handle */
                   &phash,       /* Key to use */
                   dht_replication_level,     /* Replication level */
@@ -131,15 +274,18 @@ announce_id (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  * Initialize the DHT subsystem.
  *
  * @param c Configuration.
+ * @param peer_id Local peer ID (must remain valid during all execution time).
  */
 void
-GMD_init (const struct GNUNET_CONFIGURATION_Handle *c)
+GMD_init (const struct GNUNET_CONFIGURATION_Handle *c,
+          struct GNUNET_PeerIdentity *peer_id)
 {
+  full_id = peer_id;
   if (GNUNET_OK !=
       GNUNET_CONFIGURATION_get_value_number (c, "MESH", "DHT_REPLICATION_LEVEL",
                                              &dht_replication_level))
   {
-    GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
+    LOG_config_invalid (GNUNET_ERROR_TYPE_WARNING,
                                "MESH", "DHT_REPLICATION_LEVEL", "USING DEFAULT");
     dht_replication_level = 3;
   }
@@ -148,7 +294,7 @@ GMD_init (const struct GNUNET_CONFIGURATION_Handle *c)
       GNUNET_CONFIGURATION_get_value_time (c, "MESH", "ID_ANNOUNCE_TIME",
                                            &id_announce_time))
   {
-    GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+    LOG_config_invalid (GNUNET_ERROR_TYPE_ERROR,
                                "MESH", "ID_ANNOUNCE_TIME", "MISSING");
     GNUNET_SCHEDULER_shutdown ();
     return;
@@ -160,7 +306,7 @@ GMD_init (const struct GNUNET_CONFIGURATION_Handle *c)
     GNUNET_break (0);
   }
 
-  announce_id_task = GNUNET_SCHEDULER_add_now (&announce_id, cls);
+  announce_id_task = GNUNET_SCHEDULER_add_now (&announce_id, NULL);
 }
 
 
@@ -181,3 +327,34 @@ GMD_shutdown(void )
     announce_id_task = GNUNET_SCHEDULER_NO_TASK;
   }
 }
+
+struct GMD_search_handle *
+GMD_search (const struct GNUNET_PeerIdentity *peer_id,
+            GMD_search_callback callback, void *cls)
+{
+  struct GNUNET_HashCode phash;
+  struct GMD_search_handle *h;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "  Starting DHT GET for peer %s\n", GNUNET_i2s (peer_id));
+  GNUNET_CRYPTO_hash (peer_id, sizeof (struct GNUNET_PeerIdentity), &phash);
+  h = GNUNET_new (struct GMD_search_handle);
+  h->cls = cls;
+  h->dhtget = GNUNET_DHT_get_start (dht_handle,    /* handle */
+                                    GNUNET_BLOCK_TYPE_MESH_PEER, /* type */
+                                    &phash,     /* key to search */
+                                    dht_replication_level, /* replication level */
+                                    GNUNET_DHT_RO_RECORD_ROUTE |
+                                    GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
+                                    NULL,       /* xquery */
+                                    0,     /* xquery bits */
+                                    &dht_get_id_handler, h);
+  return h;
+}
+
+void
+GMD_search_stop (struct GMD_search_handle *h)
+{
+  GNUNET_DHT_get_stop (h->dhtget);
+  GNUNET_free (h);
+}
\ No newline at end of file