#define LOG(level, ...) GNUNET_log_from(level,"mesh-tun",__VA_ARGS__)
-#define REKEY_WAIT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30)
+#define REKEY_WAIT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5)
/******************************************************************************/
/******************************** STRUCTS **********************************/
/**
* Queued messages, to transmit once tunnel gets connected.
*/
- struct MeshTunnelQueue *tq_head;
- struct MeshTunnelQueue *tq_tail;
+ struct MeshTunnelDelayed *tq_head;
+ struct MeshTunnelDelayed *tq_tail;
};
/**
- * Struct used to queue messages in a tunnel.
+ * Struct used to save messages in a non-ready tunnel to send once connected.
*/
-struct MeshTunnelQueue
+struct MeshTunnelDelayed
{
/**
* DLL
*/
- struct MeshTunnelQueue *next;
- struct MeshTunnelQueue *prev;
+ struct MeshTunnelDelayed *next;
+ struct MeshTunnelDelayed *prev;
/**
* Channel.
};
+/**
+ * Handle for messages queued but not yet sent.
+ */
+struct MeshTunnel3Queue
+{
+ /**
+ * Connection queue handle, to cancel if necessary.
+ */
+ struct MeshConnectionQueue *q;
+
+ /**
+ * Continuation to call once sent.
+ */
+ GMT_sent cont;
+
+ /**
+ * Closure for @c cont.
+ */
+ void *cont_cls;
+};
+
+
/******************************************************************************/
/******************************* GLOBALS ***********************************/
/******************************************************************************/
return "MESH_TUNNEL3_WAITING";
case MESH_TUNNEL3_KEY_SENT:
return "MESH_TUNNEL3_KEY_SENT";
- case MESH_TUNNEL3_PING_SENT:
- return "MESH_TUNNEL3_PING_SENT";
case MESH_TUNNEL3_READY:
return "MESH_TUNNEL3_READY";
case MESH_TUNNEL3_RECONNECTING:
* @return GNUNET_OK if message is fine, GNUNET_SYSERR otherwise.
*/
int
-check_ephemeral (struct MeshTunnel3 *t,
+check_ephemeral (struct MeshTunnel3 *t,
const struct GNUNET_MESH_KX_Ephemeral *msg)
{
/* Check message size */
static void
send_queued_data (struct MeshTunnel3 *t)
{
- struct MeshTunnelQueue *tq;
- struct MeshTunnelQueue *next;
+ struct MeshTunnelDelayed *tq;
+ struct MeshTunnelDelayed *next;
unsigned int room;
LOG (GNUNET_ERROR_TYPE_DEBUG,
room--;
GNUNET_CONTAINER_DLL_remove (t->tq_head, t->tq_tail, tq);
GMCH_send_prebuilt_message ((struct GNUNET_MessageHeader *) &tq[1],
- tq->ch, GMCH_is_origin (tq->ch, GNUNET_YES));
+ tq->ch, GMCH_is_origin (tq->ch, GNUNET_YES),
+ GNUNET_NO);
GNUNET_free (tq);
}
struct MeshChannel *ch,
const struct GNUNET_MessageHeader *msg)
{
- struct MeshTunnelQueue *tq;
+ struct MeshTunnelDelayed *tq;
uint16_t size = ntohs (msg->size);
if (MESH_TUNNEL3_READY == t->state)
return;
}
- tq = GNUNET_malloc (sizeof (struct MeshTunnelQueue) + size);
+ tq = GNUNET_malloc (sizeof (struct MeshTunnelDelayed) + size);
tq->ch = ch;
memcpy (&tq[1], msg, size);
t->rekey_task = GNUNET_SCHEDULER_NO_TASK;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Re-key Tunnel\n");
if (NULL != tc && 0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
return;
- t->kx_ctx = GNUNET_new (struct MeshTunnelKXCtx);
- t->kx_ctx->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
- UINT32_MAX);
- t->kx_ctx->d_key_old = t->d_key;
+ if (NULL == t->kx_ctx)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " new kx ctx\n");
+ t->kx_ctx = GNUNET_new (struct MeshTunnelKXCtx);
+ t->kx_ctx->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
+ UINT32_MAX);
+ t->kx_ctx->d_key_old = t->d_key;
+ }
send_ephemeral (t);
if (MESH_TUNNEL3_READY == t->state || MESH_TUNNEL3_REKEY == t->state)
{
LOG (GNUNET_ERROR_TYPE_DEBUG, "Unexpected state %u\n", t->state);
}
+ 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);
}
}
+/**
+ * Called only on shutdown, destroy every tunnel.
+ *
+ * @param cls Closure (unused).
+ * @param key Current public key.
+ * @param value Value in the hash map (tunnel).
+ *
+ * @return #GNUNET_YES, so we should continue to iterate,
+ */
+static int
+destroy_iterator (void *cls,
+ const struct GNUNET_PeerIdentity *key,
+ void *value)
+{
+ struct MeshTunnel3 *t = value;
+
+ GMT_destroy (t);
+ return GNUNET_YES;
+}
+
+
/**
* Demultiplex data per channel and call appropriate channel handler.
*
/**
- * Handle channel NACK.
+ * Handle channel NACK: check correctness and call channel handler for NACKs.
*
- * @param t Tunnel on which the data came.
- * @param msg Data message.
+ * @param t Tunnel on which the NACK came.
+ * @param msg NACK message.
*/
static void
handle_ch_nack (struct MeshTunnel3 *t,
/* Check channel */
ch = GMT_get_channel (t, ntohl (msg->chid));
- if (NULL != ch && ! GMT_is_loopback (t))
+ if (NULL == ch)
{
GNUNET_STATISTICS_update (stats, "# channel NACK on unknown channel",
1, GNUNET_NO);
{
LOG (GNUNET_ERROR_TYPE_DEBUG, " our key was sent, send ping\n");
send_ping (t);
- t->state = MESH_TUNNEL3_PING_SENT;
+ t->state = MESH_TUNNEL3_REKEY;
}
}
t_decrypt (t, &res.target, &msg->target, ping_encryption_size (), msg->iv);
if (0 != memcmp (&my_full_id, &res.target, sizeof (my_full_id)))
{
- GNUNET_break (0);
+ GNUNET_break_op (0);
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);
GNUNET_SCHEDULER_cancel (rekey_task);
rekey_task = GNUNET_SCHEDULER_NO_TASK;
}
+ GNUNET_CONTAINER_multipeermap_iterate (tunnels, &destroy_iterator, NULL);
GNUNET_CONTAINER_multipeermap_destroy (tunnels);
}
{
struct MeshTConnection *iter;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel empty: destroying scheduled\n");
for (iter = t->connection_head; NULL != iter; iter = iter->next)
{
GMC_send_destroy (iter->c);
void
GMT_destroy (struct MeshTunnel3 *t)
{
- struct MeshTConnection *iter;
- struct MeshTConnection *next;
+ struct MeshTConnection *iter_c;
+ struct MeshTConnection *next_c;
+ struct MeshTChannel *iter_ch;
+ struct MeshTChannel *next_ch;
if (NULL == t)
return;
LOG (GNUNET_ERROR_TYPE_DEBUG, "destroying tunnel %s\n", GMP_2s (t->peer));
-// if (GNUNET_YES != GNUNET_CONTAINER_multihashmap_remove (tunnels, &t->id, t))
-// GNUNET_break (0);
+ GNUNET_break (GNUNET_YES ==
+ GNUNET_CONTAINER_multipeermap_remove (tunnels,
+ GMP_get_id (t->peer), t));
- for (iter = t->connection_head; NULL != iter; iter = next)
+ for (iter_c = t->connection_head; NULL != iter_c; iter_c = next_c)
+ {
+ next_c = iter_c->next;
+ GMC_destroy (iter_c->c);
+ }
+ for (iter_ch = t->channel_head; NULL != iter_ch; iter_ch = next_ch)
{
- next = iter->next;
- GMC_destroy (iter->c);
+ next_ch = iter_ch->next;
+ GMCH_destroy (iter_ch->ch);
+ /* Should only happen on shutdown, but it's ok. */
}
GNUNET_STATISTICS_update (stats, "# tunnels", -1, GNUNET_NO);
if (NULL != t->channel_head)
LOG (GNUNET_ERROR_TYPE_DEBUG, " head ch: %p\n", t->channel_head->ch);
- if (NULL == t)
- {
- GNUNET_break (0);
- return;
- }
-
/* Get buffer space */
buffer = GMT_get_connections_buffer (t);
if (0 == buffer)
unsigned int cs;
unsigned int buffer;
- LOG (GNUNET_ERROR_TYPE_DEBUG,
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
"Tunnel send connection ACKs on %s\n",
GMT_2s (t));
}
+/**
+ * Callback called when a queued message is sent.
+ *
+ * Calculates the average time and connection packet tracking.
+ *
+ * @param cls Closure (TunnelQueue handle).
+ * @param c Connection this message was on.
+ * @param type Type of message sent.
+ * @param fwd Was this a FWD going message?
+ * @param size Size of the message.
+ */
+static void
+message_sent (void *cls,
+ struct MeshConnection *c,
+ struct MeshConnectionQueue *q,
+ uint16_t type, int fwd, size_t size)
+{
+ struct MeshTunnel3Queue *qt = cls;
+
+ GNUNET_assert (NULL != qt->cont);
+ qt->cont (qt->cont_cls, GMC_get_tunnel (c), qt, type, size);
+ GNUNET_free (qt);
+}
+
+
+/**
+ * Cancel a previously sent message while it's in the queue.
+ *
+ * ONLY can be called before the continuation given to the send function
+ * is called. Once the continuation is called, the message is no longer in the
+ * queue.
+ *
+ * @param q Handle to the queue.
+ */
+void
+GMT_cancel (struct MeshTunnel3Queue *q)
+{
+ GMC_cancel (q->q);
+ /* message_sent() will be called and free q */
+}
+
/**
* Sends an already built message on a tunnel, encrypting it and
* choosing the best connection.
* @param t Tunnel on which this message is transmitted.
* @param ch Channel on which this message is transmitted.
* @param fwd Is this a fwd message on @c ch?
+ * @param cont Continuation to call once message is really sent.
+ * @param cont_cls Closure for @c cont.
+ *
+ * @return Handle to cancel message. NULL if @c cont is NULL.
*/
-void
+struct MeshTunnel3Queue *
GMT_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
struct MeshTunnel3 *t,
- struct MeshChannel *ch,
- int fwd)
+ struct MeshChannel *ch, int fwd,
+ GMT_sent cont, void *cont_cls)
{
+ struct MeshTunnel3Queue *q;
struct MeshConnection *c;
struct GNUNET_MESH_Encrypted *msg;
size_t size = ntohs (message->size);
if (MESH_TUNNEL3_READY != t->state)
{
queue_data (t, ch, message);
- return;
+ /* FIXME */
+ return NULL;
}
LOG (GNUNET_ERROR_TYPE_DEBUG, "GMT Send on Tunnel %s\n", GMT_2s (t));
{
LOG (GNUNET_ERROR_TYPE_DEBUG, " loopback!\n");
handle_decrypted (t, message, fwd);
- return;
+ /* FIXME: call cont? */
+ return NULL; /* Already delivered, cannot cancel */
}
iv = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX);
if (NULL == c)
{
GNUNET_break (GNUNET_YES == t->destroy);
- return;
+ return NULL;
}
type = ntohs (message->type);
switch (type)
}
fwd = GMC_is_origin (c, GNUNET_YES);
- /* FIXME allow channels to cancel */
- GMC_send_prebuilt_message (&msg->header, c, fwd, NULL, NULL);
+
+ if (NULL == cont)
+ {
+ (void) GMC_send_prebuilt_message (&msg->header, c, fwd, NULL, NULL);
+ return NULL;
+ }
+ q = GNUNET_new (struct MeshTunnel3Queue); /* FIXME valgrind: leak*/
+ q->q = GMC_send_prebuilt_message (&msg->header, c, fwd, &message_sent, q);
+ q->cont = cont;
+ q->cont_cls = cont_cls;
+
+ return q;
}
/**
return "(NULL)";
return GMP_2s (t->peer);
-}
\ No newline at end of file
+}