fix startup interaction between channel and tunnel to not send CHANNEL_OPEN until...
authorChristian Grothoff <christian@grothoff.org>
Sun, 22 Jan 2017 10:35:46 +0000 (11:35 +0100)
committerChristian Grothoff <christian@grothoff.org>
Sun, 22 Jan 2017 10:35:46 +0000 (11:35 +0100)
src/cadet/gnunet-service-cadet-new_channel.c
src/cadet/gnunet-service-cadet-new_channel.h
src/cadet/gnunet-service-cadet-new_tunnels.c

index 6f57538acdcc1f18bd1521788188c3ba517fcacc..60e1a77668bac35af450990e1cdae15bf9f8e93d 100644 (file)
@@ -440,6 +440,9 @@ send_channel_open (void *cls)
   uint32_t options;
 
   ch->retry_task = NULL;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Sending CHANNEL_OPEN message for channel %s\n",
+       GCCH_2s (ch));
   options = 0;
   if (ch->nobuffer)
     options |= GNUNET_CADET_OPTION_NOBUFFER;
@@ -457,9 +460,25 @@ send_channel_open (void *cls)
                                   &msgcc.header,
                                   &channel_open_sent_cb,
                                   ch);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Sending CHANNEL_OPEN message for channel %s\n",
-       GCCH_2s (ch));
+}
+
+
+/**
+ * Function called once and only once after a channel was bound
+ * to its tunnel via #GCT_add_channel() is ready for transmission.
+ * Note that this is only the case for channels that this peer
+ * initiates, as for incoming channels we assume that they are
+ * ready for transmission immediately upon receiving the open
+ * message.  Used to bootstrap the #GCT_send() process.
+ *
+ * @param ch the channel for which the tunnel is now ready
+ */
+void
+GCCH_tunnel_up (struct CadetChannel *ch)
+{
+  GNUNET_assert (NULL == ch->retry_task);
+  ch->retry_task = GNUNET_SCHEDULER_add_now (&send_channel_open,
+                                             ch);
 }
 
 
@@ -492,11 +511,9 @@ GCCH_channel_local_new (struct CadetClient *owner,
   ch->port = *port;
   ch->t = GCP_get_tunnel (destination,
                           GNUNET_YES);
-  ch->ctn = GCT_add_channel (ch->t,
-                              ch);
   ch->retry_time = CADET_INITIAL_RETRANSMIT_TIME;
-  ch->retry_task = GNUNET_SCHEDULER_add_now (&send_channel_open,
-                                             ch);
+  ch->ctn = GCT_add_channel (ch->t,
+                             ch);
   GNUNET_STATISTICS_update (stats,
                             "# channels",
                             1,
@@ -814,6 +831,8 @@ GCCH_handle_channel_open_ack (struct CadetChannel *ch)
     LOG (GNUNET_ERROR_TYPE_DEBUG,
          "Received channel OPEN_ACK for waiting channel %s, entering READY state\n",
          GCCH_2s (ch));
+    GNUNET_SCHEDULER_cancel (ch->retry_task);
+    ch->retry_task = NULL;
     ch->state = CADET_CHANNEL_READY;
     /* On first connect, send client as many ACKs as we allow messages
        to be buffered! */
index a479145aa9865866eb3093c320d6b0f86d465e3f..ae4c5da5a3dcc77e7d0881a71f3e2715f0508d46 100644 (file)
@@ -118,6 +118,20 @@ void
 GCCH_channel_local_destroy (struct CadetChannel *ch);
 
 
+/**
+ * Function called once and only once after a channel was bound
+ * to its tunnel via #GCT_add_channel() is ready for transmission.
+ * Note that this is only the case for channels that this peer
+ * initiates, as for incoming channels we assume that they are
+ * ready for transmission immediately upon receiving the open
+ * message.  Used to bootstrap the #GCT_send() process.
+ *
+ * @param ch the channel for which the tunnel is now ready
+ */
+void
+GCCH_tunnel_up (struct CadetChannel *ch);
+
+
 /**
  * Create a new channel based on a request coming in over the network.
  *
index 178577b46a157023aae91731bc0a94978ef3c55f..cad3306cde25daf897261668c6a741d57901d129 100644 (file)
@@ -1173,6 +1173,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 +1222,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 +1483,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 +1507,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;
 }
 
@@ -1518,6 +1552,11 @@ 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);
 }
@@ -2138,6 +2177,7 @@ GCT_create_tunnel (struct CadetPeer *destination)
 
   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,