must delay iteration over paths until later, as we may be right now creating a connection
[oweals/gnunet.git] / src / cadet / gnunet-service-cadet-new_tunnels.c
index 535bd66a8083e30151be5fc7b7167bb49607de60..d63da29d4c6c65c2acabf4f363dd738651f35acc 100644 (file)
@@ -407,11 +407,10 @@ GCT_2s (const struct CadetTunnel *t)
 
   if (NULL == t)
     return "T(NULL)";
-
   GNUNET_snprintf (buf,
                    sizeof (buf),
                    "T(%s)",
-                   GCP_2s (t->destination));
+                   GNUNET_i2s (GCP_get_id (t->destination)));
   return buf;
 }
 
@@ -1173,6 +1172,27 @@ t_ax_decrypt_and_validate (struct CadetTunnel *t,
 }
 
 
+/**
+ * Our tunnel became ready for the first time, notify channels
+ * that have been waiting.
+ *
+ * @param cls our tunnel, not used
+ * @param key unique ID of the channel, not used
+ * @param value the `struct CadetChannel` to notify
+ * @return #GNUNET_OK (continue to iterate)
+ */
+static int
+notify_tunnel_up_cb (void *cls,
+                     uint32_t key,
+                     void *value)
+{
+  struct CadetChannel *ch = value;
+
+  GCCH_tunnel_up (ch);
+  return GNUNET_OK;
+}
+
+
 /**
  * Change the tunnel encryption state.
  * If the encryption state changes to OK, stop the rekey task.
@@ -1201,6 +1221,14 @@ GCT_change_estate (struct CadetTunnel *t,
       GNUNET_SCHEDULER_cancel (t->kx_task);
       t->kx_task = NULL;
     }
+    if (CADET_TUNNEL_KEY_REKEY != old)
+    {
+      /* notify all channels that have been waiting */
+      GNUNET_CONTAINER_multihashmap32_iterate (t->channels,
+                                               &notify_tunnel_up_cb,
+                                               t);
+    }
+
     /* FIXME: schedule rekey task! */
   }
 }
@@ -1454,7 +1482,9 @@ get_next_free_ctn (struct CadetTunnel *t)
 
 
 /**
- * Add a channel to a tunnel.
+ * Add a channel to a tunnel, and notify channel that we are ready
+ * for transmission if we are already up.  Otherwise that notification
+ * will be done later in #notify_tunnel_up_cb().
  *
  * @param t Tunnel.
  * @param ch Channel
@@ -1476,6 +1506,9 @@ GCT_add_channel (struct CadetTunnel *t,
               "Adding channel %s to tunnel %s\n",
               GCCH_2s (ch),
               GCT_2s (t));
+  if ( (CADET_TUNNEL_KEY_OK == t->estate) ||
+       (CADET_TUNNEL_KEY_REKEY == t->estate) )
+    GCCH_tunnel_up (ch);
   return ctn;
 }
 
@@ -1490,7 +1523,7 @@ destroy_tunnel (void *cls)
 {
   struct CadetTunnel *t = cls;
   struct CadetTConnection *ct;
-  struct CadetTunnelQueueEntry *tqe;
+  struct CadetTunnelQueueEntry *tq;
 
   t->destroy_task = NULL;
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -1506,14 +1539,8 @@ destroy_tunnel (void *cls)
     GCC_destroy (ct->cc);
     GNUNET_free (ct);
   }
-  while (NULL != (tqe = t->tq_head))
-  {
-    GNUNET_CONTAINER_DLL_remove (t->tq_head,
-                                 t->tq_tail,
-                                 tqe);
-    GNUNET_MQ_discard (tqe->env);
-    GNUNET_free (tqe);
-  }
+  while (NULL != (tq = t->tq_head))
+    GCT_send_cancel (tq);
   GCP_drop_tunnel (t->destination,
                    t);
   GNUNET_CONTAINER_multihashmap32_destroy (t->channels);
@@ -1524,6 +1551,12 @@ destroy_tunnel (void *cls)
   }
   GNUNET_MST_destroy (t->mst);
   GNUNET_MQ_destroy (t->mq);
+  while (NULL != t->ax.skipped_head)
+    delete_skipped_key (t,
+                        t->ax.skipped_head);
+  GNUNET_assert (0 == t->ax.skipped);
+  GNUNET_free_non_null (t->ax.kx_0);
+  GNUNET_free_non_null (t->ax.DHRs);
   GNUNET_free (t);
 }
 
@@ -1558,6 +1591,21 @@ GCT_remove_channel (struct CadetTunnel *t,
 }
 
 
+/**
+ * Destroys the tunnel @a t now, without delay. Used during shutdown.
+ *
+ * @param t tunnel to destroy
+ */
+void
+GCT_destroy_tunnel_now (struct CadetTunnel *t)
+{
+  GNUNET_assert (0 ==
+                 GNUNET_CONTAINER_multihashmap32_size (t->channels));
+  GNUNET_SCHEDULER_cancel (t->destroy_task);
+  destroy_tunnel (t);
+}
+
+
 /**
  * It's been a while, we should try to redo the KX, if we can.
  *
@@ -1663,9 +1711,9 @@ connection_ready_cb (void *cls,
     if (NULL == t->kx_task)
     {
       t->kx_task
-        = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining (t->next_kx_attempt),
-                                        &retry_kx,
-                                        t);
+        = GNUNET_SCHEDULER_add_at (t->next_kx_attempt,
+                                   &retry_kx,
+                                   t);
     }
     break;
   case CADET_TUNNEL_KEY_OK:
@@ -1704,28 +1752,6 @@ trigger_transmissions (struct CadetTunnel *t)
 }
 
 
-/**
- * Function called to maintain the connections underlying our tunnel.
- * Tries to maintain (incl. tear down) connections for the tunnel, and
- * if there is a significant change, may trigger transmissions.
- *
- * Basically, needs to check if there are connections that perform
- * badly, and if so eventually kill them and trigger a replacement.
- * The strategy is to open one more connection than
- * #DESIRED_CONNECTIONS_PER_TUNNEL, and then periodically kick out the
- * least-performing one, and then inquire for new ones.
- *
- * @param cls the `struct CadetTunnel`
- */
-static void
-maintain_connections_cb (void *cls)
-{
-  struct CadetTunnel *t = cls;
-
-  GNUNET_break (0); // FIXME: implement!
-}
-
-
 /**
  * Consider using the path @a p for the tunnel @a t.
  * The tunnel destination is at offset @a off in path @a p.
@@ -1754,7 +1780,13 @@ consider_path_cb (void *cls,
 
     ps = GCC_get_path (ct->cc);
     if (ps == path)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "Ignoring duplicate path %s for tunnel %s.\n",
+                  GCPP_2s (path),
+                  GCT_2s (t));
       return GNUNET_YES; /* duplicate */
+    }
     min_length = GNUNET_MIN (min_length,
                              GCPP_get_length (ps));
     max_desire = GNUNET_MAX (max_desire,
@@ -1816,6 +1848,37 @@ consider_path_cb (void *cls,
 }
 
 
+/**
+ * Function called to maintain the connections underlying our tunnel.
+ * Tries to maintain (incl. tear down) connections for the tunnel, and
+ * if there is a significant change, may trigger transmissions.
+ *
+ * Basically, needs to check if there are connections that perform
+ * badly, and if so eventually kill them and trigger a replacement.
+ * The strategy is to open one more connection than
+ * #DESIRED_CONNECTIONS_PER_TUNNEL, and then periodically kick out the
+ * least-performing one, and then inquire for new ones.
+ *
+ * @param cls the `struct CadetTunnel`
+ */
+static void
+maintain_connections_cb (void *cls)
+{
+  struct CadetTunnel *t = cls;
+
+  t->maintain_connections_task = NULL;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Performing connection maintenance for tunnel %s.\n",
+              GCT_2s (t));
+
+  (void) GCP_iterate_paths (t->destination,
+                            &consider_path_cb,
+                            t);
+
+  GNUNET_break (0); // FIXME: implement!
+}
+
+
 /**
  * Consider using the path @a p for the tunnel @a t.
  * The tunnel destination is at offset @a off in path @a p.
@@ -2126,11 +2189,10 @@ GCT_create_tunnel (struct CadetPeer *destination)
   struct CadetTunnel *t;
 
   t = GNUNET_new (struct CadetTunnel);
+  new_ephemeral (t);
+  t->ax.kx_0 = GNUNET_CRYPTO_ecdhe_key_create ();
   t->destination = destination;
   t->channels = GNUNET_CONTAINER_multihashmap32_create (8);
-  (void) GCP_iterate_paths (destination,
-                            &consider_path_cb,
-                            t);
   t->maintain_connections_task
     = GNUNET_SCHEDULER_add_now (&maintain_connections_cb,
                                 t);
@@ -2335,17 +2397,18 @@ GCT_send (struct CadetTunnel *t,
  * function is called. Once the continuation is called, the message is
  * no longer in the queue!
  *
- * @param q Handle to the queue entry to cancel.
+ * @param tq Handle to the queue entry to cancel.
  */
 void
-GCT_send_cancel (struct CadetTunnelQueueEntry *q)
+GCT_send_cancel (struct CadetTunnelQueueEntry *tq)
 {
-  struct CadetTunnel *t = q->t;
+  struct CadetTunnel *t = tq->t;
 
   GNUNET_CONTAINER_DLL_remove (t->tq_head,
                                t->tq_tail,
-                               q);
-  GNUNET_free (q);
+                               tq);
+  GNUNET_MQ_discard (tq->env);
+  GNUNET_free (tq);
 }