This file is part of GNUnet.
Copyright (C) 2013, 2017, 2018 GNUnet e.V.
- GNUnet is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
+ GNUnet is free software: you can redistribute it and/or modify it
+ under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License,
+ or (at your option) any later version.
GNUnet is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
+ Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
- You should have received a copy of the GNU General Public License
- along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
+ SPDX-License-Identifier: AGPL3.0-or-later
*/
/**
* @file cadet/gnunet-service-cadet_tunnels.c
};
+/**
+ * Am I Alice or Betty (some call her Bob), or talking to myself?
+ *
+ * @param other the other peer
+ * @return #GNUNET_YES for Alice, #GNUNET_NO for Betty, #GNUNET_SYSERR if talking to myself
+ */
+static int
+alice_or_betty (const struct GNUNET_PeerIdentity *other)
+{
+ if (0 > GNUNET_CRYPTO_cmp_peer_identity (&my_full_id,
+ other))
+ return GNUNET_YES;
+ else if (0 < GNUNET_CRYPTO_cmp_peer_identity (&my_full_id,
+ other))
+ return GNUNET_NO;
+ else
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+}
+
+
/**
* Connection @a ct is now unready, clear it's ready flag
* and move it from the ready DLL to the busy DLL.
struct GNUNET_CADET_TunnelKeyExchangeMessage *msg;
enum GNUNET_CADET_KX_Flags flags;
+ if (GNUNET_YES != alice_or_betty (GCP_get_id (t->destination)))
+ return; /* only Alice may send KX */
if ( (NULL == ct) ||
(GNUNET_NO == ct->is_ready) )
ct = get_ready_connection (t);
msg->cid = *GCC_get_id (cc);
GNUNET_CRYPTO_ecdhe_key_get_public (&ax->kx_0,
&msg->ephemeral_key);
- GNUNET_CRYPTO_ecdhe_key_get_public (&ax->DHRs,
- &msg->ratchet_key);
+#if DEBUG_KX
+ msg->ephemeral_key_XXX = ax->kx_0;
+ msg->private_key_XXX = *my_private_key;
+#endif
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Sending KX with E=%s and R=%s on %s via %s in state %s\n",
- GNUNET_e2s (&msg->ephemeral_key),
- GNUNET_e2s2 (&msg->ratchet_key),
+ "Sending KX message to %s with ephemeral %s on CID %s\n",
GCT_2s (t),
- GCC_2s (cc),
- estate2s (t->estate));
+ GNUNET_e2s (&msg->ephemeral_key),
+ GNUNET_sh2s (&msg->cid.connection_of_tunnel));
+ 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);
t->next_kx_attempt = GNUNET_TIME_relative_to_absolute (t->kx_retry_delay);
&msg->kx.ephemeral_key);
GNUNET_CRYPTO_ecdhe_key_get_public (&ax->DHRs,
&msg->kx.ratchet_key);
+#if DEBUG_KX
+ msg->kx.ephemeral_key_XXX = ax->kx_0;
+ msg->kx.private_key_XXX = *my_private_key;
+ msg->r_ephemeral_key_XXX = ax->last_ephemeral;
+#endif
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending KX_AUTH message to %s with ephemeral %s on CID %s\n",
+ GCT_2s (t),
+ GNUNET_e2s (&msg->kx.ephemeral_key),
+ GNUNET_sh2s (&msg->kx.cid.connection_of_tunnel));
+
/* Compute authenticator (this is the main difference to #send_kx()) */
GNUNET_CRYPTO_hash (&ax->RK,
sizeof (ax->RK),
&msg->auth);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Sending KX_AUTH with E=%s and R=%s and A=%s on %s using %s\n",
- GNUNET_e2s (&msg->kx.ephemeral_key),
- GNUNET_e2s2 (&msg->kx.ratchet_key),
- GNUNET_h2s (&msg->auth),
- GCT_2s (t),
- GCC_2s (ct->cc));
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "... this is in response to foreign E=%s and R=%s\n",
- GNUNET_e2s2 (&ax->last_ephemeral),
- GNUNET_e2s (&ax->DHRr));
-
/* Compute when to be triggered again; actual job will
be scheduled via #connection_ready_cb() */
t->kx_retry_delay
const char salt[] = "CADET Axolotl salt";
int am_I_alice;
- if (0 > GNUNET_CRYPTO_cmp_peer_identity (&my_full_id,
- pid))
- am_I_alice = GNUNET_YES;
- else if (0 < GNUNET_CRYPTO_cmp_peer_identity (&my_full_id,
- pid))
- am_I_alice = GNUNET_NO;
- else
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
-
+ if (GNUNET_SYSERR == (am_I_alice = alice_or_betty (pid)))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
if (0 == memcmp (&ax->DHRr,
ratchet_key,
sizeof (*ratchet_key)))
- {
- GNUNET_STATISTICS_update (stats,
- "# Ratchet key already known",
- 1,
- GNUNET_NO);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Ratchet key already known. Ignoring KX.\n");
- return GNUNET_NO;
- }
+ {
+ GNUNET_STATISTICS_update (stats,
+ "# Ratchet key already known",
+ 1,
+ GNUNET_NO);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Ratchet key already known. Ignoring KX.\n");
+ return GNUNET_NO;
+ }
ax->DHRr = *ratchet_key;
ax->last_ephemeral = *ephemeral_key;
/* ECDH A B0 */
if (GNUNET_YES == am_I_alice)
- {
- GNUNET_CRYPTO_eddsa_ecdh (my_private_key, /* A */
- ephemeral_key, /* B0 */
- &key_material[0]);
- }
+ {
+ GNUNET_CRYPTO_eddsa_ecdh (my_private_key, /* a */
+ ephemeral_key, /* B0 */
+ &key_material[0]);
+ }
else
- {
- GNUNET_CRYPTO_ecdh_eddsa (&ax->kx_0, /* B0 */
- &pid->public_key, /* A */
- &key_material[0]);
- }
-
+ {
+ 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 */
- &pid->public_key, /* B */
- &key_material[1]);
- }
+ {
+ GNUNET_CRYPTO_ecdh_eddsa (&ax->kx_0, /* a0 */
+ &pid->public_key, /* B */
+ &key_material[1]);
+ }
else
- {
- GNUNET_CRYPTO_eddsa_ecdh (my_private_key, /* A */
- ephemeral_key, /* B0 */
- &key_material[1]);
- }
+ {
+ GNUNET_CRYPTO_eddsa_ecdh (my_private_key, /* b */
+ ephemeral_key, /* A0 */
+ &key_material[1]);
+ }
/* ECDH A0 B0 */
- 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]);
-
/* KDF */
GNUNET_CRYPTO_kdf (keys, sizeof (keys),
salt, sizeof (salt),
if (0 == memcmp (&ax->RK,
&keys[0],
sizeof (ax->RK)))
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Root key of handshake already known. Ignoring KX.\n");
- GNUNET_STATISTICS_update (stats,
- "# Root key already known",
- 1,
- GNUNET_NO);
- return GNUNET_NO;
- }
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Root key already known. Ignoring KX.\n");
+ GNUNET_STATISTICS_update (stats,
+ "# Root key already known",
+ 1,
+ GNUNET_NO);
+ return GNUNET_NO;
+ }
ax->RK = keys[0];
if (GNUNET_YES == am_I_alice)
- {
- ax->HKr = keys[1];
- ax->NHKs = keys[2];
- ax->NHKr = keys[3];
- ax->CKr = keys[4];
- ax->ratchet_flag = GNUNET_YES;
- }
+ {
+ ax->HKr = keys[1];
+ ax->NHKs = keys[2];
+ ax->NHKr = keys[3];
+ ax->CKr = keys[4];
+ ax->ratchet_flag = GNUNET_YES;
+ }
else
- {
- ax->HKs = keys[1];
- ax->NHKr = keys[2];
- ax->NHKs = keys[3];
- ax->CKs = keys[4];
- ax->ratchet_flag = GNUNET_NO;
- ax->ratchet_expiration
- = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(),
- ratchet_time);
- }
+ {
+ ax->HKs = keys[1];
+ ax->NHKr = keys[2];
+ ax->NHKs = keys[3];
+ ax->CKs = keys[4];
+ ax->ratchet_flag = GNUNET_NO;
+ ax->ratchet_expiration
+ = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(),
+ ratchet_time);
+ }
return GNUNET_OK;
}
const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg)
{
struct CadetTunnel *t = ct->t;
- struct CadetTunnelAxolotl *ax;
int ret;
GNUNET_STATISTICS_update (stats,
"# KX received",
1,
GNUNET_NO);
+ if (GNUNET_YES ==
+ alice_or_betty (GCP_get_id (t->destination)))
+ {
+ /* Betty/Bob is not allowed to send KX! */
+ GNUNET_break_op (0);
+ return;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Received KX message from %s with ephemeral %s from %s on connection %s\n",
+ GCT_2s (t),
+ GNUNET_e2s (&msg->ephemeral_key),
+ GNUNET_i2s (GCP_get_id (t->destination)),
+ GCC_2s (ct->cc));
#if 1
if ( (0 ==
memcmp (&t->ax.DHRr,
sizeof (msg->ephemeral_key))) )
{
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Got duplicate KX. Firing back KX_AUTH.\n");
GNUNET_STATISTICS_update (stats,
"# Duplicate KX received",
1,
/* We only keep ONE unverified KX around, so if there is an existing one,
clean it up. */
if (NULL != t->unverified_ax)
+ {
+ if ( (0 ==
+ memcmp (&t->unverified_ax->DHRr,
+ &msg->ratchet_key,
+ sizeof (msg->ratchet_key))) &&
+ (0 ==
+ memcmp (&t->unverified_ax->last_ephemeral,
+ &msg->ephemeral_key,
+ sizeof (msg->ephemeral_key))) )
{
- if ( (0 ==
- memcmp (&t->unverified_ax->DHRr,
- &msg->ratchet_key,
- sizeof (msg->ratchet_key))) &&
- (0 ==
- memcmp (&t->unverified_ax->last_ephemeral,
- &msg->ephemeral_key,
- sizeof (msg->ephemeral_key))) )
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Got duplicate unverified KX on %s. Fire back KX_AUTH again.\n",
- GCT_2s (t));
- GNUNET_STATISTICS_update (stats,
- "# Duplicate unverified KX received",
- 1,
- GNUNET_NO);
-#if 1
- send_kx_auth (t,
- ct,
- t->unverified_ax,
- GNUNET_NO);
- return;
-#endif
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Dropping old unverified KX state. Got a fresh KX for %s.\n",
- GCT_2s (t));
GNUNET_STATISTICS_update (stats,
- "# Unverified KX dropped for fresh KX",
+ "# Duplicate unverified KX received",
1,
GNUNET_NO);
- GNUNET_break (NULL == t->unverified_ax->skipped_head);
- memset (t->unverified_ax,
- 0,
- sizeof (struct CadetTunnelAxolotl));
- t->unverified_ax->DHRs = t->ax.DHRs;
- t->unverified_ax->kx_0 = t->ax.kx_0;
+#if 1
+ send_kx_auth (t,
+ ct,
+ t->unverified_ax,
+ GNUNET_NO);
+ return;
+#endif
}
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Dropping old unverified KX state.\n");
+ GNUNET_STATISTICS_update (stats,
+ "# Unverified KX dropped for fresh KX",
+ 1,
+ GNUNET_NO);
+ GNUNET_break (NULL == t->unverified_ax->skipped_head);
+ memset (t->unverified_ax,
+ 0,
+ sizeof (struct CadetTunnelAxolotl));
+ }
else
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Creating fresh unverified KX for %s.\n",
- GCT_2s (t));
- GNUNET_STATISTICS_update (stats,
- "# Fresh KX setup",
- 1,
- GNUNET_NO);
- t->unverified_ax = GNUNET_new (struct CadetTunnelAxolotl);
- t->unverified_ax->DHRs = t->ax.DHRs;
- t->unverified_ax->kx_0 = t->ax.kx_0;
- }
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Creating fresh unverified KX for %s\n",
+ GCT_2s (t));
+ GNUNET_STATISTICS_update (stats,
+ "# Fresh KX setup",
+ 1,
+ GNUNET_NO);
+ t->unverified_ax = GNUNET_new (struct CadetTunnelAxolotl);
+ }
/* Set as the 'current' RK/DHRr the one we are currently using,
so that the duplicate-detection logic of
#update_ax_by_kx can work. */
t->unverified_ax->RK = t->ax.RK;
t->unverified_ax->DHRr = t->ax.DHRr;
+ t->unverified_ax->DHRs = t->ax.DHRs;
+ t->unverified_ax->kx_0 = t->ax.kx_0;
t->unverified_attempts = 0;
- ax = t->unverified_ax;
/* Update 'ax' by the new key material */
- ret = update_ax_by_kx (ax,
+ ret = update_ax_by_kx (t->unverified_ax,
GCP_get_id (t->destination),
&msg->ephemeral_key,
&msg->ratchet_key);
GNUNET_break (GNUNET_SYSERR != ret);
if (GNUNET_OK != ret)
- {
- GNUNET_STATISTICS_update (stats,
- "# Useless KX",
- 1,
- GNUNET_NO);
- return; /* duplicate KX, nothing to do */
- }
+ {
+ GNUNET_STATISTICS_update (stats,
+ "# Useless KX",
+ 1,
+ GNUNET_NO);
+ return; /* duplicate KX, nothing to do */
+ }
/* move ahead in our state machine */
if (CADET_TUNNEL_KEY_UNINITIALIZED == t->estate)
GCT_change_estate (t,
/* KX is still not done, try again our end. */
if (CADET_TUNNEL_KEY_OK != t->estate)
- {
- if (NULL != t->kx_task)
- GNUNET_SCHEDULER_cancel (t->kx_task);
- t->kx_task
- = GNUNET_SCHEDULER_add_now (&retry_kx,
- t);
- }
+ {
+ if (NULL != t->kx_task)
+ GNUNET_SCHEDULER_cancel (t->kx_task);
+ t->kx_task
+ = GNUNET_SCHEDULER_add_now (&retry_kx,
+ t);
+ }
+}
+
+
+#if DEBUG_KX
+static void
+check_ee (const struct GNUNET_CRYPTO_EcdhePrivateKey *e1,
+ const struct GNUNET_CRYPTO_EcdhePrivateKey *e2)
+{
+ struct GNUNET_CRYPTO_EcdhePublicKey p1;
+ struct GNUNET_CRYPTO_EcdhePublicKey p2;
+ struct GNUNET_HashCode hc1;
+ struct GNUNET_HashCode hc2;
+
+ GNUNET_CRYPTO_ecdhe_key_get_public (e1,
+ &p1);
+ GNUNET_CRYPTO_ecdhe_key_get_public (e2,
+ &p2);
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CRYPTO_ecc_ecdh (e1,
+ &p2,
+ &hc1));
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CRYPTO_ecc_ecdh (e2,
+ &p1,
+ &hc2));
+ GNUNET_break (0 == memcmp (&hc1,
+ &hc2,
+ sizeof (hc1)));
+}
+
+
+static void
+check_ed (const struct GNUNET_CRYPTO_EcdhePrivateKey *e1,
+ const struct GNUNET_CRYPTO_EddsaPrivateKey *e2)
+{
+ struct GNUNET_CRYPTO_EcdhePublicKey p1;
+ struct GNUNET_CRYPTO_EddsaPublicKey p2;
+ struct GNUNET_HashCode hc1;
+ struct GNUNET_HashCode hc2;
+
+ GNUNET_CRYPTO_ecdhe_key_get_public (e1,
+ &p1);
+ GNUNET_CRYPTO_eddsa_key_get_public (e2,
+ &p2);
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CRYPTO_ecdh_eddsa (e1,
+ &p2,
+ &hc1));
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CRYPTO_eddsa_ecdh (e2,
+ &p1,
+ &hc2));
+ GNUNET_break (0 == memcmp (&hc1,
+ &hc2,
+ sizeof (hc1)));
}
+static void
+test_crypto_bug (const struct GNUNET_CRYPTO_EcdhePrivateKey *e1,
+ const struct GNUNET_CRYPTO_EcdhePrivateKey *e2,
+ const struct GNUNET_CRYPTO_EddsaPrivateKey *d1,
+ const struct GNUNET_CRYPTO_EddsaPrivateKey *d2)
+{
+ check_ee (e1, e2);
+ check_ed (e1, d2);
+ check_ed (e2, d1);
+}
+
+#endif
+
+
/**
* Handle KX_AUTH message.
*
GNUNET_NO);
if ( (CADET_TUNNEL_KEY_UNINITIALIZED == t->estate) ||
(CADET_TUNNEL_KEY_AX_RECV == t->estate) )
- {
- /* Confusing, we got a KX_AUTH before we even send our own
- KX. This should not happen. We'll send our own KX ASAP anyway,
- so let's ignore this here. */
- GNUNET_break_op (0);
- return;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Handling KX_AUTH message for %s with E=%s and R=%s and A=%s\n",
- GCT_2s (t),
- GNUNET_e2s (&msg->kx.ephemeral_key),
- GNUNET_e2s2 (&msg->kx.ratchet_key),
- GNUNET_h2s (&msg->auth));
{
- struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
- struct GNUNET_CRYPTO_EcdhePublicKey ratchet_key;
-
- GNUNET_CRYPTO_ecdhe_key_get_public (&t->ax.kx_0,
- &ephemeral_key);
- GNUNET_CRYPTO_ecdhe_key_get_public (&t->ax.DHRs,
- &ratchet_key);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "... my E=%s and R=%s\n",
- GNUNET_e2s2 (&ephemeral_key),
- GNUNET_e2s (&ratchet_key));
+ /* Confusing, we got a KX_AUTH before we even send our own
+ KX. This should not happen. We'll send our own KX ASAP anyway,
+ so let's ignore this here. */
+ GNUNET_break_op (0);
+ return;
}
-
-
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Handling KX_AUTH message from %s with ephemeral %s\n",
+ GCT_2s (t),
+ GNUNET_e2s (&msg->kx.ephemeral_key));
/* We do everything in ax_tmp until we've checked the authentication
so we don't clobber anything we care about by accident. */
ax_tmp = t->ax;
"# KX_AUTH not using our last KX received (auth failure)",
1,
GNUNET_NO);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "AUTH missmatch: got %s, expected %s\n",
- GNUNET_h2s (&msg->auth),
- GNUNET_h2s2 (&kx_auth));
- send_kx (t,
- ct,
- &t->ax);
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "KX AUTH mismatch!\n");
+#if DEBUG_KX
+ {
+ struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
+
+ GNUNET_CRYPTO_ecdhe_key_get_public (&ax_tmp.kx_0,
+ &ephemeral_key);
+ if (0 != memcmp (&ephemeral_key,
+ &msg->r_ephemeral_key_XXX,
+ sizeof (ephemeral_key)))
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "My ephemeral is %s!\n",
+ GNUNET_e2s (&ephemeral_key));
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "Response is for ephemeral %s!\n",
+ GNUNET_e2s (&msg->r_ephemeral_key_XXX));
+ }
+ else
+ {
+ test_crypto_bug (&ax_tmp.kx_0,
+ &msg->kx.ephemeral_key_XXX,
+ my_private_key,
+ &msg->kx.private_key_XXX);
+ }
+ }
+#endif
+ if (NULL == t->kx_task)
+ t->kx_task
+ = GNUNET_SCHEDULER_add_at (t->next_kx_attempt,
+ &retry_kx,
+ t);
return;
}
/* Yep, we're good. */
Nothing to do here. */
break;
}
+ if (0 != (GNUNET_CADET_KX_FLAG_FORCE_REPLY & ntohl (msg->kx.flags)))
+ {
+ send_kx_auth (t,
+ NULL,
+ &t->ax,
+ GNUNET_NO);
+ }
}
{
case CADET_TUNNEL_KEY_UNINITIALIZED:
/* Do not begin KX if WE have no channels waiting! */
- if (0 == GCT_count_channels (t))
- return;
+ if (0 != GNUNET_TIME_absolute_get_remaining (t->next_kx_attempt).rel_value_us)
+ return; /* wait for timeout before retrying */
/* We are uninitialized, just transmit immediately,
without undue delay. */
if (NULL != t->kx_task)
send_kx (t,
ct,
&t->ax);
+ if ( (0 ==
+ GCT_count_channels (t)) &&
+ (NULL == t->destroy_task) )
+ {
+ t->destroy_task
+ = GNUNET_SCHEDULER_add_delayed (IDLE_DESTROY_DELAY,
+ &destroy_tunnel,
+ t);
+ }
break;
case CADET_TUNNEL_KEY_AX_RECV:
case CADET_TUNNEL_KEY_AX_SENT:
case CADET_TUNNEL_KEY_OK:
if (GNUNET_YES == t->kx_auth_requested)
{
+ if (0 != GNUNET_TIME_absolute_get_remaining (t->next_kx_attempt).rel_value_us)
+ return; /* wait for timeout */
if (NULL != t->kx_task)
{
GNUNET_SCHEDULER_cancel (t->kx_task);
{
struct EvaluationSummary *es = cls;
struct CadetConnection *cc = ct->cc;
- struct CadetPeerPath *ps = GCC_get_path (cc);
+ unsigned int ct_length;
+ struct CadetPeerPath *ps;
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;
+ ps = GCC_get_path (cc,
+ &ct_length);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Evaluating path %s of existing %s\n",
+ GCPP_2s (ps),
+ GCC_2s (cc));
if (ps == es->path)
{
LOG (GNUNET_ERROR_TYPE_DEBUG,
es->duplicate = GNUNET_YES;
return;
}
+ if (NULL != es->path)
+ {
+ int duplicate = GNUNET_YES;
+
+ for (unsigned int i=0;i<ct_length;i++)
+ {
+ GNUNET_assert (GCPP_get_length (es->path) > i);
+ if (GCPP_get_peer_at_offset (es->path,
+ i) !=
+ GCPP_get_peer_at_offset (ps,
+ i))
+ {
+ duplicate = GNUNET_NO;
+ break;
+ }
+ }
+ if (GNUNET_YES == duplicate)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Ignoring overlapping path %s.\n",
+ GCPP_2s (es->path));
+ es->duplicate = GNUNET_YES;
+ return;
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Known path %s differs from proposed path\n",
+ GCPP_2s (ps));
+ }
+ }
+
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);
struct CadetTConnection *ct;
GNUNET_assert (off < GCPP_get_length (path));
+ GNUNET_assert (GCPP_get_peer_at_offset (path,
+ off) == t->destination);
es.min_length = UINT_MAX;
es.max_length = 0;
es.max_desire = 0;
es.worst = NULL;
/* Compute evaluation summary over existing connections. */
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Evaluating proposed path %s for target %s\n",
+ GCPP_2s (path),
+ GCT_2s (t));
+ /* FIXME: suspect this does not ACTUALLY iterate
+ over all existing paths, otherwise dup detection
+ should work!!! */
GCT_iterate_connections (t,
&evaluate_connection,
&es);
unsigned int off)
{
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Considering %s for %s\n",
+ "Considering %s for %s (offset %u)\n",
GCPP_2s (p),
- GCT_2s (t));
+ GCT_2s (t),
+ off);
(void) consider_path_cb (t,
p,
off);