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;
&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);
}
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,
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! */
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.
*
}
+/**
+ * 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.
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,
+ ¬ify_tunnel_up_cb,
+ t);
+ }
+
/* FIXME: schedule rekey task! */
}
}
/**
- * 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
"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;
}
}
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);
}
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,