* @author Christian Grothoff
*
* FIXME:
- * - connection management
- * + properly (evaluate, kill old ones, search for new ones)
- * + when managing connections, distinguish those that
- * have (recently) had traffic from those that were
- * never ready (or not recently)
+ * - proper connection evaluation during connection management:
+ * + consider quality (or quality spread?) of current connection set
+ * when deciding how often to do maintenance
+ * + interact with PEER to drive DHT GET/PUT operations based
+ * on how much we like our connections
*/
#include "platform.h"
#include "gnunet_util_lib.h"
struct GNUNET_CRYPTO_SymmetricSessionKey CKr;
/**
- * ECDH for key exchange (A0 / B0). Note that for the
- * 'unverified_ax', this member is an alias with the main
- * 't->ax.kx_0' value, so do not free it!
+ * ECDH for key exchange (A0 / B0).
*/
- struct GNUNET_CRYPTO_EcdhePrivateKey *kx_0;
+ struct GNUNET_CRYPTO_EcdhePrivateKey kx_0;
/**
- * ECDH Ratchet key (our private key in the current DH). Note that
- * for the 'unverified_ax', this member is an alias with the main
- * 't->ax.kx_0' value, so do not free it!
+ * ECDH Ratchet key (our private key in the current DH).
*/
- struct GNUNET_CRYPTO_EcdhePrivateKey *DHRs;
+ struct GNUNET_CRYPTO_EcdhePrivateKey DHRs;
/**
* ECDH Ratchet key (other peer's public key in the current DH).
/**
* Continuation to call once sent (on the channel layer).
*/
- GNUNET_SCHEDULER_TaskCallback cont;
+ GCT_SendContinuation cont;
/**
* Closure for @c cont.
*/
struct CadetTunnelQueueEntry *tq_tail;
+ /**
+ * Identification of the connection from which we are currently processing
+ * a message. Only valid (non-NULL) during #handle_decrypted() and the
+ * handle-*()-functions called from our @e mq during that function.
+ */
+ struct CadetTConnection *current_ct;
+
/**
* How long do we wait until we retry the KX?
*/
static struct CadetTConnection *
get_ready_connection (struct CadetTunnel *t)
{
- return t->connection_ready_head;
+ struct CadetTConnection *hd = t->connection_ready_head;
+
+ GNUNET_assert ( (NULL == hd) ||
+ (GNUNET_YES == hd->is_ready) );
+ return hd;
}
static void
new_ephemeral (struct CadetTunnelAxolotl *ax)
{
- GNUNET_free_non_null (ax->DHRs);
LOG (GNUNET_ERROR_TYPE_DEBUG,
"Creating new ephemeral ratchet key (DHRs)\n");
- ax->DHRs = GNUNET_CRYPTO_ecdhe_key_create ();
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CRYPTO_ecdhe_key_create2 (&ax->DHRs));
}
ax->HKs = ax->NHKs;
/* RK, NHKs, CKs = KDF( HMAC-HASH(RK, DH(DHRs, DHRr)) ) */
- GNUNET_CRYPTO_ecc_ecdh (ax->DHRs,
+ GNUNET_CRYPTO_ecc_ecdh (&ax->DHRs,
&ax->DHRr,
&dh);
t_ax_hmac_hash (&ax->RK,
PNp);
/* RKp, NHKp, CKp = KDF (HMAC-HASH (RK, DH (DHRp, DHRs))) */
- GNUNET_CRYPTO_ecc_ecdh (ax->DHRs,
+ GNUNET_CRYPTO_ecc_ecdh (&ax->DHRs,
DHRp,
&dh);
t_ax_hmac_hash (&ax->RK,
struct GNUNET_CADET_TunnelKeyExchangeMessage *msg;
enum GNUNET_CADET_KX_Flags flags;
- if (NULL == ct)
+ if ( (NULL == ct) ||
+ (GNUNET_NO == ct->is_ready) )
ct = get_ready_connection (t);
if (NULL == ct)
{
}
cc = ct->cc;
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Sending KX on %s via %s using %s in state %s\n",
+ "Sending KX on %s via %s in state %s\n",
GCT_2s (t),
GCC_2s (cc),
estate2s (t->estate));
flags = GNUNET_CADET_KX_FLAG_FORCE_REPLY; /* always for KX */
msg->flags = htonl (flags);
msg->cid = *GCC_get_id (cc);
- GNUNET_CRYPTO_ecdhe_key_get_public (ax->kx_0,
+ GNUNET_CRYPTO_ecdhe_key_get_public (&ax->kx_0,
&msg->ephemeral_key);
- GNUNET_CRYPTO_ecdhe_key_get_public (ax->DHRs,
+ GNUNET_CRYPTO_ecdhe_key_get_public (&ax->DHRs,
&msg->ratchet_key);
mark_connection_unready (ct);
t->kx_retry_delay = GNUNET_TIME_STD_BACKOFF (t->kx_retry_delay);
flags |= GNUNET_CADET_KX_FLAG_FORCE_REPLY;
msg->kx.flags = htonl (flags);
msg->kx.cid = *GCC_get_id (cc);
- GNUNET_CRYPTO_ecdhe_key_get_public (ax->kx_0,
+ GNUNET_CRYPTO_ecdhe_key_get_public (&ax->kx_0,
&msg->kx.ephemeral_key);
- GNUNET_CRYPTO_ecdhe_key_get_public (ax->DHRs,
+ GNUNET_CRYPTO_ecdhe_key_get_public (&ax->DHRs,
&msg->kx.ratchet_key);
/* Compute authenticator (this is the main difference to #send_kx()) */
GNUNET_CRYPTO_hash (&ax->RK,
delete_skipped_key (ax,
ax->skipped_head);
GNUNET_assert (0 == ax->skipped);
- GNUNET_free_non_null (ax->kx_0);
- GNUNET_free_non_null (ax->DHRs);
+ GNUNET_CRYPTO_ecdhe_key_clear (&ax->kx_0);
+ GNUNET_CRYPTO_ecdhe_key_clear (&ax->DHRs);
}
}
else
{
- GNUNET_CRYPTO_ecdh_eddsa (ax->kx_0, /* B0 */
+ GNUNET_CRYPTO_ecdh_eddsa (&ax->kx_0, /* B0 */
&pid->public_key, /* A */
&key_material[0]);
}
/* ECDH A0 B */
if (GNUNET_YES == am_I_alice)
{
- GNUNET_CRYPTO_ecdh_eddsa (ax->kx_0, /* A0 */
+ GNUNET_CRYPTO_ecdh_eddsa (&ax->kx_0, /* A0 */
&pid->public_key, /* B */
&key_material[1]);
}
/* ECDH A0 B0 */
/* (This is the triple-DH, we could probably safely skip this,
as A0/B0 are already in the key material.) */
- GNUNET_CRYPTO_ecc_ecdh (ax->kx_0, /* A0 or B0 */
+ GNUNET_CRYPTO_ecc_ecdh (&ax->kx_0, /* A0 or B0 */
ephemeral_key, /* B0 or A0 */
&key_material[2]);
GCP_get_id (t->destination),
&msg->kx.ephemeral_key,
&msg->kx.ratchet_key);
- GNUNET_break (GNUNET_OK == ret);
+ if (GNUNET_OK != ret)
+ {
+ if (GNUNET_NO == ret)
+ GNUNET_STATISTICS_update (stats,
+ "# redundant KX_AUTH received",
+ 1,
+ GNUNET_NO);
+ else
+ GNUNET_break (0); /* connect to self!? */
+ return;
+ }
GNUNET_CRYPTO_hash (&ax_tmp.RK,
sizeof (ax_tmp.RK),
&kx_auth);
sizeof (kx_auth)))
{
/* This KX_AUTH is not using the latest KX/KX_AUTH data
- we transmitted to the sender, refuse it! */
- GNUNET_break_op (0);
+ we transmitted to the sender, refuse it, try KX again. */
+ GNUNET_STATISTICS_update (stats,
+ "# KX_AUTH not using our last KX received (auth failure)",
+ 1,
+ GNUNET_NO);
+ send_kx (t,
+ ct,
+ &t->ax);
return;
}
/* Yep, we're good. */
if (NULL != t->unverified_ax)
{
/* We got some "stale" KX before, drop that. */
- t->unverified_ax->DHRs = NULL; /* aliased with ax.DHRs */
- t->unverified_ax->kx_0 = NULL; /* aliased with ax.DHRs */
cleanup_ax (t->unverified_ax);
GNUNET_free (t->unverified_ax);
t->unverified_ax = NULL;
ctn = ntohl (t->next_ctn.cn);
while (NULL !=
GNUNET_CONTAINER_multihashmap32_get (t->channels,
- ctn))
+ ctn | highbit))
{
- ctn = ((ctn + 1) & (~ HIGH_BIT)) | highbit;
+ ctn = ((ctn + 1) & (~ HIGH_BIT));
}
- t->next_ctn.cn = htonl (((ctn + 1) & (~ HIGH_BIT)) | highbit);
- ret.cn = ntohl (ctn);
+ t->next_ctn.cn = htonl ((ctn + 1) & (~ HIGH_BIT));
+ ret.cn = htonl (ctn | highbit);
return ret;
}
struct GNUNET_CADET_ChannelTunnelNumber ctn;
ctn = get_next_free_ctn (t);
+ if (NULL != t->destroy_task)
+ {
+ GNUNET_SCHEDULER_cancel (t->destroy_task);
+ t->destroy_task = NULL;
+ }
GNUNET_assert (GNUNET_YES ==
GNUNET_CONTAINER_multihashmap32_put (t->channels,
ntohl (ctn.cn),
struct CadetTunnel *t = ct->t;
if (GNUNET_YES == ct->is_ready)
+ {
GNUNET_CONTAINER_DLL_remove (t->connection_ready_head,
t->connection_ready_tail,
ct);
+ t->num_ready_connections--;
+ }
else
+ {
GNUNET_CONTAINER_DLL_remove (t->connection_busy_head,
t->connection_busy_tail,
ct);
+ t->num_busy_connections--;
+ }
GNUNET_free (ct);
}
+/**
+ * Clean up connection @a ct of a tunnel.
+ *
+ * @param cls the `struct CadetTunnel`
+ * @param ct connection to clean up
+ */
+static void
+destroy_t_connection (void *cls,
+ struct CadetTConnection *ct)
+{
+ struct CadetTunnel *t = cls;
+ struct CadetConnection *cc = ct->cc;
+
+ GNUNET_assert (ct->t == t);
+ GCT_connection_lost (ct);
+ GCC_destroy_without_tunnel (cc);
+}
+
+
/**
* This tunnel is no longer used, destroy it.
*
destroy_tunnel (void *cls)
{
struct CadetTunnel *t = cls;
- struct CadetTConnection *ct;
struct CadetTunnelQueueEntry *tq;
t->destroy_task = NULL;
"Destroying idle %s\n",
GCT_2s (t));
GNUNET_assert (0 == GCT_count_channels (t));
- while (NULL != (ct = t->connection_ready_head))
- {
- struct CadetConnection *cc;
-
- GNUNET_assert (ct->t == t);
- cc = ct->cc;
- GCT_connection_lost (ct);
- GCC_destroy_without_tunnel (cc);
- }
- while (NULL != (ct = t->connection_busy_head))
- {
- struct CadetConnection *cc;
-
- GNUNET_assert (ct->t == t);
- cc = ct->cc;
- GCT_connection_lost (ct);
- GCC_destroy_without_tunnel (cc);
- }
+ GCT_iterate_connections (t,
+ &destroy_t_connection,
+ t);
+ GNUNET_assert (NULL == t->connection_ready_head);
+ GNUNET_assert (NULL == t->connection_busy_head);
while (NULL != (tq = t->tq_head))
{
if (NULL != tq->cont)
- tq->cont (tq->cont_cls);
+ tq->cont (tq->cont_cls,
+ NULL);
GCT_send_cancel (tq);
}
GCP_drop_tunnel (t->destination,
GNUNET_MQ_destroy (t->mq);
if (NULL != t->unverified_ax)
{
- t->unverified_ax->DHRs = NULL; /* aliased with ax.DHRs */
- t->unverified_ax->kx_0 = NULL; /* aliased with ax.DHRs */
cleanup_ax (t->unverified_ax);
GNUNET_free (t->unverified_ax);
}
cleanup_ax (&t->ax);
+ GNUNET_assert (NULL == t->destroy_task);
GNUNET_free (t);
}
GNUNET_CONTAINER_multihashmap32_remove (t->channels,
ntohl (ctn.cn),
ch));
- if (0 ==
- GCT_count_channels (t))
+ if ( (0 ==
+ GCT_count_channels (t)) &&
+ (NULL == t->destroy_task) )
{
- t->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_DESTROY_DELAY,
- &destroy_tunnel,
- t);
+ t->destroy_task
+ = GNUNET_SCHEDULER_add_delayed (IDLE_DESTROY_DELAY,
+ &destroy_tunnel,
+ t);
}
}
{
struct CadetChannel *ch = value;
- GCCH_handle_remote_destroy (ch);
+ GCCH_handle_remote_destroy (ch,
+ NULL);
return GNUNET_OK;
}
GCC_transmit (ct->cc,
tq->env);
if (NULL != tq->cont)
- tq->cont (tq->cont_cls);
+ tq->cont (tq->cont_cls,
+ GCC_get_id (ct->cc));
GNUNET_free (tq);
}
GNUNET_CONTAINER_HeapCostType max_desire;
/**
- * Path we are comparing against.
+ * Path we are comparing against for #evaluate_connection, can be NULL.
*/
struct CadetPeerPath *path;
+ /**
+ * Connection deemed the "worst" so far encountered by #evaluate_connection,
+ * NULL if we did not yet encounter any connections.
+ */
+ struct CadetTConnection *worst;
+
+ /**
+ * Numeric score of @e worst, only set if @e worst is non-NULL.
+ */
+ double worst_score;
+
/**
* Set to #GNUNET_YES if we have a connection over @e path already.
*/
* what kinds of connections we have.
*
* @param cls the `struct EvaluationSummary *` to update
- * @param cc a connection to include in the summary
+ * @param ct a connection to include in the summary
*/
static void
evaluate_connection (void *cls,
- struct CadetConnection *cc)
+ struct CadetTConnection *ct)
{
struct EvaluationSummary *es = cls;
+ struct CadetConnection *cc = ct->cc;
struct CadetPeerPath *ps = GCC_get_path (cc);
+ const struct CadetConnectionMetrics *metrics;
+ GNUNET_CONTAINER_HeapCostType ct_desirability;
+ struct GNUNET_TIME_Relative uptime;
+ struct GNUNET_TIME_Relative last_use;
+ uint32_t ct_length;
+ double score;
+ double success_rate;
if (ps == es->path)
{
es->duplicate = GNUNET_YES;
return;
}
+ ct_desirability = GCPP_get_desirability (ps);
+ ct_length = GCPP_get_length (ps);
+ metrics = GCC_get_metrics (cc);
+ uptime = GNUNET_TIME_absolute_get_duration (metrics->age);
+ last_use = GNUNET_TIME_absolute_get_duration (metrics->last_use);
+ /* We add 1.0 here to avoid division by zero. */
+ success_rate = (metrics->num_acked_transmissions + 1.0) / (metrics->num_successes + 1.0);
+ score
+ = ct_desirability
+ + 100.0 / (1.0 + ct_length) /* longer paths = better */
+ + sqrt (uptime.rel_value_us / 60000000LL) /* larger uptime = better */
+ - last_use.rel_value_us / 1000L; /* longer idle = worse */
+ score *= success_rate; /* weigh overall by success rate */
+
+ if ( (NULL == es->worst) ||
+ (score < es->worst_score) )
+ {
+ es->worst = ct;
+ es->worst_score = score;
+ }
es->min_length = GNUNET_MIN (es->min_length,
- GCPP_get_length (ps));
+ ct_length);
es->max_length = GNUNET_MAX (es->max_length,
- GCPP_get_length (ps));
+ ct_length);
es->min_desire = GNUNET_MIN (es->min_desire,
- GCPP_get_desirability (ps));
+ ct_desirability);
es->max_desire = GNUNET_MAX (es->max_desire,
- GCPP_get_desirability (ps));
+ ct_desirability);
}
struct EvaluationSummary es;
struct CadetTConnection *ct;
+ GNUNET_assert (off < GCPP_get_length (path));
es.min_length = UINT_MAX;
es.max_length = 0;
es.max_desire = 0;
es.min_desire = UINT64_MAX;
es.path = path;
es.duplicate = GNUNET_NO;
+ es.worst = NULL;
/* Compute evaluation summary over existing connections. */
GCT_iterate_connections (t,
this one is more than twice as long than what we are currently
using, then ignore all of these super-long ones! */
if ( (GCT_count_any_connections (t) > DESIRED_CONNECTIONS_PER_TUNNEL) &&
- (es.min_length * 2 < off) )
+ (es.min_length * 2 < off) &&
+ (es.max_length < off) )
{
LOG (GNUNET_ERROR_TYPE_DEBUG,
"Ignoring paths of length %u, they are way too long.\n",
/* If we have enough paths and this one looks no better, ignore it. */
if ( (GCT_count_any_connections (t) >= DESIRED_CONNECTIONS_PER_TUNNEL) &&
(es.min_length < GCPP_get_length (path)) &&
- (es.max_desire > GCPP_get_desirability (path)) )
+ (es.min_desire > GCPP_get_desirability (path)) &&
+ (es.max_length < off) )
{
LOG (GNUNET_ERROR_TYPE_DEBUG,
"Ignoring path (%u/%llu) to %s, got something better already.\n",
ct->t = t;
ct->cc = GCC_create (t->destination,
path,
+ off,
+ GNUNET_CADET_OPTION_DEFAULT, /* FIXME: set based on what channels want/need! */
ct,
&connection_ready_cb,
ct);
+
/* FIXME: schedule job to kill connection (and path?) if it takes
too long to get ready! (And track performance data on how long
other connections took with the tunnel!)
maintain_connections_cb (void *cls)
{
struct CadetTunnel *t = cls;
+ struct GNUNET_TIME_Relative delay;
+ struct EvaluationSummary es;
t->maintain_connections_task = NULL;
LOG (GNUNET_ERROR_TYPE_DEBUG,
"Performing connection maintenance for %s.\n",
GCT_2s (t));
+ es.min_length = UINT_MAX;
+ es.max_length = 0;
+ es.max_desire = 0;
+ es.min_desire = UINT64_MAX;
+ es.path = NULL;
+ es.worst = NULL;
+ es.duplicate = GNUNET_NO;
+ GCT_iterate_connections (t,
+ &evaluate_connection,
+ &es);
+ if ( (NULL != es.worst) &&
+ (GCT_count_any_connections (t) > DESIRED_CONNECTIONS_PER_TUNNEL) )
+ {
+ /* Clear out worst-performing connection 'es.worst'. */
+ destroy_t_connection (t,
+ es.worst);
+ }
+
+ /* Consider additional paths */
(void) GCP_iterate_paths (t->destination,
&consider_path_cb,
t);
- GNUNET_break (0); // FIXME: implement!
+ /* FIXME: calculate when to try again based on how well we are doing;
+ in particular, if we have to few connections, we might be able
+ to do without this (as PATHS should tell us whenever a new path
+ is available instantly; however, need to make sure this job is
+ restarted after that happens).
+ Furthermore, if the paths we do know are in a reasonably narrow
+ quality band and are plentyful, we might also consider us stabilized
+ and then reduce the frequency accordingly. */
+ delay = GNUNET_TIME_UNIT_MINUTES;
+ t->maintain_connections_task
+ = GNUNET_SCHEDULER_add_delayed (delay,
+ &maintain_connections_cb,
+ t);
}
struct CadetPeerPath *p,
unsigned int off)
{
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Considering %s for %s\n",
+ GCPP_2s (p),
+ GCT_2s (t));
(void) consider_path_cb (t,
p,
off);
/* We don't know about such a channel, might have been destroyed on our
end in the meantime, or never existed. Send back a DESTROY. */
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Receicved %u bytes of application data for unknown channel %u, sending DESTROY\n",
+ "Received %u bytes of application data for unknown channel %u, sending DESTROY\n",
(unsigned int) (ntohs (msg->header.size) - sizeof (*msg)),
ntohl (msg->ctn.cn));
GCT_send_channel_destroy (t,
return;
}
GCCH_handle_channel_plaintext_data (ch,
+ GCC_get_id (t->current_ct->cc),
msg);
}
/* We don't know about such a channel, might have been destroyed on our
end in the meantime, or never existed. Send back a DESTROY. */
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Receicved DATA_ACK for unknown channel %u, sending DESTROY\n",
+ "Received DATA_ACK for unknown channel %u, sending DESTROY\n",
ntohl (ack->ctn.cn));
GCT_send_channel_destroy (t,
ack->ctn);
return;
}
GCCH_handle_channel_plaintext_data_ack (ch,
+ GCC_get_id (t->current_ct->cc),
ack);
}
if (NULL != ch)
{
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Receicved duplicate channel OPEN on port %s from %s (%s), resending ACK\n",
+ "Received duplicate channel CHANNEL_OPEN on port %s from %s (%s), resending ACK\n",
GNUNET_h2s (&copen->port),
GCT_2s (t),
GCCH_2s (ch));
- GCCH_handle_duplicate_open (ch);
+ GCCH_handle_duplicate_open (ch,
+ GCC_get_id (t->current_ct->cc));
return;
}
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Receicved channel OPEN on port %s from %s\n",
+ "Received CHANNEL_OPEN on port %s from %s\n",
GNUNET_h2s (&copen->port),
GCT_2s (t));
ch = GCCH_channel_incoming_new (t,
copen->ctn,
&copen->port,
ntohl (copen->opt));
+ if (NULL != t->destroy_task)
+ {
+ GNUNET_SCHEDULER_cancel (t->destroy_task);
+ t->destroy_task = NULL;
+ }
GNUNET_assert (GNUNET_OK ==
GNUNET_CONTAINER_multihashmap32_put (t->channels,
ntohl (copen->ctn.cn),
"Received channel OPEN_ACK on channel %s from %s\n",
GCCH_2s (ch),
GCT_2s (t));
- GCCH_handle_channel_open_ack (ch);
+ GCCH_handle_channel_open_ack (ch,
+ GCC_get_id (t->current_ct->cc));
}
return;
}
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Receicved channel DESTROY on %s from %s\n",
+ "Received channel DESTROY on %s from %s\n",
GCCH_2s (ch),
GCT_2s (t));
- GCCH_handle_remote_destroy (ch);
+ GCCH_handle_remote_destroy (ch,
+ GCC_get_id (t->current_ct->cc));
}
{
struct CadetTunnel *t = cls;
+ GNUNET_assert (NULL != t->current_ct);
GNUNET_MQ_inject_message (t->mq,
msg);
return GNUNET_OK;
t->kx_retry_delay = INITIAL_KX_RETRY_DELAY;
new_ephemeral (&t->ax);
- t->ax.kx_0 = GNUNET_CRYPTO_ecdhe_key_create ();
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CRYPTO_ecdhe_key_create2 (&t->ax.kx_0));
t->destination = destination;
t->channels = GNUNET_CONTAINER_multihashmap32_create (8);
t->maintain_connections_task
*
* @param t a tunnel
* @param cid connection identifer to use for the connection
+ * @param options options for the connection
* @param path path to use for the connection
* @return #GNUNET_OK on success,
* #GNUNET_SYSERR on failure (duplicate connection)
int
GCT_add_inbound_connection (struct CadetTunnel *t,
const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
+ enum GNUNET_CADET_ChannelOption options,
struct CadetPeerPath *path)
{
struct CadetTConnection *ct;
ct->t = t;
ct->cc = GCC_create_inbound (t->destination,
path,
+ options,
ct,
cid,
&connection_ready_cb,
case CADET_TUNNEL_KEY_UNINITIALIZED:
case CADET_TUNNEL_KEY_AX_RECV:
/* We did not even SEND our KX, how can the other peer
- send us encrypted data? */
- GNUNET_break_op (0);
+ send us encrypted data? Must have been that we went
+ down and the other peer still things we are up.
+ Let's send it KX back. */
+ GNUNET_STATISTICS_update (stats,
+ "# received encrypted without any KX",
+ 1,
+ GNUNET_NO);
+ if (NULL != t->kx_task)
+ {
+ GNUNET_SCHEDULER_cancel (t->kx_task);
+ t->kx_task = NULL;
+ }
+ send_kx (t,
+ ct,
+ &t->ax);
return;
case CADET_TUNNEL_KEY_AX_SENT_AND_RECV:
/* We send KX, and other peer send KX to us at the same time.
break;
}
- GNUNET_STATISTICS_update (stats,
- "# received encrypted",
- 1,
- GNUNET_NO);
decrypted_size = -1;
if (CADET_TUNNEL_KEY_OK == t->estate)
{
if (-1 != decrypted_size)
{
/* It worked! Treat this as authentication of the AX data! */
- t->ax.DHRs = NULL; /* aliased with ax.DHRs */
- t->ax.kx_0 = NULL; /* aliased with ax.DHRs */
cleanup_ax (&t->ax);
t->ax = *t->unverified_ax;
GNUNET_free (t->unverified_ax);
t->unverified_attempts);
if (t->unverified_attempts > MAX_UNVERIFIED_ATTEMPTS)
{
- t->unverified_ax->DHRs = NULL; /* aliased with ax.DHRs */
- t->unverified_ax->kx_0 = NULL; /* aliased with ax.DHRs */
cleanup_ax (t->unverified_ax);
GNUNET_free (t->unverified_ax);
t->unverified_ax = NULL;
if (-1 == decrypted_size)
{
/* Decryption failed for good, complain. */
- GNUNET_break_op (0);
LOG (GNUNET_ERROR_TYPE_WARNING,
- "%s failed to decrypt and validate encrypted data\n",
+ "%s failed to decrypt and validate encrypted data, retrying KX\n",
GCT_2s (t));
GNUNET_STATISTICS_update (stats,
"# unable to decrypt",
1,
GNUNET_NO);
+ if (NULL != t->kx_task)
+ {
+ GNUNET_SCHEDULER_cancel (t->kx_task);
+ t->kx_task = NULL;
+ }
+ send_kx (t,
+ ct,
+ &t->ax);
return;
}
+ GNUNET_STATISTICS_update (stats,
+ "# decrypted bytes",
+ decrypted_size,
+ GNUNET_NO);
/* The MST will ultimately call #handle_decrypted() on each message. */
+ t->current_ct = ct;
GNUNET_break_op (GNUNET_OK ==
GNUNET_MST_from_buffer (t->mst,
cbuf,
decrypted_size,
GNUNET_YES,
GNUNET_NO));
+ t->current_ct = NULL;
}
struct CadetTunnelQueueEntry *
GCT_send (struct CadetTunnel *t,
const struct GNUNET_MessageHeader *message,
- GNUNET_SCHEDULER_TaskCallback cont,
+ GCT_SendContinuation cont,
void *cont_cls)
{
struct CadetTunnelQueueEntry *tq;
&ax_msg[1],
message,
payload_size);
+ GNUNET_STATISTICS_update (stats,
+ "# encrypted bytes",
+ payload_size,
+ GNUNET_NO);
ax_msg->ax_header.Ns = htonl (t->ax.Ns++);
ax_msg->ax_header.PNs = htonl (t->ax.PNs);
/* FIXME: we should do this once, not once per message;
this is a point multiplication, and DHRs does not
change all the time. */
- GNUNET_CRYPTO_ecdhe_key_get_public (t->ax.DHRs,
+ GNUNET_CRYPTO_ecdhe_key_get_public (&t->ax.DHRs,
&ax_msg->ax_header.DHRs);
t_h_encrypt (&t->ax,
ax_msg);
{
n = ct->next;
iter (iter_cls,
- ct->cc);
+ ct);
}
for (struct CadetTConnection *ct = t->connection_busy_head;
NULL != ct;
{
n = ct->next;
iter (iter_cls,
- ct->cc);
+ ct);
}
}