pass only CadetTunnelAxolotl if it suffices, preparation for having ambiguous KX...
[oweals/gnunet.git] / src / cadet / gnunet-service-cadet-new_peer.c
index fe344fcbf0f53936fd48ada6ed32fca48dfe3221..180fdab54037de28858a2ef38e4d228f2700fe06 100644 (file)
@@ -25,6 +25,7 @@
  * @author Christian Grothoff
  *
  * TODO:
+ * - timeout for routes
  * - optimize stopping/restarting DHT search to situations
  *   where we actually need it (i.e. not if we have a direct connection,
  *   or if we already have plenty of good short ones, or maybe even
@@ -40,7 +41,6 @@
 #include "gnunet_core_service.h"
 #include "gnunet_statistics_service.h"
 #include "cadet_protocol.h"
-#include "cadet_path.h"
 #include "gnunet-service-cadet-new.h"
 #include "gnunet-service-cadet-new_connection.h"
 #include "gnunet-service-cadet-new_dht.h"
@@ -257,7 +257,8 @@ destroy_peer (void *cls)
   cp->destroy_task = NULL;
   GNUNET_assert (NULL == cp->t);
   GNUNET_assert (NULL == cp->core_mq);
-  GNUNET_assert (0 == cp->path_dll_length);
+  for (unsigned int i=0;i<cp->path_dll_length;i++)
+    GNUNET_assert (NULL == cp->path_heads[i]);
   GNUNET_assert (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections));
   GNUNET_assert (GNUNET_YES ==
                  GNUNET_CONTAINER_multipeermap_remove (peers,
@@ -284,7 +285,11 @@ destroy_peer (void *cls)
     cp->connectivity_suggestion = NULL;
   }
   GNUNET_CONTAINER_multishortmap_destroy (cp->connections);
-  GNUNET_CONTAINER_heap_destroy (cp->path_heap);
+  if (NULL != cp->path_heap)
+  {
+    GNUNET_CONTAINER_heap_destroy (cp->path_heap);
+    cp->path_heap = NULL;
+  }
   GNUNET_free_non_null (cp->hello);
   /* Peer should not be freed if paths exist; if there are no paths,
      there ought to be no connections, and without connections, no
@@ -418,8 +423,9 @@ consider_peer_destroy (struct CadetPeer *cp)
                                                      cp);
     return;
   }
-  if (0 < cp->path_dll_length)
-    return; /* still relevant! */
+  for (unsigned int i=0;i<cp->path_dll_length;i++)
+    if (NULL != cp->path_heads[i])
+      return; /* still relevant! */
   if (NULL != cp->hello)
   {
     /* relevant only until HELLO expires */
@@ -497,6 +503,34 @@ GCP_set_mq (struct CadetPeer *cp,
 }
 
 
+/**
+ * Debug function should NEVER return true in production code, useful to
+ * simulate losses for testcases.
+ *
+ * @return #GNUNET_YES or #GNUNET_NO with the decision to drop.
+ */
+static int
+should_I_drop (void)
+{
+  if (0 == drop_percent)
+    return GNUNET_NO;
+  if (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
+                                101) < drop_percent)
+    return GNUNET_YES;
+  return GNUNET_NO;
+}
+
+
+/**
+ * Function called when CORE took one of the messages from
+ * a message queue manager and transmitted it.
+ *
+ * @param cls the `struct CadetPeeer` where we made progress
+ */
+static void
+mqm_send_done (void *cls);
+
+
 /**
  * Transmit current envelope from this @a mqm.
  *
@@ -507,10 +541,6 @@ mqm_execute (struct GCP_MessageQueueManager *mqm)
 {
   struct CadetPeer *cp = mqm->cp;
 
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Sending to peer %s from MQM %p\n",
-       GCP_2s (cp),
-       mqm);
   /* Move entry to the end of the DLL, to be fair. */
   if (mqm != cp->mqm_tail)
   {
@@ -521,10 +551,29 @@ mqm_execute (struct GCP_MessageQueueManager *mqm)
                                       cp->mqm_tail,
                                       mqm);
   }
-  GNUNET_MQ_send (cp->core_mq,
-                  mqm->env);
-  mqm->env = NULL;
   cp->mqm_ready_counter--;
+  if (GNUNET_YES == should_I_drop ())
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "DROPPING message to peer %s from MQM %p\n",
+         GCP_2s (cp),
+         mqm);
+    GNUNET_MQ_discard (mqm->env);
+    mqm->env = NULL;
+    mqm_send_done (cp);
+  }
+  else
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Sending to peer %s from MQM %p\n",
+         GCP_2s (cp),
+         mqm);
+    GNUNET_MQ_send (cp->core_mq,
+                    mqm->env);
+    mqm->env = NULL;
+  }
+  mqm->cb (mqm->cb_cls,
+           GNUNET_YES);
 }
 
 
@@ -627,6 +676,28 @@ GCP_destroy_all_peers ()
 }
 
 
+/**
+ * Drop all paths owned by this peer, and do not
+ * allow new ones to be added: We are shutting down.
+ *
+ * @param cp peer to drop paths to
+ */
+void
+GCP_drop_owned_paths (struct CadetPeer *cp)
+{
+  struct CadetPeerPath *path;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Destroying all paths to %s\n",
+       GCP_2s (cp));
+  while (NULL != (path =
+                  GNUNET_CONTAINER_heap_remove_root (cp->path_heap)))
+    GCPP_release (path);
+  GNUNET_CONTAINER_heap_destroy (cp->path_heap);
+  cp->path_heap = NULL;
+}
+
+
 /**
  * Add an entry to the DLL of all of the paths that this peer is on.
  *
@@ -639,6 +710,8 @@ GCP_path_entry_add (struct CadetPeer *cp,
                     struct CadetPeerPathEntry *entry,
                     unsigned int off)
 {
+  GNUNET_assert (cp == GCPP_get_peer_at_offset (entry->path,
+                                                off));
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Discovered that peer %s is on path %s at offset %u\n",
        GCP_2s (cp),
@@ -730,6 +803,14 @@ GCP_attach_path (struct CadetPeer *cp,
   GNUNET_CONTAINER_HeapCostType root_desirability;
   struct GNUNET_CONTAINER_HeapNode *hn;
 
+  GNUNET_assert (cp == GCPP_get_peer_at_offset (path,
+                                                off));
+  if (NULL == cp->path_heap)
+  {
+    /* #GCP_drop_owned_paths() was already called, we cannot take new ones! */
+    GNUNET_assert (GNUNET_NO == force);
+    return NULL;
+  }
   desirability = GCPP_get_desirability (path);
   if (GNUNET_NO == force)
   {
@@ -755,7 +836,7 @@ GCP_attach_path (struct CadetPeer *cp,
   }
 
   LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Attaching path %p to peer %s (%s)\n",
+       "Attaching path %s to peer %s (%s)\n",
        GCPP_2s (path),
        GCP_2s (cp),
        (GNUNET_NO == force) ? "desirable" : "forced");
@@ -806,7 +887,7 @@ GCP_detach_path (struct CadetPeer *cp,
                  struct GNUNET_CONTAINER_HeapNode *hn)
 {
   LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Detatching path %p from peer %s\n",
+       "Detatching path %s from peer %s\n",
        GCPP_2s (path),
        GCP_2s (cp));
   GNUNET_assert (path ==
@@ -954,10 +1035,10 @@ GCP_iterate_paths (struct CadetPeer *cp,
 {
   unsigned int ret = 0;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Iterating over paths to peer %s%s\n",
-              GCP_2s (cp),
-              (NULL == cp->core_mq) ? "" : " including direct link");
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Iterating over paths to peer %s%s\n",
+       GCP_2s (cp),
+       (NULL == cp->core_mq) ? "" : " including direct link");
   if (NULL != cp->core_mq)
   {
     struct CadetPeerPath *path;
@@ -1007,8 +1088,14 @@ GCP_iterate_paths_at (struct CadetPeer *cp,
 {
   unsigned int ret = 0;
 
-  if (dist <= cp->path_dll_length)
+  if (dist >= cp->path_dll_length)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Asked to look for paths at distance %u, but maximum for me is < %u\n",
+         dist,
+         cp->path_dll_length);
     return 0;
+  }
   for (struct CadetPeerPathEntry *pe = cp->path_heads[dist];
        NULL != pe;
        pe = pe->next)