*/
struct CadetTunnelKXCtx
{
+ /**
+ * Encryption ("our") old key, for encrypting traffic sent by us
+ * end before the key exchange is finished or times out.
+ */
+ struct GNUNET_CRYPTO_SymmetricSessionKey e_key_old;
+
/**
* Decryption ("their") old key, for decrypting traffic sent by the
* other end before the key exchange started.
* Challenge to send in a ping and expect in the pong.
*/
uint32_t challenge;
+
+ /**
+ * When the rekey started. One minute after this the new key will be used.
+ */
+ struct GNUNET_TIME_Absolute rekey_start_time;
+
+ /**
+ * Task for delayed destruction of the Key eXchange context, to allow delayed
+ * messages with the old key to be decrypted successfully.
+ */
+ GNUNET_SCHEDULER_TaskIdentifier finish_task;
};
/**
* Struct containing all information regarding a tunnel to a peer.
*/
-struct CadetTunnel3
+struct CadetTunnel
{
/**
* Endpoint of the tunnel.
/**
* State of the tunnel connectivity.
*/
- enum CadetTunnel3CState cstate;
+ enum CadetTunnelCState cstate;
/**
* State of the tunnel encryption.
*/
- enum CadetTunnel3EState estate;
+ enum CadetTunnelEState estate;
/**
* Key eXchange context.
*/
struct CadetTunnelKXCtx *kx_ctx;
+ /**
+ * Peer's ephemeral key, to recreate @c e_key and @c d_key when own ephemeral
+ * key changes.
+ */
+ struct GNUNET_CRYPTO_EcdhePublicKey peers_ephemeral_key;
+
/**
* Encryption ("our") key.
*/
/**
* Tunnel.
*/
- struct CadetTunnel3 *t;
+ struct CadetTunnel *t;
/**
* Tunnel queue given to the channel to cancel request. Update on send_queued.
*/
- struct CadetTunnel3Queue *tq;
+ struct CadetTunnelQueue *tq;
/**
* Message to send.
/**
* Handle for messages queued but not yet sent.
*/
-struct CadetTunnel3Queue
+struct CadetTunnelQueue
{
/**
* Connection queue handle, to cancel if necessary.
/**
* Continuation to call once sent.
*/
- GMT_sent cont;
+ GCT_sent cont;
/**
* Closure for @c cont.
* @return String representation.
*/
static const char *
-cstate2s (enum CadetTunnel3CState cs)
+cstate2s (enum CadetTunnelCState cs)
{
static char buf[128];
* @return String representation.
*/
static const char *
-estate2s (enum CadetTunnel3EState es)
+estate2s (enum CadetTunnelEState es)
{
static char buf[128];
* @return #GNUNET_YES if ready, #GNUNET_NO otherwise
*/
static int
-is_ready (struct CadetTunnel3 *t)
+is_ready (struct CadetTunnel *t)
{
int ready;
- GMT_debug (t);
+ GCT_debug (t);
ready = (CADET_TUNNEL3_READY == t->cstate && CADET_TUNNEL3_KEY_OK == t->estate);
- ready = ready || GMT_is_loopback (t);
+ ready = ready || GCT_is_loopback (t);
return ready;
}
int fwd;
/* If channel is outgoing, is origin in the FWD direction and fwd is YES */
- fwd = GMCH_is_origin (tch->ch, GNUNET_YES);
+ fwd = GCCH_is_origin (tch->ch, GNUNET_YES);
- return GMCH_get_buffer (tch->ch, fwd);
+ return GCCH_get_buffer (tch->ch, fwd);
}
int fwd;
/* If channel is outgoing, is origin in the FWD direction and fwd is YES */
- fwd = GMCH_is_origin (tch->ch, GNUNET_YES);
+ fwd = GCCH_is_origin (tch->ch, GNUNET_YES);
- return GMCH_get_allowed (tch->ch, fwd);
+ return GCCH_get_allowed (tch->ch, fwd);
}
int fwd;
/* If connection is outgoing, is origin in the FWD direction and fwd is YES */
- fwd = GMC_is_origin (tc->c, GNUNET_YES);
+ fwd = GCC_is_origin (tc->c, GNUNET_YES);
- return GMC_get_buffer (tc->c, fwd);
+ return GCC_get_buffer (tc->c, fwd);
}
int fwd;
/* If connection is outgoing, is origin in the FWD direction and fwd is YES */
- fwd = GMC_is_origin (tc->c, GNUNET_YES);
+ fwd = GCC_is_origin (tc->c, GNUNET_YES);
- return GMC_get_allowed (tc->c, fwd);
+ return GCC_get_allowed (tc->c, fwd);
}
* @return GNUNET_OK if message is fine, GNUNET_SYSERR otherwise.
*/
int
-check_ephemeral (struct CadetTunnel3 *t,
+check_ephemeral (struct CadetTunnel *t,
const struct GNUNET_CADET_KX_Ephemeral *msg)
{
/* Check message size */
/* Check origin */
if (0 != memcmp (&msg->origin_identity,
- GMP_get_id (t->peer),
+ GCP_get_id (t->peer),
sizeof (struct GNUNET_PeerIdentity)))
return GNUNET_SYSERR;
}
+/**
+ * Calculate HMAC.
+ *
+ * @param t Tunnel to get keys from.
+ * @param plaintext Content to HMAC.
+ * @param size Size of @c plaintext.
+ * @param iv Initialization vector for the message.
+ * @param outgoing Is this an outgoing message that we encrypted?
+ * @param hmac Destination to store the HMAC.
+ */
+static void
+t_hmac (struct CadetTunnel *t, const void *plaintext, size_t size, uint32_t iv,
+ int outgoing, struct GNUNET_CADET_Hash *hmac)
+{
+ struct GNUNET_CRYPTO_AuthKey auth_key;
+ static const char ctx[] = "cadet authentication key";
+ struct GNUNET_CRYPTO_SymmetricSessionKey *key;
+ struct GNUNET_HashCode hash;
+
+ key = outgoing ? &t->e_key : &t->d_key;
+ GNUNET_CRYPTO_hmac_derive_key (&auth_key, key,
+ &iv, sizeof (iv),
+ key, sizeof (*key),
+ ctx, sizeof (ctx),
+ NULL);
+ GNUNET_CRYPTO_hmac (&auth_key, plaintext, size, &hash);
+ memcpy (hmac, &hash, sizeof (*hmac));
+}
+
+
/**
* Encrypt data with the tunnel key.
*
* @param src Source of the plaintext. Can overlap with @c dst.
* @param size Size of the plaintext.
* @param iv Initialization Vector to use.
+ * @param force_newest_key Force the use of the newest key, otherwise
+ * CADET will use the old key when allowed.
+ * This can happen in the case when a KX is going on
+ * and the old one hasn't expired.
*/
static int
-t_encrypt (struct CadetTunnel3 *t,
- void *dst, const void *src,
- size_t size, uint32_t iv)
+t_encrypt (struct CadetTunnel *t, void *dst, const void *src,
+ size_t size, uint32_t iv, int force_newest_key)
{
struct GNUNET_CRYPTO_SymmetricInitializationVector siv;
+ struct GNUNET_CRYPTO_SymmetricSessionKey *e_key;
size_t out_size;
LOG (GNUNET_ERROR_TYPE_DEBUG, " t_encrypt start\n");
- GNUNET_CRYPTO_symmetric_derive_iv (&siv, &t->e_key, &iv, sizeof (iv), NULL);
+ if (GNUNET_NO == force_newest_key
+ && NULL != t->kx_ctx
+ && GNUNET_SCHEDULER_NO_TASK == t->kx_ctx->finish_task)
+ {
+ struct GNUNET_TIME_Relative age;
+
+ age = GNUNET_TIME_absolute_get_duration (t->kx_ctx->rekey_start_time);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ " key exchange in progress, started %s ago\n",
+ GNUNET_STRINGS_relative_time_to_string (age, GNUNET_YES));
+ if (age.rel_value_us < GNUNET_TIME_UNIT_MINUTES.rel_value_us)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " using old key\n");
+ e_key = &t->kx_ctx->e_key_old;
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " using new key\n");
+ e_key = &t->e_key;
+ }
+ }
+ else
+ {
+ e_key = &t->e_key;
+ }
+ GNUNET_CRYPTO_symmetric_derive_iv (&siv, e_key, &iv, sizeof (iv), NULL);
LOG (GNUNET_ERROR_TYPE_DEBUG, " t_encrypt IV derived\n");
- out_size = GNUNET_CRYPTO_symmetric_encrypt (src, size, &t->e_key, &siv, dst);
+ out_size = GNUNET_CRYPTO_symmetric_encrypt (src, size, e_key, &siv, dst);
LOG (GNUNET_ERROR_TYPE_DEBUG, " t_encrypt end\n");
return out_size;
/**
- * Decrypt data with the tunnel key.
+ * Decrypt and verify data with the appropriate tunnel key.
+ *
+ * @param key Key to use.
+ * @param dst Destination for the plaintext.
+ * @param src Source of the encrypted data. Can overlap with @c dst.
+ * @param size Size of the encrypted data.
+ * @param iv Initialization Vector to use.
+ *
+ * @return Size of the decrypted data, -1 if an error was encountered.
+ */
+static int
+decrypt (const struct GNUNET_CRYPTO_SymmetricSessionKey *key,
+ void *dst, const void *src, size_t size, uint32_t iv)
+{
+ struct GNUNET_CRYPTO_SymmetricInitializationVector siv;
+ size_t out_size;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " decrypt start\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " decrypt iv\n");
+ GNUNET_CRYPTO_symmetric_derive_iv (&siv, key, &iv, sizeof (iv), NULL);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " decrypt iv done\n");
+ out_size = GNUNET_CRYPTO_symmetric_decrypt (src, size, key, &siv, dst);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " decrypt end\n");
+
+ return out_size;
+}
+
+
+/**
+ * Decrypt and verify data with the most recent tunnel key.
*
* @param t Tunnel whose key to use.
* @param dst Destination for the plaintext.
* @param src Source of the encrypted data. Can overlap with @c dst.
* @param size Size of the encrypted data.
* @param iv Initialization Vector to use.
+ *
+ * @return Size of the decrypted data, -1 if an error was encountered.
*/
static int
-t_decrypt (struct CadetTunnel3 *t,
- void *dst, const void *src,
+t_decrypt (struct CadetTunnel *t, void *dst, const void *src,
size_t size, uint32_t iv)
{
- struct GNUNET_CRYPTO_SymmetricInitializationVector siv;
struct GNUNET_CRYPTO_SymmetricSessionKey *key;
size_t out_size;
{
key = &t->d_key;
}
- else if (NULL != t->kx_ctx)
- {
- key = &t->kx_ctx->d_key_old;
- }
else
{
GNUNET_STATISTICS_update (stats, "# non decryptable data", 1, GNUNET_NO);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "WARNING got data on %s without a valid key\n",
- GMT_2s (t));
- GMT_debug (t);
- return 0;
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "got data on %s without a valid key\n",
+ GCT_2s (t));
+ GCT_debug (t);
+ return -1;
}
- LOG (GNUNET_ERROR_TYPE_DEBUG, " t_decrypt iv\n");
- GNUNET_CRYPTO_symmetric_derive_iv (&siv, key, &iv, sizeof (iv), NULL);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " t_decrypt iv done\n");
- out_size = GNUNET_CRYPTO_symmetric_decrypt (src, size, key, &siv, dst);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " t_decrypt end\n");
+ out_size = decrypt (key, dst, src, size, iv);
return out_size;
}
+/**
+ * Decrypt and verify data with the appropriate tunnel key and verify that the
+ * data has not been altered since it was sent by the remote peer.
+ *
+ * @param t Tunnel whose key to use.
+ * @param dst Destination for the plaintext.
+ * @param src Source of the encrypted data. Can overlap with @c dst.
+ * @param size Size of the encrypted data.
+ * @param iv Initialization Vector to use.
+ * @param msg_hmac HMAC of the message, cannot be NULL.
+ *
+ * @return Size of the decrypted data, -1 if an error was encountered.
+ */
+static int
+t_decrypt_and_validate (struct CadetTunnel *t,
+ void *dst, const void *src,
+ size_t size, uint32_t iv,
+ const struct GNUNET_CADET_Hash *msg_hmac)
+{
+ struct GNUNET_CRYPTO_SymmetricSessionKey *key;
+ struct GNUNET_CADET_Hash hmac;
+ int decrypted_size;
+
+ /* Try primary (newest) key */
+ key = &t->d_key;
+ decrypted_size = decrypt (key, dst, src, size, iv);
+ t_hmac (t, src, size, iv, GNUNET_NO, &hmac);
+ if (0 == memcmp (msg_hmac, &hmac, sizeof (hmac)))
+ return decrypted_size;
+
+ /* If no key exchange is going on, we just failed */
+ if (NULL == t->kx_ctx)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Failed checksum validation on tunnel %s with no KX\n",
+ GCT_2s (t));
+ GNUNET_STATISTICS_update (stats, "# wrong HMAC", 1, GNUNET_NO);
+ return -1;
+ }
+
+ /* Try secondary (from previous KX period) key */
+ key = &t->kx_ctx->d_key_old;
+ decrypted_size = decrypt (key, dst, src, size, iv);
+ t_hmac (t, src, size, iv, GNUNET_NO, &hmac);
+ if (0 == memcmp (msg_hmac, &hmac, sizeof (hmac)))
+ return decrypted_size;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Failed checksum validation on tunnel %s with KX\n",
+ GCT_2s (t));
+ GNUNET_STATISTICS_update (stats, "# wrong HMAC", 1, GNUNET_NO);
+ return -1;
+}
+
+
/**
* Create key material by doing ECDH on the local and remote ephemeral keys.
*
}
}
+
/**
* Create a symmetic key from the identities of both ends and the key material
* from ECDH.
NULL);
}
+
+/**
+ * Derive the tunnel's keys using our own and the peer's ephemeral keys.
+ *
+ * @param t Tunnel for which to create the keys.
+ */
+static void
+create_keys (struct CadetTunnel *t)
+{
+ struct GNUNET_HashCode km;
+
+ derive_key_material (&km, &t->peers_ephemeral_key);
+ derive_symmertic (&t->e_key, &my_full_id, GCP_get_id (t->peer), &km);
+ derive_symmertic (&t->d_key, GCP_get_id (t->peer), &my_full_id, &km);
+}
+
+
/**
* Pick a connection on which send the next data message.
*
* @return The connection on which to send the next message.
*/
static struct CadetConnection *
-tunnel_get_connection (struct CadetTunnel3 *t)
+tunnel_get_connection (struct CadetTunnel *t)
{
struct CadetTConnection *iter;
struct CadetConnection *best;
unsigned int qn;
unsigned int lowest_q;
- LOG (GNUNET_ERROR_TYPE_DEBUG, "tunnel_get_connection %s\n", GMT_2s (t));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "tunnel_get_connection %s\n", GCT_2s (t));
best = NULL;
lowest_q = UINT_MAX;
for (iter = t->connection_head; NULL != iter; iter = iter->next)
{
LOG (GNUNET_ERROR_TYPE_DEBUG, " connection %s: %u\n",
- GMC_2s (iter->c), GMC_get_state (iter->c));
- if (CADET_CONNECTION_READY == GMC_get_state (iter->c))
+ GCC_2s (iter->c), GCC_get_state (iter->c));
+ if (CADET_CONNECTION_READY == GCC_get_state (iter->c))
{
- qn = GMC_get_qn (iter->c, GMC_is_origin (iter->c, GNUNET_YES));
+ qn = GCC_get_qn (iter->c, GCC_is_origin (iter->c, GNUNET_YES));
LOG (GNUNET_ERROR_TYPE_DEBUG, " q_n %u, \n", qn);
if (qn < lowest_q)
{
}
}
}
- LOG (GNUNET_ERROR_TYPE_DEBUG, " selected: connection %s\n", GMC_2s (best));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " selected: connection %s\n", GCC_2s (best));
return best;
}
struct CadetConnectionQueue *q,
uint16_t type, int fwd, size_t size)
{
- struct CadetTunnel3Queue *qt = cls;
- struct CadetTunnel3 *t;
+ struct CadetTunnelQueue *qt = cls;
+ struct CadetTunnel *t;
LOG (GNUNET_ERROR_TYPE_DEBUG, "tun_message_sent\n");
GNUNET_assert (NULL != qt->cont);
- t = NULL == c ? NULL : GMC_get_tunnel (c);
+ t = NULL == c ? NULL : GCC_get_tunnel (c);
qt->cont (qt->cont_cls, t, qt, type, size);
GNUNET_free (qt);
}
* @param msg Message itself (copy will be made).
*/
static struct CadetTunnelDelayed *
-queue_data (struct CadetTunnel3 *t, const struct GNUNET_MessageHeader *msg)
+queue_data (struct CadetTunnel *t, const struct GNUNET_MessageHeader *msg)
{
struct CadetTunnelDelayed *tqd;
uint16_t size = ntohs (msg->size);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "queue data on Tunnel %s\n", GMT_2s (t));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "queue data on Tunnel %s\n", GCT_2s (t));
if (GNUNET_YES == is_ready (t))
{
}
-/**
- * Calculate HMAC.
- *
- * @param t Tunnel to get keys from.
- * @param plaintext Content to HMAC.
- * @param size Size of @c plaintext.
- * @param iv Initialization vector for the message.
- * @param outgoing Is this an outgoing message that we encrypted?
- * @param hmac Destination to store the HMAC.
- */
-static void
-t_hmac (struct CadetTunnel3 *t, const void *plaintext, size_t size, uint32_t iv,
- int outgoing, struct GNUNET_CADET_Hash *hmac)
-{
- struct GNUNET_CRYPTO_AuthKey auth_key;
- static const char ctx[] = "cadet authentication key";
- struct GNUNET_CRYPTO_SymmetricSessionKey *key;
- struct GNUNET_HashCode hash;
-
- key = outgoing ? &t->e_key : &t->d_key;
- GNUNET_CRYPTO_hmac_derive_key (&auth_key, key,
- &iv, sizeof (iv),
- key, sizeof (*key),
- ctx, sizeof (ctx),
- NULL);
- GNUNET_CRYPTO_hmac (&auth_key, plaintext, size, &hash);
- memcpy (hmac, &hash, sizeof (*hmac));
-}
-
-
/**
* Sends an already built message on a tunnel, encrypting it and
* choosing the best connection.
*
* @return Handle to cancel message. NULL if @c cont is NULL.
*/
-static struct CadetTunnel3Queue *
+static struct CadetTunnelQueue *
send_prebuilt_message (const struct GNUNET_MessageHeader *message,
- struct CadetTunnel3 *t, struct CadetConnection *c,
- int force, GMT_sent cont, void *cont_cls,
- struct CadetTunnel3Queue *existing_q)
+ struct CadetTunnel *t, struct CadetConnection *c,
+ int force, GCT_sent cont, void *cont_cls,
+ struct CadetTunnelQueue *existing_q)
{
- struct CadetTunnel3Queue *tq;
+ struct CadetTunnelQueue *tq;
struct GNUNET_CADET_Encrypted *msg;
size_t size = ntohs (message->size);
char cbuf[sizeof (struct GNUNET_CADET_Encrypted) + size];
uint16_t type;
int fwd;
- LOG (GNUNET_ERROR_TYPE_DEBUG, "GMT Send on Tunnel %s\n", GMT_2s (t));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "GMT Send on Tunnel %s\n", GCT_2s (t));
if (GNUNET_NO == is_ready (t))
{
tqd = queue_data (t, message);
if (NULL == cont)
return NULL;
- tq = GNUNET_new (struct CadetTunnel3Queue);
+ tq = GNUNET_new (struct CadetTunnelQueue);
tq->tqd = tqd;
tqd->tq = tq;
tq->cont = cont;
return tq;
}
- GNUNET_assert (GNUNET_NO == GMT_is_loopback (t));
+ GNUNET_assert (GNUNET_NO == GCT_is_loopback (t));
iv = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX);
msg = (struct GNUNET_CADET_Encrypted *) cbuf;
msg->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED);
msg->iv = iv;
- GNUNET_assert (t_encrypt (t, &msg[1], message, size, iv) == size);
+ GNUNET_assert (t_encrypt (t, &msg[1], message, size, iv, GNUNET_NO) == size);
t_hmac (t, &msg[1], size, iv, GNUNET_YES, &msg->hmac);
msg->header.size = htons (sizeof (struct GNUNET_CADET_Encrypted) + size);
|| CADET_TUNNEL3_SEARCHING != t->cstate)
{
GNUNET_break (0);
- GMT_debug (t);
+ GCT_debug (t);
}
return NULL;
}
case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY:
case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_ACK:
case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_NACK:
- msg->cid = *GMC_get_id (c);
+ msg->cid = *GCC_get_id (c);
msg->ttl = htonl (default_ttl);
break;
default:
GNUNET_break (0);
}
- LOG (GNUNET_ERROR_TYPE_DEBUG, "type %s\n", GM_m2s (type));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "type %s\n", GC_m2s (type));
- fwd = GMC_is_origin (c, GNUNET_YES);
+ fwd = GCC_is_origin (c, GNUNET_YES);
if (NULL == cont)
{
GNUNET_break (NULL ==
- GMC_send_prebuilt_message (&msg->header, type, mid,
+ GCC_send_prebuilt_message (&msg->header, type, mid,
c, fwd, force, NULL, NULL));
return NULL;
}
if (NULL == existing_q)
{
- tq = GNUNET_new (struct CadetTunnel3Queue); /* FIXME valgrind: leak*/
+ tq = GNUNET_new (struct CadetTunnelQueue); /* FIXME valgrind: leak*/
}
else
{
tq = existing_q;
tq->tqd = NULL;
}
- tq->cq = GMC_send_prebuilt_message (&msg->header, type, mid, c, fwd, force,
+ tq->cq = GCC_send_prebuilt_message (&msg->header, type, mid, c, fwd, force,
&tun_message_sent, tq);
tq->cont = cont;
tq->cont_cls = cont_cls;
* @param t Tunnel that holds the messages. Cannot be loopback.
*/
static void
-send_queued_data (struct CadetTunnel3 *t)
+send_queued_data (struct CadetTunnel *t)
{
struct CadetTunnelDelayed *tqd;
struct CadetTunnelDelayed *next;
unsigned int room;
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "GMT_send_queued_data on tunnel %s\n",
- GMT_2s (t));
+ "GCT_send_queued_data on tunnel %s\n",
+ GCT_2s (t));
- if (GMT_is_loopback (t))
+ if (GCT_is_loopback (t))
{
GNUNET_break (0);
return;
return;
}
- room = GMT_get_connections_buffer (t);
+ room = GCT_get_connections_buffer (t);
LOG (GNUNET_ERROR_TYPE_DEBUG, " buffer space: %u\n", room);
LOG (GNUNET_ERROR_TYPE_DEBUG, " tq head: %p\n", t->tq_head);
for (tqd = t->tq_head; NULL != tqd && room > 0; tqd = next)
tqd->tq);
unqueue_data (tqd);
}
- LOG (GNUNET_ERROR_TYPE_DEBUG, "GMT_send_queued_data end\n", GMP_2s (t->peer));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "GCT_send_queued_data end\n", GCP_2s (t->peer));
}
* @param message Message to send. Function modifies it.
*/
static void
-send_kx (struct CadetTunnel3 *t,
+send_kx (struct CadetTunnel *t,
const struct GNUNET_MessageHeader *message)
{
struct CadetConnection *c;
uint16_t type;
int fwd;
- LOG (GNUNET_ERROR_TYPE_DEBUG, "GMT KX on Tunnel %s\n", GMT_2s (t));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "GMT KX on Tunnel %s\n", GCT_2s (t));
/* Avoid loopback. */
- if (GMT_is_loopback (t))
+ if (GCT_is_loopback (t))
{
LOG (GNUNET_ERROR_TYPE_DEBUG, " loopback!\n");
GNUNET_break (0);
return;
}
- /* Even if tunnel is troyed, send anyway.
- * Could be a rekey initiated by remote peer to create a new channel!
+ /* Even if tunnel is being destroyed, send anyway.
+ * Could be a response to a rekey initiated by remote peer,
+ * who is trying to create a new channel!
*/
/* Must have a connection. */
if (NULL == t->connection_head)
{
GNUNET_break (CADET_TUNNEL3_SEARCHING == t->cstate);
- GMT_debug (t);
+ GCT_debug (t);
return;
}
{
GNUNET_break (GNUNET_SCHEDULER_NO_TASK != t->destroy_task
|| CADET_TUNNEL3_READY != t->cstate);
- GMT_debug (t);
+ GCT_debug (t);
return;
}
type = ntohs (message->type);
break;
default:
LOG (GNUNET_ERROR_TYPE_DEBUG, "unkown type %s\n",
- GM_m2s (type));
+ GC_m2s (type));
GNUNET_break (0);
}
- fwd = GMC_is_origin (t->connection_head->c, GNUNET_YES);
+ fwd = GCC_is_origin (t->connection_head->c, GNUNET_YES);
/* TODO save handle and cancel in case of a unneeded retransmission */
- GMC_send_prebuilt_message (&msg->header, GNUNET_MESSAGE_TYPE_CADET_KX,
+ GCC_send_prebuilt_message (&msg->header, GNUNET_MESSAGE_TYPE_CADET_KX,
message->type, c, fwd, GNUNET_YES, NULL, NULL);
}
* @param t Tunnel on which to send the key.
*/
static void
-send_ephemeral (struct CadetTunnel3 *t)
+send_ephemeral (struct CadetTunnel *t)
{
- LOG (GNUNET_ERROR_TYPE_INFO, "=> EPHM for %s\n", GMT_2s (t));
+ LOG (GNUNET_ERROR_TYPE_INFO, "===> EPHM for %s\n", GCT_2s (t));
kx_msg.sender_status = htonl (t->estate);
send_kx (t, &kx_msg.header);
* @param t Tunnel on which to send the ping.
*/
static void
-send_ping (struct CadetTunnel3 *t)
+send_ping (struct CadetTunnel *t)
{
struct GNUNET_CADET_KX_Ping msg;
- LOG (GNUNET_ERROR_TYPE_INFO, "=> PING for %s\n", GMT_2s (t));
+ LOG (GNUNET_ERROR_TYPE_INFO, "===> PING for %s\n", GCT_2s (t));
msg.header.size = htons (sizeof (msg));
msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_KX_PING);
msg.iv = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX);
- msg.target = *GMP_get_id (t->peer);
+ msg.target = *GCP_get_id (t->peer);
msg.nonce = t->kx_ctx->challenge;
LOG (GNUNET_ERROR_TYPE_DEBUG, " sending %u\n", msg.nonce);
LOG (GNUNET_ERROR_TYPE_DEBUG, " towards %s\n", GNUNET_i2s (&msg.target));
- t_encrypt (t, &msg.target, &msg.target, ping_encryption_size(), msg.iv);
+ t_encrypt (t, &msg.target, &msg.target,
+ ping_encryption_size(), msg.iv, GNUNET_YES);
LOG (GNUNET_ERROR_TYPE_DEBUG, " e sending %u\n", msg.nonce);
LOG (GNUNET_ERROR_TYPE_DEBUG, " e towards %s\n", GNUNET_i2s (&msg.target));
/**
* Send a pong message on a tunnel.
- *
+ *d_
* @param t Tunnel on which to send the pong.
* @param challenge Value sent in the ping that we have to send back.
*/
static void
-send_pong (struct CadetTunnel3 *t, uint32_t challenge)
+send_pong (struct CadetTunnel *t, uint32_t challenge)
{
struct GNUNET_CADET_KX_Pong msg;
- LOG (GNUNET_ERROR_TYPE_INFO, "=> PONG for %s\n", GMT_2s (t));
+ LOG (GNUNET_ERROR_TYPE_INFO, "===> PONG for %s\n", GCT_2s (t));
msg.header.size = htons (sizeof (msg));
msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_KX_PONG);
msg.iv = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX);
msg.nonce = challenge;
LOG (GNUNET_ERROR_TYPE_DEBUG, " sending %u\n", msg.nonce);
- t_encrypt (t, &msg.nonce, &msg.nonce, sizeof (msg.nonce), msg.iv);
+ t_encrypt (t, &msg.nonce, &msg.nonce,
+ sizeof (msg.nonce), msg.iv, GNUNET_YES);
LOG (GNUNET_ERROR_TYPE_DEBUG, " e sending %u\n", msg.nonce);
send_kx (t, &msg.header);
static void
rekey_tunnel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
{
- struct CadetTunnel3 *t = cls;
+ struct CadetTunnel *t = cls;
t->rekey_task = GNUNET_SCHEDULER_NO_TASK;
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Re-key Tunnel %s\n", GMT_2s (t));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Re-key Tunnel %s\n", GCT_2s (t));
if (NULL != tc && 0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
return;
t->kx_ctx->challenge =
GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX);
t->kx_ctx->d_key_old = t->d_key;
+ t->kx_ctx->e_key_old = t->e_key;
+ create_keys (t);
+ t->kx_ctx->rekey_start_time = GNUNET_TIME_absolute_get ();
LOG (GNUNET_ERROR_TYPE_DEBUG, " new challenge for %s: %u\n",
- GMT_2s (t), t->kx_ctx->challenge);
+ GCT_2s (t), t->kx_ctx->challenge);
}
+
send_ephemeral (t);
+
switch (t->estate)
{
case CADET_TUNNEL3_KEY_UNINITIALIZED:
LOG (GNUNET_ERROR_TYPE_DEBUG, "Unexpected state %u\n", t->estate);
}
+ // FIXME exponential backoff
LOG (GNUNET_ERROR_TYPE_DEBUG, " next call in %s\n",
GNUNET_STRINGS_relative_time_to_string (REKEY_WAIT, GNUNET_YES));
t->rekey_task = GNUNET_SCHEDULER_add_delayed (REKEY_WAIT, &rekey_tunnel, t);
/**
- * Out ephemeral key has changed, create new session key on all tunnels.
+ * Our ephemeral key has changed, create new session key on all tunnels.
+ *
+ * Each tunnel will start the Key Exchange with a random delay between
+ * 0 and number_of_tunnels*100 milliseconds, so there are 10 key exchanges
+ * per second, on average.
*
* @param cls Closure (size of the hashmap).
* @param key Current public key.
const struct GNUNET_PeerIdentity *key,
void *value)
{
- struct CadetTunnel3 *t = value;
+ struct CadetTunnel *t = value;
struct GNUNET_TIME_Relative delay;
long n = (long) cls;
uint32_t r;
if (GNUNET_SCHEDULER_NO_TASK != t->rekey_task)
return GNUNET_YES;
- if (GNUNET_YES == GMT_is_loopback (t))
+ if (GNUNET_YES == GCT_is_loopback (t))
return GNUNET_YES;
r = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, (uint32_t) n * 100);
const struct GNUNET_PeerIdentity *key,
void *value)
{
- struct CadetTunnel3 *t = value;
+ struct CadetTunnel *t = value;
- LOG (GNUNET_ERROR_TYPE_DEBUG, "GMT_shutdown destroying tunnel at %p\n", t);
- GMT_destroy (t);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "GCT_shutdown destroying tunnel at %p\n", t);
+ GCT_destroy (t);
return GNUNET_YES;
}
* @param gid ID of the channel.
*/
static void
-send_channel_destroy (struct CadetTunnel3 *t, unsigned int gid)
+send_channel_destroy (struct CadetTunnel *t, unsigned int gid)
{
struct GNUNET_CADET_ChannelManage msg;
LOG (GNUNET_ERROR_TYPE_DEBUG,
"WARNING destroying unknown channel %u on tunnel %s\n",
- gid, GMT_2s (t));
+ gid, GCT_2s (t));
send_prebuilt_message (&msg.header, t, NULL, GNUNET_YES, NULL, NULL, NULL);
}
* #GNUNET_SYSERR if message on a one-ended channel (remote)
*/
static void
-handle_data (struct CadetTunnel3 *t,
+handle_data (struct CadetTunnel *t,
const struct GNUNET_CADET_Data *msg,
int fwd)
{
return;
}
LOG (GNUNET_ERROR_TYPE_DEBUG, " payload of type %s\n",
- GM_m2s (ntohs (msg[1].header.type)));
+ GC_m2s (ntohs (msg[1].header.type)));
/* Check channel */
- ch = GMT_get_channel (t, ntohl (msg->chid));
+ ch = GCT_get_channel (t, ntohl (msg->chid));
if (NULL == ch)
{
GNUNET_STATISTICS_update (stats, "# data on unknown channel",
return;
}
- GMCH_handle_data (ch, msg, fwd);
+ GCCH_handle_data (ch, msg, fwd);
}
* #GNUNET_SYSERR if message on a one-ended channel (remote)
*/
static void
-handle_data_ack (struct CadetTunnel3 *t,
+handle_data_ack (struct CadetTunnel *t,
const struct GNUNET_CADET_DataACK *msg,
int fwd)
{
}
/* Check channel */
- ch = GMT_get_channel (t, ntohl (msg->chid));
+ ch = GCT_get_channel (t, ntohl (msg->chid));
if (NULL == ch)
{
GNUNET_STATISTICS_update (stats, "# data ack on unknown channel",
return;
}
- GMCH_handle_data_ack (ch, msg, fwd);
+ GCCH_handle_data_ack (ch, msg, fwd);
}
* @param msg Data message.
*/
static void
-handle_ch_create (struct CadetTunnel3 *t,
+handle_ch_create (struct CadetTunnel *t,
const struct GNUNET_CADET_ChannelCreate *msg)
{
struct CadetChannel *ch;
}
/* Check channel */
- ch = GMT_get_channel (t, ntohl (msg->chid));
- if (NULL != ch && ! GMT_is_loopback (t))
+ ch = GCT_get_channel (t, ntohl (msg->chid));
+ if (NULL != ch && ! GCT_is_loopback (t))
{
/* Probably a retransmission, safe to ignore */
LOG (GNUNET_ERROR_TYPE_DEBUG, " already exists...\n");
}
- ch = GMCH_handle_create (t, msg);
+ ch = GCCH_handle_create (t, msg);
if (NULL != ch)
- GMT_add_channel (t, ch);
+ GCT_add_channel (t, ch);
}
* @param msg NACK message.
*/
static void
-handle_ch_nack (struct CadetTunnel3 *t,
+handle_ch_nack (struct CadetTunnel *t,
const struct GNUNET_CADET_ChannelManage *msg)
{
struct CadetChannel *ch;
}
/* Check channel */
- ch = GMT_get_channel (t, ntohl (msg->chid));
+ ch = GCT_get_channel (t, ntohl (msg->chid));
if (NULL == ch)
{
GNUNET_STATISTICS_update (stats, "# channel NACK on unknown channel",
return;
}
- GMCH_handle_nack (ch);
+ GCCH_handle_nack (ch);
}
* #GNUNET_SYSERR if message on a one-ended channel (remote)
*/
static void
-handle_ch_ack (struct CadetTunnel3 *t,
+handle_ch_ack (struct CadetTunnel *t,
const struct GNUNET_CADET_ChannelManage *msg,
int fwd)
{
}
/* Check channel */
- ch = GMT_get_channel (t, ntohl (msg->chid));
+ ch = GCT_get_channel (t, ntohl (msg->chid));
if (NULL == ch)
{
GNUNET_STATISTICS_update (stats, "# channel ack on unknown channel",
return;
}
- GMCH_handle_ack (ch, msg, fwd);
+ GCCH_handle_ack (ch, msg, fwd);
}
-
/**
* Handle a channel destruction message.
*
* #GNUNET_SYSERR if message on a one-ended channel (remote)
*/
static void
-handle_ch_destroy (struct CadetTunnel3 *t,
+handle_ch_destroy (struct CadetTunnel *t,
const struct GNUNET_CADET_ChannelManage *msg,
int fwd)
{
}
/* Check channel */
- ch = GMT_get_channel (t, ntohl (msg->chid));
+ ch = GCT_get_channel (t, ntohl (msg->chid));
if (NULL == ch)
{
/* Probably a retransmission, safe to ignore */
return;
}
- GMCH_handle_destroy (ch, msg, fwd);
+ GCCH_handle_destroy (ch, msg, fwd);
}
* @param msg Key eXchange message.
*/
static void
-handle_ephemeral (struct CadetTunnel3 *t,
+handle_ephemeral (struct CadetTunnel *t,
const struct GNUNET_CADET_KX_Ephemeral *msg)
{
- struct GNUNET_HashCode km;
- LOG (GNUNET_ERROR_TYPE_INFO, "<=== EPHM for %s\n", GMT_2s (t));
+ LOG (GNUNET_ERROR_TYPE_INFO, "<=== EPHM for %s\n", GCT_2s (t));
if (GNUNET_OK != check_ephemeral (t, msg))
{
GNUNET_break_op (0);
return;
}
- derive_key_material (&km, &msg->ephemeral_key);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " km is %s\n", GNUNET_h2s (&km));
- derive_symmertic (&t->e_key, &my_full_id, GMP_get_id (t->peer), &km);
- derive_symmertic (&t->d_key, GMP_get_id (t->peer), &my_full_id, &km);
+ t->peers_ephemeral_key = msg->ephemeral_key;
+ create_keys (t);
if (CADET_TUNNEL3_KEY_SENT == t->estate)
{
- LOG (GNUNET_ERROR_TYPE_DEBUG, " our key was sent, send ping\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " our key was sent, sending ping\n");
send_ping (t);
t->estate = CADET_TUNNEL3_KEY_PING;
}
* @param msg Key eXchange Ping message.
*/
static void
-handle_ping (struct CadetTunnel3 *t,
+handle_ping (struct CadetTunnel *t,
const struct GNUNET_CADET_KX_Ping *msg)
{
struct GNUNET_CADET_KX_Ping res;
return;
}
- LOG (GNUNET_ERROR_TYPE_INFO, "<=== PING for %s\n", GMT_2s (t));
+ LOG (GNUNET_ERROR_TYPE_INFO, "<=== PING for %s\n", GCT_2s (t));
t_decrypt (t, &res.target, &msg->target, ping_encryption_size (), msg->iv);
if (0 != memcmp (&my_full_id, &res.target, sizeof (my_full_id)))
{
- // FIXME: move to debug
GNUNET_STATISTICS_update (stats, "# malformed PINGs", 1, GNUNET_NO);
- LOG (GNUNET_ERROR_TYPE_WARNING, " malformed PING on %s\n", GMT_2s (t));
- LOG (GNUNET_ERROR_TYPE_WARNING, " e got %u\n", msg->nonce);
- LOG (GNUNET_ERROR_TYPE_WARNING, " e towards %s\n", GNUNET_i2s (&msg->target));
- LOG (GNUNET_ERROR_TYPE_WARNING, " got %u\n", res.nonce);
- LOG (GNUNET_ERROR_TYPE_WARNING, " towards %s\n", GNUNET_i2s (&res.target));
+ LOG (GNUNET_ERROR_TYPE_WARNING, " malformed PING on %s\n", GCT_2s (t));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " e got %u\n", msg->nonce);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " e towards %s\n", GNUNET_i2s (&msg->target));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " got %u\n", res.nonce);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " towards %s\n", GNUNET_i2s (&res.target));
send_ephemeral (t);
send_ping (t);
return;
send_pong (t, res.nonce);
}
+/**
+ * @brief Finish the Key eXchange and destory the old keys.
+ *
+ * @param cls Closure (Tunnel for which to finish the KX).
+ * @param tc Task context.
+ */
+static void
+finish_kx (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct CadetTunnel *t = cls;
+
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ return;
+
+ GNUNET_free (t->kx_ctx);
+ t->kx_ctx = NULL;
+}
/**
* @param msg Key eXchange Pong message.
*/
static void
-handle_pong (struct CadetTunnel3 *t,
+handle_pong (struct CadetTunnel *t,
const struct GNUNET_CADET_KX_Pong *msg)
{
uint32_t challenge;
- LOG (GNUNET_ERROR_TYPE_INFO, "<=== PONG for %s\n", GMT_2s (t));
+ LOG (GNUNET_ERROR_TYPE_INFO, "<=== PONG for %s\n", GCT_2s (t));
if (GNUNET_SCHEDULER_NO_TASK == t->rekey_task)
{
GNUNET_STATISTICS_update (stats, "# duplicate PONG messages", 1, GNUNET_NO);
if (challenge != t->kx_ctx->challenge)
{
- LOG (GNUNET_ERROR_TYPE_WARNING, "Wrong PONG challenge on %s\n", GMT_2s (t));
- LOG (GNUNET_ERROR_TYPE_WARNING, "PONG: %u (e: %u). Expected: %u.\n",
+ LOG (GNUNET_ERROR_TYPE_WARNING, "Wrong PONG challenge on %s\n", GCT_2s (t));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "PONG: %u (e: %u). Expected: %u.\n",
challenge, msg->nonce, t->kx_ctx->challenge);
send_ephemeral (t);
send_ping (t);
}
GNUNET_SCHEDULER_cancel (t->rekey_task);
t->rekey_task = GNUNET_SCHEDULER_NO_TASK;
- GNUNET_free (t->kx_ctx);
- t->kx_ctx = NULL;
- GMT_change_estate (t, CADET_TUNNEL3_KEY_OK);
+
+ /* Don't free the old keys right away, but after a delay.
+ * Rationale: the KX could have happened over a very fast connection,
+ * with payload traffic still signed with the old key stuck in a slower
+ * connection.
+ */
+ if (GNUNET_SCHEDULER_NO_TASK == t->kx_ctx->finish_task)
+ {
+ t->kx_ctx->finish_task =
+ GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_UNIT_MINUTES, finish_kx, t);
+ }
+ GCT_change_estate (t, CADET_TUNNEL3_KEY_OK);
}
* #GNUNET_SYSERR if message on a one-ended channel (remote)
*/
static void
-handle_decrypted (struct CadetTunnel3 *t,
+handle_decrypted (struct CadetTunnel *t,
const struct GNUNET_MessageHeader *msgh,
int fwd)
{
uint16_t type;
type = ntohs (msgh->type);
- LOG (GNUNET_ERROR_TYPE_INFO, "<=== %s on %s\n", GM_m2s (type), GMT_2s (t));
+ LOG (GNUNET_ERROR_TYPE_INFO, "<=== %s on %s\n", GC_m2s (type), GCT_2s (t));
switch (type)
{
LOG (GNUNET_ERROR_TYPE_WARNING,
"end-to-end message not known (%u)\n",
ntohs (msgh->type));
- GMT_debug (t);
+ GCT_debug (t);
}
}
* @param msg Encrypted message.
*/
void
-GMT_handle_encrypted (struct CadetTunnel3 *t,
+GCT_handle_encrypted (struct CadetTunnel *t,
const struct GNUNET_CADET_Encrypted *msg)
{
size_t size = ntohs (msg->header.size);
size_t payload_size = size - sizeof (struct GNUNET_CADET_Encrypted);
- size_t decrypted_size;
+ int decrypted_size;
char cbuf [payload_size];
struct GNUNET_MessageHeader *msgh;
unsigned int off;
- struct GNUNET_CADET_Hash hmac;
- decrypted_size = t_decrypt (t, cbuf, &msg[1], payload_size, msg->iv);
- t_hmac (t, &msg[1], payload_size, msg->iv, GNUNET_NO, &hmac);
- if (0 != memcmp (&hmac, &msg->hmac, sizeof (hmac)))
- {
- /* checksum failed */
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed checksum validation for a message on tunnel `%s'\n",
- GMT_2s (t));
- GNUNET_STATISTICS_update (stats, "# wrong HMAC", 1, GNUNET_NO);
- return;
- }
+ decrypted_size = t_decrypt_and_validate (t, cbuf, &msg[1], payload_size,
+ msg->iv, &msg->hmac);
+
off = 0;
while (off < decrypted_size)
{
* @param message Payload of KX message.
*/
void
-GMT_handle_kx (struct CadetTunnel3 *t,
+GCT_handle_kx (struct CadetTunnel *t,
const struct GNUNET_MessageHeader *message)
{
uint16_t type;
* @param key ECC private key, to derive all other keys and do crypto.
*/
void
-GMT_init (const struct GNUNET_CONFIGURATION_Handle *c,
+GCT_init (const struct GNUNET_CONFIGURATION_Handle *c,
const struct GNUNET_CRYPTO_EddsaPrivateKey *key)
{
LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n");
* Shut down the tunnel subsystem.
*/
void
-GMT_shutdown (void)
+GCT_shutdown (void)
{
if (GNUNET_SCHEDULER_NO_TASK != rekey_task)
{
*
* @param destination Peer this tunnel is towards.
*/
-struct CadetTunnel3 *
-GMT_new (struct CadetPeer *destination)
+struct CadetTunnel *
+GCT_new (struct CadetPeer *destination)
{
- struct CadetTunnel3 *t;
+ struct CadetTunnel *t;
- t = GNUNET_new (struct CadetTunnel3);
+ t = GNUNET_new (struct CadetTunnel);
t->next_chid = 0;
t->peer = destination;
if (GNUNET_OK !=
- GNUNET_CONTAINER_multipeermap_put (tunnels, GMP_get_id (destination), t,
+ GNUNET_CONTAINER_multipeermap_put (tunnels, GCP_get_id (destination), t,
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
{
GNUNET_break (0);
* @param cstate New connection state.
*/
void
-GMT_change_cstate (struct CadetTunnel3* t, enum CadetTunnel3CState cstate)
+GCT_change_cstate (struct CadetTunnel* t, enum CadetTunnelCState cstate)
{
if (NULL == t)
return;
LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel %s cstate %s => %s\n",
- GMP_2s (t->peer), cstate2s (t->cstate), cstate2s (cstate));
- if (myid != GMP_get_short_id (t->peer) &&
+ GCP_2s (t->peer), cstate2s (t->cstate), cstate2s (cstate));
+ if (myid != GCP_get_short_id (t->peer) &&
CADET_TUNNEL3_READY != t->cstate &&
CADET_TUNNEL3_READY == cstate)
{
t->cstate = cstate;
if (CADET_TUNNEL3_READY == cstate
- && CONNECTIONS_PER_TUNNEL <= GMT_count_connections (t))
+ && CONNECTIONS_PER_TUNNEL <= GCT_count_connections (t))
{
LOG (GNUNET_ERROR_TYPE_DEBUG, " cstate triggered stop dht\n");
- GMP_stop_search (t->peer);
+ GCP_stop_search (t->peer);
}
}
* @param state New encryption state.
*/
void
-GMT_change_estate (struct CadetTunnel3* t, enum CadetTunnel3EState state)
+GCT_change_estate (struct CadetTunnel* t, enum CadetTunnelEState state)
{
if (NULL == t)
return;
LOG (GNUNET_ERROR_TYPE_DEBUG,
"Tunnel %s estate was %s\n",
- GMP_2s (t->peer), estate2s (t->estate));
+ GCP_2s (t->peer), estate2s (t->estate));
LOG (GNUNET_ERROR_TYPE_DEBUG,
"Tunnel %s estate is now %s\n",
- GMP_2s (t->peer), estate2s (state));
- if (myid != GMP_get_short_id (t->peer) &&
+ GCP_2s (t->peer), estate2s (state));
+ if (myid != GCP_get_short_id (t->peer) &&
CADET_TUNNEL3_KEY_OK != t->estate && CADET_TUNNEL3_KEY_OK == state)
{
t->estate = state;
static void
trim_connections (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
{
- struct CadetTunnel3 *t = cls;
+ struct CadetTunnel *t = cls;
if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
return;
- if (GMT_count_connections (t) > 2 * CONNECTIONS_PER_TUNNEL)
+ if (GCT_count_connections (t) > 2 * CONNECTIONS_PER_TUNNEL)
{
struct CadetTConnection *iter;
struct CadetTConnection *c;
for (c = iter = t->connection_head; NULL != iter; iter = iter->next)
{
if ((NULL == c || iter->created.abs_value_us > c->created.abs_value_us)
- && GNUNET_NO == GMC_is_direct (iter->c))
+ && GNUNET_NO == GCC_is_direct (iter->c))
{
c = iter;
}
if (NULL != c)
{
LOG (GNUNET_ERROR_TYPE_DEBUG, "Too many connections on tunnel %s\n",
- GMT_2s (t));
+ GCT_2s (t));
LOG (GNUNET_ERROR_TYPE_DEBUG, "Destroying connection %s\n",
- GMC_2s (c->c));
- GMC_destroy (c->c);
+ GCC_2s (c->c));
+ GCC_destroy (c->c);
}
else
{
* @param c Connection.
*/
void
-GMT_add_connection (struct CadetTunnel3 *t, struct CadetConnection *c)
+GCT_add_connection (struct CadetTunnel *t, struct CadetConnection *c)
{
struct CadetTConnection *aux;
GNUNET_assert (NULL != c);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "add connection %s\n", GMC_2s (c));
- LOG (GNUNET_ERROR_TYPE_DEBUG, " to tunnel %s\n", GMT_2s (t));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "add connection %s\n", GCC_2s (c));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " to tunnel %s\n", GCT_2s (t));
for (aux = t->connection_head; aux != NULL; aux = aux->next)
if (aux->c == c)
return;
* @param path Invalid path to remove. Is destroyed after removal.
*/
void
-GMT_remove_path (struct CadetTunnel3 *t, struct CadetPeerPath *path)
+GCT_remove_path (struct CadetTunnel *t, struct CadetPeerPath *path)
{
- GMP_remove_path (t->peer, path);
+ GCP_remove_path (t->peer, path);
}
* @param c Connection.
*/
void
-GMT_remove_connection (struct CadetTunnel3 *t,
+GCT_remove_connection (struct CadetTunnel *t,
struct CadetConnection *c)
{
struct CadetTConnection *aux;
struct CadetTConnection *next;
LOG (GNUNET_ERROR_TYPE_DEBUG, "Removing connection %s from tunnel %s\n",
- GMC_2s (c), GMT_2s (t));
+ GCC_2s (c), GCT_2s (t));
for (aux = t->connection_head; aux != NULL; aux = next)
{
next = aux->next;
}
/* Start new connections if needed */
- if (CONNECTIONS_PER_TUNNEL < GMT_count_connections (t)
+ if (CONNECTIONS_PER_TUNNEL < GCT_count_connections (t)
&& GNUNET_SCHEDULER_NO_TASK == t->destroy_task
&& CADET_TUNNEL3_SHUTDOWN != t->cstate
&& GNUNET_NO == shutting_down)
{
LOG (GNUNET_ERROR_TYPE_DEBUG, " no more connections, getting new ones\n");
t->cstate = CADET_TUNNEL3_SEARCHING;
- GMP_connect (t->peer);
+ GCP_connect (t->peer);
return;
}
/* Check if any connection is ready to maintaing cstate */
for (aux = t->connection_head; aux != NULL; aux = aux->next)
- if (CADET_CONNECTION_READY == GMC_get_state (aux->c))
+ if (CADET_CONNECTION_READY == GCC_get_state (aux->c))
return;
t->cstate = CADET_TUNNEL3_WAITING;
* @param ch Channel.
*/
void
-GMT_add_channel (struct CadetTunnel3 *t, struct CadetChannel *ch)
+GCT_add_channel (struct CadetTunnel *t, struct CadetChannel *ch)
{
struct CadetTChannel *aux;
* @param ch Channel.
*/
void
-GMT_remove_channel (struct CadetTunnel3 *t, struct CadetChannel *ch)
+GCT_remove_channel (struct CadetTunnel *t, struct CadetChannel *ch)
{
struct CadetTChannel *aux;
{
if (aux->ch == ch)
{
- LOG (GNUNET_ERROR_TYPE_DEBUG, " found! %s\n", GMCH_2s (ch));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " found! %s\n", GCCH_2s (ch));
GNUNET_CONTAINER_DLL_remove (t->channel_head, t->channel_tail, aux);
GNUNET_free (aux);
return;
* @return channel handler, NULL if doesn't exist
*/
struct CadetChannel *
-GMT_get_channel (struct CadetTunnel3 *t, CADET_ChannelNumber chid)
+GCT_get_channel (struct CadetTunnel *t, CADET_ChannelNumber chid)
{
struct CadetTChannel *iter;
for (iter = t->channel_head; NULL != iter; iter = iter->next)
{
- if (GMCH_get_id (iter->ch) == chid)
+ if (GCCH_get_id (iter->ch) == chid)
break;
}
static void
delayed_destroy (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
{
- struct CadetTunnel3 *t = cls;
+ struct CadetTunnel *t = cls;
struct CadetTConnection *iter;
LOG (GNUNET_ERROR_TYPE_DEBUG, "delayed destroying tunnel %p\n", t);
{
LOG (GNUNET_ERROR_TYPE_WARNING,
"Not destroying tunnel, due to shutdown. "
- "Tunnel at %p should have been freed by GMT_shutdown\n", t);
+ "Tunnel at %p should have been freed by GCT_shutdown\n", t);
return;
}
t->destroy_task = GNUNET_SCHEDULER_NO_TASK;
for (iter = t->connection_head; NULL != iter; iter = iter->next)
{
- GMC_send_destroy (iter->c);
+ GCC_send_destroy (iter->c);
}
- GMT_destroy (t);
+ GCT_destroy (t);
}
* @param t Tunnel to destroy.
*/
void
-GMT_destroy_empty (struct CadetTunnel3 *t)
+GCT_destroy_empty (struct CadetTunnel *t)
{
if (GNUNET_YES == shutting_down)
return; /* Will be destroyed immediately anyway */
{
LOG (GNUNET_ERROR_TYPE_DEBUG,
"Tunnel %s is already scheduled for destruction\n",
- GMT_2s (t));
+ GCT_2s (t));
GNUNET_break (0);
/* should never happen, tunnel can only become empty once, and the
* task identifier should be NO_TASK (cleaned when the tunnel was created
}
LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel %s empty: destroying scheduled\n",
- GMT_2s (t));
+ GCT_2s (t));
t->destroy_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
&delayed_destroy, t);
* @param t Tunnel to destroy if empty.
*/
void
-GMT_destroy_if_empty (struct CadetTunnel3 *t)
+GCT_destroy_if_empty (struct CadetTunnel *t)
{
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel %s destroy if empty\n", GMT_2s (t));
- if (1 < GMT_count_channels (t))
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel %s destroy if empty\n", GCT_2s (t));
+ if (1 < GCT_count_channels (t))
return;
- GMT_destroy_empty (t);
+ GCT_destroy_empty (t);
}
* @param t The tunnel to destroy.
*/
void
-GMT_destroy (struct CadetTunnel3 *t)
+GCT_destroy (struct CadetTunnel *t)
{
struct CadetTConnection *iter_c;
struct CadetTConnection *next_c;
if (NULL == t)
return;
- LOG (GNUNET_ERROR_TYPE_DEBUG, "destroying tunnel %s\n", GMP_2s (t->peer));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "destroying tunnel %s\n", GCP_2s (t->peer));
GNUNET_break (GNUNET_YES ==
GNUNET_CONTAINER_multipeermap_remove (tunnels,
- GMP_get_id (t->peer), t));
+ GCP_get_id (t->peer), t));
for (iter_c = t->connection_head; NULL != iter_c; iter_c = next_c)
{
next_c = iter_c->next;
- GMC_destroy (iter_c->c);
+ GCC_destroy (iter_c->c);
}
for (iter_ch = t->channel_head; NULL != iter_ch; iter_ch = next_ch)
{
next_ch = iter_ch->next;
- GMCH_destroy (iter_ch->ch);
+ GCCH_destroy (iter_ch->ch);
/* Should only happen on shutdown, but it's ok. */
}
}
GNUNET_STATISTICS_update (stats, "# tunnels", -1, GNUNET_NO);
- GMP_set_tunnel (t->peer, NULL);
+ GCP_set_tunnel (t->peer, NULL);
if (GNUNET_SCHEDULER_NO_TASK != t->rekey_task)
{
GNUNET_SCHEDULER_cancel (t->rekey_task);
t->rekey_task = GNUNET_SCHEDULER_NO_TASK;
- if (NULL != t->kx_ctx)
- GNUNET_free (t->kx_ctx);
- else
- GNUNET_break (0);
}
-
+ if (NULL != t->kx_ctx)
+ {
+ if (GNUNET_SCHEDULER_NO_TASK != t->kx_ctx->finish_task)
+ GNUNET_SCHEDULER_cancel (t->kx_ctx->finish_task);
+ GNUNET_free (t->kx_ctx);
+ }
GNUNET_free (t);
}
* @return Connection created.
*/
struct CadetConnection *
-GMT_use_path (struct CadetTunnel3 *t, struct CadetPeerPath *p)
+GCT_use_path (struct CadetTunnel *t, struct CadetPeerPath *p)
{
struct CadetConnection *c;
struct GNUNET_CADET_Hash cid;
}
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, &cid, sizeof (cid));
- c = GMC_new (&cid, t, p, own_pos);
+ c = GCC_new (&cid, t, p, own_pos);
if (NULL == c)
{
/* Path was flawed */
return NULL;
}
- GMT_add_connection (t, c);
+ GCT_add_connection (t, c);
return c;
}
* @return Number of connections.
*/
unsigned int
-GMT_count_connections (struct CadetTunnel3 *t)
+GCT_count_connections (struct CadetTunnel *t)
{
struct CadetTConnection *iter;
unsigned int count;
return 0;
for (count = 0, iter = t->connection_head; NULL != iter; iter = iter->next)
- if (CADET_CONNECTION_DESTROYED != GMC_get_state (iter->c))
+ if (CADET_CONNECTION_DESTROYED != GCC_get_state (iter->c))
count++;
return count;
* @return Number of channels.
*/
unsigned int
-GMT_count_channels (struct CadetTunnel3 *t)
+GCT_count_channels (struct CadetTunnel *t)
{
struct CadetTChannel *iter;
unsigned int count;
*
* @return Tunnel's connectivity state.
*/
-enum CadetTunnel3CState
-GMT_get_cstate (struct CadetTunnel3 *t)
+enum CadetTunnelCState
+GCT_get_cstate (struct CadetTunnel *t)
{
if (NULL == t)
{
GNUNET_assert (0);
- return (enum CadetTunnel3CState) -1;
+ return (enum CadetTunnelCState) -1;
}
return t->cstate;
}
*
* @return Tunnel's encryption state.
*/
-enum CadetTunnel3EState
-GMT_get_estate (struct CadetTunnel3 *t)
+enum CadetTunnelEState
+GCT_get_estate (struct CadetTunnel *t)
{
if (NULL == t)
{
GNUNET_assert (0);
- return (enum CadetTunnel3EState) -1;
+ return (enum CadetTunnelEState) -1;
}
return t->estate;
}
* @return Biggest buffer space offered by any channel in the tunnel.
*/
unsigned int
-GMT_get_channels_buffer (struct CadetTunnel3 *t)
+GCT_get_channels_buffer (struct CadetTunnel *t)
{
struct CadetTChannel *iter;
unsigned int buffer;
* @return Buffer space offered by all connections in the tunnel.
*/
unsigned int
-GMT_get_connections_buffer (struct CadetTunnel3 *t)
+GCT_get_connections_buffer (struct CadetTunnel *t)
{
struct CadetTConnection *iter;
unsigned int buffer;
buffer = 0;
for (iter = t->connection_head; NULL != iter; iter = iter->next)
{
- if (GMC_get_state (iter->c) != CADET_CONNECTION_READY)
+ if (GCC_get_state (iter->c) != CADET_CONNECTION_READY)
{
continue;
}
* @return ID of the destination peer.
*/
const struct GNUNET_PeerIdentity *
-GMT_get_destination (struct CadetTunnel3 *t)
+GCT_get_destination (struct CadetTunnel *t)
{
- return GMP_get_id (t->peer);
+ return GCP_get_id (t->peer);
}
* @return GID of a channel free to use.
*/
CADET_ChannelNumber
-GMT_get_next_chid (struct CadetTunnel3 *t)
+GCT_get_next_chid (struct CadetTunnel *t)
{
CADET_ChannelNumber chid;
CADET_ChannelNumber mask;
* If our ID is bigger or loopback tunnel, start at 0, bit 30 = 0
* If peer's ID is bigger, start at 0x4... bit 30 = 1
*/
- result = GNUNET_CRYPTO_cmp_peer_identity (&my_full_id, GMP_get_id (t->peer));
+ result = GNUNET_CRYPTO_cmp_peer_identity (&my_full_id, GCP_get_id (t->peer));
if (0 > result)
mask = 0x40000000;
else
mask = 0x0;
t->next_chid |= mask;
- while (NULL != GMT_get_channel (t, t->next_chid))
+ while (NULL != GCT_get_channel (t, t->next_chid))
{
LOG (GNUNET_ERROR_TYPE_DEBUG, "Channel %u exists...\n", t->next_chid);
t->next_chid = (t->next_chid + 1) & ~GNUNET_CADET_LOCAL_CHANNEL_ID_CLI;
* @param t Channel which has some free buffer space.
*/
void
-GMT_unchoke_channels (struct CadetTunnel3 *t)
+GCT_unchoke_channels (struct CadetTunnel *t)
{
struct CadetTChannel *iter;
unsigned int buffer;
- unsigned int channels = GMT_count_channels (t);
+ unsigned int channels = GCT_count_channels (t);
unsigned int choked_n;
struct CadetChannel *choked[channels];
- LOG (GNUNET_ERROR_TYPE_DEBUG, "GMT_unchoke_channels on %s\n", GMT_2s (t));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "GCT_unchoke_channels on %s\n", GCT_2s (t));
LOG (GNUNET_ERROR_TYPE_DEBUG, " head: %p\n", t->channel_head);
if (NULL != t->channel_head)
LOG (GNUNET_ERROR_TYPE_DEBUG, " head ch: %p\n", t->channel_head->ch);
/* Get buffer space */
- buffer = GMT_get_connections_buffer (t);
+ buffer = GCT_get_connections_buffer (t);
if (0 == buffer)
{
return;
{
unsigned int r = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
choked_n);
- GMCH_allow_client (choked[r], GMCH_is_origin (choked[r], GNUNET_YES));
+ GCCH_allow_client (choked[r], GCCH_is_origin (choked[r], GNUNET_YES));
choked_n--;
buffer--;
choked[r] = choked[choked_n];
* @param t Tunnel.
*/
void
-GMT_send_connection_acks (struct CadetTunnel3 *t)
+GCT_send_connection_acks (struct CadetTunnel *t)
{
struct CadetTConnection *iter;
uint32_t allowed;
unsigned int buffer;
LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel send connection ACKs on %s\n",
- GMT_2s (t));
+ GCT_2s (t));
if (NULL == t)
{
return;
}
- buffer = GMT_get_channels_buffer (t);
+ buffer = GCT_get_channels_buffer (t);
LOG (GNUNET_ERROR_TYPE_DEBUG, " buffer %u\n", buffer);
/* Count connections, how many messages are already allowed */
- cs = GMT_count_connections (t);
+ cs = GCT_count_connections (t);
for (allowed = 0, iter = t->connection_head; NULL != iter; iter = iter->next)
{
allowed += get_connection_allowed (iter);
{
continue;
}
- GMC_allow (iter->c, allow_per_connection,
- GMC_is_origin (iter->c, GNUNET_NO));
+ GCC_allow (iter->c, allow_per_connection,
+ GCC_is_origin (iter->c, GNUNET_NO));
}
GNUNET_break (to_allow == 0);
* @param q Handle to the queue.
*/
void
-GMT_cancel (struct CadetTunnel3Queue *q)
+GCT_cancel (struct CadetTunnelQueue *q)
{
if (NULL != q->cq)
{
- GMC_cancel (q->cq);
+ GCC_cancel (q->cq);
/* tun_message_sent() will be called and free q */
}
else if (NULL != q->tqd)
*
* @return Handle to cancel message. NULL if @c cont is NULL.
*/
-struct CadetTunnel3Queue *
-GMT_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
- struct CadetTunnel3 *t, struct CadetConnection *c,
- int force, GMT_sent cont, void *cont_cls)
+struct CadetTunnelQueue *
+GCT_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
+ struct CadetTunnel *t, struct CadetConnection *c,
+ int force, GCT_sent cont, void *cont_cls)
{
return send_prebuilt_message (message, t, c, force, cont, cont_cls, NULL);
}
* @return #GNUNET_YES if it is loopback.
*/
int
-GMT_is_loopback (const struct CadetTunnel3 *t)
+GCT_is_loopback (const struct CadetTunnel *t)
{
- return (myid == GMP_get_short_id (t->peer));
+ return (myid == GCP_get_short_id (t->peer));
}
* @return #GNUNET_YES a connection uses this path.
*/
int
-GMT_is_path_used (const struct CadetTunnel3 *t, const struct CadetPeerPath *p)
+GCT_is_path_used (const struct CadetTunnel *t, const struct CadetPeerPath *p)
{
struct CadetTConnection *iter;
for (iter = t->connection_head; NULL != iter; iter = iter->next)
- if (GMC_get_path (iter->c) == p)
+ if (GCC_get_path (iter->c) == p)
return GNUNET_YES;
return GNUNET_NO;
* @return Cost of the path (path length + number of overlapping nodes)
*/
unsigned int
-GMT_get_path_cost (const struct CadetTunnel3 *t,
+GCT_get_path_cost (const struct CadetTunnel *t,
const struct CadetPeerPath *path)
{
struct CadetTConnection *iter;
{
for (iter = t->connection_head; NULL != iter; iter = iter->next)
{
- aux = GMC_get_path (iter->c);
+ aux = GCC_get_path (iter->c);
if (NULL == aux)
continue;
* @return Static string the destination peer's ID.
*/
const char *
-GMT_2s (const struct CadetTunnel3 *t)
+GCT_2s (const struct CadetTunnel *t)
{
if (NULL == t)
return "(NULL)";
- return GMP_2s (t->peer);
+ return GCP_2s (t->peer);
}
* @param t Tunnel to debug.
*/
void
-GMT_debug (const struct CadetTunnel3 *t)
+GCT_debug (const struct CadetTunnel *t)
{
struct CadetTChannel *iterch;
struct CadetTConnection *iterc;
- LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT DEBUG TUNNEL TOWARDS %s\n", GMT_2s (t));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT DEBUG TUNNEL TOWARDS %s\n", GCT_2s (t));
LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT cstate %s, estate %s\n",
cstate2s (t->cstate), estate2s (t->estate));
LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT kx_ctx %p, rekey_task %u\n",
LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT channels:\n");
for (iterch = t->channel_head; NULL != iterch; iterch = iterch->next)
{
- LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT - %s\n", GMCH_2s (iterch->ch));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT - %s\n", GCCH_2s (iterch->ch));
}
LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT connections:\n");
for (iterc = t->connection_head; NULL != iterc; iterc = iterc->next)
{
LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT - %s [%u] buf: %u/%u (qn %u/%u)\n",
- GMC_2s (iterc->c), GMC_get_state (iterc->c),
- GMC_get_buffer (iterc->c, GNUNET_YES),
- GMC_get_buffer (iterc->c, GNUNET_NO),
- GMC_get_qn (iterc->c, GNUNET_YES),
- GMC_get_qn (iterc->c, GNUNET_NO));
+ GCC_2s (iterc->c), GCC_get_state (iterc->c),
+ GCC_get_buffer (iterc->c, GNUNET_YES),
+ GCC_get_buffer (iterc->c, GNUNET_NO),
+ GCC_get_qn (iterc->c, GNUNET_YES),
+ GCC_get_qn (iterc->c, GNUNET_NO));
}
LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT DEBUG TUNNEL END\n");
* @param cls Closure for @c iter.
*/
void
-GMT_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter, void *cls)
+GCT_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter, void *cls)
{
GNUNET_CONTAINER_multipeermap_iterate (tunnels, iter, cls);
}
* @return Number of tunnels to remote peers kept by this peer.
*/
unsigned int
-GMT_count_all (void)
+GCT_count_all (void)
{
return GNUNET_CONTAINER_multipeermap_size (tunnels);
}
* @param cls Closure for @c iter.
*/
void
-GMT_iterate_connections (struct CadetTunnel3 *t, GMT_conn_iter iter, void *cls)
+GCT_iterate_connections (struct CadetTunnel *t, GCT_conn_iter iter, void *cls)
{
struct CadetTConnection *ct;
* @param cls Closure for @c iter.
*/
void
-GMT_iterate_channels (struct CadetTunnel3 *t, GMT_chan_iter iter, void *cls)
+GCT_iterate_channels (struct CadetTunnel *t, GCT_chan_iter iter, void *cls)
{
struct CadetTChannel *cht;