- cancel SYNACK retry task when forced to SYNACK by an incoming SYN
[oweals/gnunet.git] / src / mesh / gnunet-service-mesh_dht.c
index a194bd0b73b8efb00e15761f7326a630358787a9..01fb4a30f2f59bc82d4ac62faa78f9a5006b3c9a 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"
+#include "gnunet-service-mesh_hello.h"
 
-#define MESH_DEBUG_DHT          GNUNET_NO
-
-#if MESH_DEBUG_DHT
-#define DEBUG_DHT(...) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
-#else
-#define DEBUG_DHT(...)
-#endif
-
-#define LOG (level, ...) GNUNET_log_from ("mesh-dht", level, __VA_ARGS__)
+#define LOG(level, ...) GNUNET_log_from (level,"mesh-dht",__VA_ARGS__)
 
 
-
-/**
- * Callback called on each path found over the DHT.
- *
- * @param cls Closure.
- * @param path An unchecked, unoptimized path to the target node.
- *             After callback will no longer be valid!
- */
-typedef void (*GMD_search_callback) (void *cls,
-                                     const struct MeshPeerPath *path);
-
 /******************************************************************************/
 /********************************   STRUCTS  **********************************/
 /******************************************************************************/
@@ -67,6 +50,9 @@ struct GMD_search_handle
 
   /** Provided closure. */
   void *cls;
+
+  /** Peer ID searched for */
+  GNUNET_PEER_Id peer_id;
 };
 
 
@@ -74,6 +60,21 @@ struct GMD_search_handle
 /*******************************   GLOBALS  ***********************************/
 /******************************************************************************/
 
+/**
+ * Global handle to the statistics service.
+ */
+extern struct GNUNET_STATISTICS_Handle *stats;
+
+/**
+ * Own ID (short value).
+ */
+extern GNUNET_PEER_Id myid;
+
+/**
+ * Own ID (full value).
+ */
+extern struct GNUNET_PeerIdentity my_full_id;
+
 /**
  * Handle to use DHT.
  */
@@ -95,20 +96,9 @@ static unsigned long long dht_replication_level;
 static GNUNET_SCHEDULER_TaskIdentifier announce_id_task;
 
 /**
- * Own ID (short value).
+ * GET requests to stop on shutdown.
  */
-static GNUNET_PEER_Id short_id;
-
-/**
- * Own ID (full value).
- */
-static struct GNUNET_PeerIdentity *full_id;
-
-/**
- * Own private key.
- */
-static struct GNUNET_CRYPTO_EccPrivateKey *private_key;
-
+static struct GNUNET_CONTAINER_MultiHashMap32 *get_requests;
 
 /******************************************************************************/
 /********************************   STATIC  ***********************************/
@@ -120,6 +110,8 @@ static struct GNUNET_CRYPTO_EccPrivateKey *private_key;
  * to obtain a local peer -> destination path and interning the peer ids.
  *
  * @return Newly allocated and created path
+ *
+ * FIXME refactor and use build_path_from_peer_ids
  */
 static struct MeshPeerPath *
 path_build_from_dht (const struct GNUNET_PeerIdentity *get_path,
@@ -135,18 +127,18 @@ path_build_from_dht (const struct GNUNET_PeerIdentity *get_path,
   p->peers[0] = myid;
   GNUNET_PEER_change_rc (myid, 1);
   i = get_path_length;
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "   GET has %d hops.\n", i);
+  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])
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "   Optimizing 1 hop out.\n");
+      LOG (GNUNET_ERROR_TYPE_DEBUG, "   Optimizing 1 hop out.\n");
       GNUNET_PEER_change_rc (id, -1);
     }
     else
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "   Adding from GET: %s.\n",
+      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);
@@ -154,7 +146,7 @@ path_build_from_dht (const struct GNUNET_PeerIdentity *get_path,
     }
   }
   i = put_path_length;
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "   PUT has %d hops.\n", i);
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "   PUT has %d hops.\n", i);
   for (i--; i >= 0; i--)
   {
     id = GNUNET_PEER_intern (&put_path[i]);
@@ -168,12 +160,12 @@ path_build_from_dht (const struct GNUNET_PeerIdentity *get_path,
     }
     if (p->length > 0 && id == p->peers[p->length - 1])
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "   Optimizing 1 hop out.\n");
+      LOG (GNUNET_ERROR_TYPE_DEBUG, "   Optimizing 1 hop out.\n");
       GNUNET_PEER_change_rc (id, -1);
     }
     else
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "   Adding from PUT: %s.\n",
+      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);
@@ -182,19 +174,19 @@ path_build_from_dht (const struct GNUNET_PeerIdentity *get_path,
   }
 #if MESH_DEBUG
   if (get_path_length > 0)
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "   (first of GET: %s)\n",
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "   (first of GET: %s)\n",
                 GNUNET_i2s (&get_path[0]));
   if (put_path_length > 0)
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "   (first of PUT: %s)\n",
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "   (first of PUT: %s)\n",
                 GNUNET_i2s (&put_path[0]));
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "   In total: %d hops\n",
+  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);
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "       %u: %s\n", p->peers[i],
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "       %u: %s\n", p->peers[i],
                 GNUNET_i2s (&peer_id));
   }
 #endif
@@ -228,13 +220,23 @@ dht_get_id_handler (void *cls, struct GNUNET_TIME_Absolute exp,
                     size_t size, const void *data)
 {
   struct GMD_search_handle *h = cls;
+  struct GNUNET_HELLO_Message *hello;
   struct MeshPeerPath *p;
+  struct MeshPeer *peer;
+  char *s;
 
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Got results!\n");
   p = path_build_from_dht (get_path, get_path_length,
                            put_path, put_path_length);
+  s = path_2s (p);
+  LOG (GNUNET_ERROR_TYPE_INFO, "Got path from DHT: %s\n", s);
+  GNUNET_free_non_null (s);
+  peer = GMP_get_short (p->peers[p->length - 1]);
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "Got HELLO for %s\n", GMP_2s (peer));
   h->callback (h->cls, p);
   path_destroy (p);
+  hello = (struct GNUNET_HELLO_Message *) data;
+  GMP_set_hello (peer, hello);
+  GMP_try_connect (peer);
   return;
 }
 
@@ -248,37 +250,75 @@ dht_get_id_handler (void *cls, struct GNUNET_TIME_Absolute exp,
 static void
 announce_id (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
-  struct PBlock block;
   struct GNUNET_HashCode phash;
+  const struct GNUNET_HELLO_Message *hello;
+  size_t size;
+  struct GNUNET_TIME_Absolute expiration;
+  struct GNUNET_TIME_Relative retry_time;
 
   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
   {
     announce_id_task = GNUNET_SCHEDULER_NO_TASK;
     return;
   }
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "Announce ID\n");
+
   /* TODO
    * - Set data expiration in function of X
    * - Adapt X to churn
    */
-  DEBUG_DHT ("DHT_put for ID %s started.\n", GNUNET_i2s (id));
+  hello = GMH_get_mine ();
+  if (NULL == hello || (size = GNUNET_HELLO_size (hello)) == 0)
+  {
+    /* Peerinfo gave us no hello yet, try again in a second. */
+    announce_id_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
+                                                     &announce_id, cls);
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "  no hello, waiting!\n");
+    return;
+  }
+  expiration = GNUNET_HELLO_get_last_expiration (hello);
+  retry_time = GNUNET_TIME_absolute_get_remaining (expiration);
 
-  block.id = *full_id;
-  GNUNET_CRYPTO_hash (full_id, sizeof (struct GNUNET_PeerIdentity), &phash);
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "Hello %p size: %u\n", hello, size);
+  memset (&phash, 0, sizeof (phash));
+  memcpy (&phash, &my_full_id, sizeof (my_full_id));
   GNUNET_DHT_put (dht_handle,   /* DHT handle */
                   &phash,       /* Key to use */
                   dht_replication_level,     /* Replication level */
-                  GNUNET_DHT_RO_RECORD_ROUTE | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,    /* DHT options */
-                  GNUNET_BLOCK_TYPE_MESH_PEER,       /* Block type */
-                  sizeof (block),  /* Size of the data */
-                  (const char *) &block, /* Data itself */
-                  GNUNET_TIME_UNIT_FOREVER_ABS,  /* Data expiration */
-                  GNUNET_TIME_UNIT_FOREVER_REL, /* Retry time */
+                  GNUNET_DHT_RO_RECORD_ROUTE
+                  | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,    /* DHT options */
+                  GNUNET_BLOCK_TYPE_DHT_HELLO,       /* Block type */
+                  size,  /* Size of the data */
+                  (const char *) hello, /* Data itself */
+                  expiration,  /* Data expiration */
+                  retry_time, /* Retry time */
                   NULL,         /* Continuation */
                   NULL);        /* Continuation closure */
   announce_id_task =
       GNUNET_SCHEDULER_add_delayed (id_announce_time, &announce_id, cls);
 }
 
+/**
+ * Iterator over hash map entries and stop GET requests before disconnecting
+ * from the DHT.
+ *
+ * @param cls Closure (unused)
+ * @param key Current peer ID.
+ * @param value Value in the hash map (GMD_search_handle).
+ *
+ * @return #GNUNET_YES, we should continue to iterate,
+ */
+int
+stop_get (void *cls,
+          uint32_t key,
+          void *value)
+{
+  struct GMD_search_handle *h = value;
+
+  GMD_search_stop (h);
+  return GNUNET_YES;
+}
+
 
 /******************************************************************************/
 /********************************    API    ***********************************/
@@ -288,13 +328,11 @@ 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,
-          struct GNUNET_PeerIdentity *peer_id)
+GMD_init (const struct GNUNET_CONFIGURATION_Handle *c)
 {
-  full_id = peer_id;
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n");
   if (GNUNET_OK !=
       GNUNET_CONFIGURATION_get_value_number (c, "MESH", "DHT_REPLICATION_LEVEL",
                                              &dht_replication_level))
@@ -321,6 +359,7 @@ GMD_init (const struct GNUNET_CONFIGURATION_Handle *c,
   }
 
   announce_id_task = GNUNET_SCHEDULER_add_now (&announce_id, NULL);
+  get_requests = GNUNET_CONTAINER_multihashmap32_create (32);
 }
 
 
@@ -328,8 +367,10 @@ GMD_init (const struct GNUNET_CONFIGURATION_Handle *c,
  * Shut down the DHT subsystem.
  */
 void
-GMD_shutdown(void )
+GMD_shutdown (void)
 {
+  GNUNET_CONTAINER_multihashmap32_iterate (get_requests, &stop_get, NULL);
+  GNUNET_CONTAINER_multihashmap32_destroy (get_requests);
   if (dht_handle != NULL)
   {
     GNUNET_DHT_disconnect (dht_handle);
@@ -351,11 +392,14 @@ GMD_search (const struct GNUNET_PeerIdentity *peer_id,
 
   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);
+  memset (&phash, 0, sizeof (phash));
+  memcpy (&phash, peer_id, sizeof (*peer_id));
   h = GNUNET_new (struct GMD_search_handle);
+  h->peer_id = GNUNET_PEER_intern (peer_id);
+  h->callback = callback;
   h->cls = cls;
   h->dhtget = GNUNET_DHT_get_start (dht_handle,    /* handle */
-                                    GNUNET_BLOCK_TYPE_MESH_PEER, /* type */
+                                    GNUNET_BLOCK_TYPE_DHT_HELLO, /* type */
                                     &phash,     /* key to search */
                                     dht_replication_level, /* replication level */
                                     GNUNET_DHT_RO_RECORD_ROUTE |
@@ -363,12 +407,17 @@ GMD_search (const struct GNUNET_PeerIdentity *peer_id,
                                     NULL,       /* xquery */
                                     0,     /* xquery bits */
                                     &dht_get_id_handler, h);
+  GNUNET_CONTAINER_multihashmap32_put (get_requests, h->peer_id, h,
+                                       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
   return h;
 }
 
 void
 GMD_search_stop (struct GMD_search_handle *h)
 {
+  GNUNET_break (GNUNET_OK ==
+                GNUNET_CONTAINER_multihashmap32_remove (get_requests,
+                                                        h->peer_id, h));
   GNUNET_DHT_get_stop (h->dhtget);
   GNUNET_free (h);
-}
\ No newline at end of file
+}