From: Christian Grothoff Date: Sun, 22 Jan 2017 10:35:46 +0000 (+0100) Subject: fix startup interaction between channel and tunnel to not send CHANNEL_OPEN until... X-Git-Tag: taler-0.2.1~384 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=2ecdd817ef433aa4ff3ddc188a30dd0408c469e1;p=oweals%2Fgnunet.git fix startup interaction between channel and tunnel to not send CHANNEL_OPEN until tunnel is in KEY_OK state --- diff --git a/src/cadet/gnunet-service-cadet-new_channel.c b/src/cadet/gnunet-service-cadet-new_channel.c index 6f57538ac..60e1a7766 100644 --- a/src/cadet/gnunet-service-cadet-new_channel.c +++ b/src/cadet/gnunet-service-cadet-new_channel.c @@ -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! */ diff --git a/src/cadet/gnunet-service-cadet-new_channel.h b/src/cadet/gnunet-service-cadet-new_channel.h index a479145aa..ae4c5da5a 100644 --- a/src/cadet/gnunet-service-cadet-new_channel.h +++ b/src/cadet/gnunet-service-cadet-new_channel.h @@ -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. * diff --git a/src/cadet/gnunet-service-cadet-new_tunnels.c b/src/cadet/gnunet-service-cadet-new_tunnels.c index 178577b46..cad3306cd 100644 --- a/src/cadet/gnunet-service-cadet-new_tunnels.c +++ b/src/cadet/gnunet-service-cadet-new_tunnels.c @@ -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, + ¬ify_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,