#define LOG(level, ...) GNUNET_log_from(level,"mesh-chn",__VA_ARGS__)
+#define MESH_RETRANSMIT_MARGIN 4
+
/**
* All the states a connection can be in.
*/
/******************************** STATIC ***********************************/
/******************************************************************************/
+/**
+ * Destroy a reliable message after it has been acknowledged, either by
+ * direct mid ACK or bitfield. Updates the appropriate data structures and
+ * timers and frees all memory.
+ *
+ * @param copy Message that is no longer needed: remote peer got it.
+ */
+static void
+rel_message_free (struct MeshReliableMessage *copy);
+
/**
* We have received a message out of order, or the client is not ready.
* Buffer it until we receive an ACK from the client or the missing
LOG (GNUNET_ERROR_TYPE_DEBUG,
"Channel send connection %s ack on %s:%X\n",
- fwd ? "FWD" : "BCK", peer2s (ch->t->peer), ch->gid);
+ fwd ? "FWD" : "BCK", GMT_2s (ch->t), ch->gid);
GNUNET_break (to_allow == 0);
}
LOG (GNUNET_ERROR_TYPE_DEBUG,
" channel confirm %s %s:%X\n",
- fwd ? "FWD" : "BCK", peer2s (ch->t->peer), ch->gid);
+ fwd ? "FWD" : "BCK", GMT_2s (ch->t), ch->gid);
ch->state = MESH_CHANNEL_READY;
rel = fwd ? ch->root_rel : ch->dest_rel;
return;
LOG (GNUNET_ERROR_TYPE_DEBUG, "destroying channel %s:%u\n",
- peer2s (ch->t->peer), ch->gid);
+ GMT_2s (ch->t), ch->gid);
GMCH_debug (ch);
c = ch->root;
if (NULL != c)
{
- if (GNUNET_YES != GNUNET_CONTAINER_multihashmap32_remove (c->own_channels,
- ch->lid_root, ch))
- {
- GNUNET_break (0);
- }
+ GML_channel_remove (c, ch->lid_root, ch);
}
c = ch->dest;
if (NULL != c)
{
- if (GNUNET_YES !=
- GNUNET_CONTAINER_multihashmap32_remove (c->incoming_channels,
- ch->lid_dest, ch))
- {
- GNUNET_break (0);
- }
+ GML_channel_remove (c, ch->lid_dest, ch);
}
channel_rel_free_all (ch->root_rel);
channel_rel_free_all (ch->dest_rel);
- GNUNET_CONTAINER_DLL_remove (ch->t->channel_head, ch->t->channel_tail, ch);
+ GMT_remove_channel (ch->t, ch);
GNUNET_STATISTICS_update (stats, "# channels", -1, GNUNET_NO);
GNUNET_free (ch);
if (NULL != owner)
{
- while (NULL != channel_get (t, t->next_chid))
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Channel %u exists (%p)...\n",
- t->next_chid, channel_get (t, t->next_chid));
- t->next_chid = (t->next_chid + 1) & ~GNUNET_MESH_LOCAL_CHANNEL_ID_CLI;
- }
- ch->gid = t->next_chid;
- t->next_chid = (t->next_chid + 1) & ~GNUNET_MESH_LOCAL_CHANNEL_ID_CLI;
-
- if (GNUNET_OK !=
- GNUNET_CONTAINER_multihashmap32_put (owner->own_channels, lid_root, ch,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
- {
- GNUNET_break (0);
- channel_destroy (ch);
- GNUNET_SERVER_receive_done (owner->handle, GNUNET_SYSERR);
- return NULL;
- }
+ ch->gid = GMT_get_next_chid (t);
+ GML_channel_add (owner, lid_root, ch);
}
- GNUNET_CONTAINER_DLL_insert (t->channel_head, t->channel_tail, ch);
+ GMT_add_channel (t, ch);
return ch;
}
msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_CHANNEL_ACK);
LOG (GNUNET_ERROR_TYPE_DEBUG,
" sending channel %s ack for channel %s:%X\n",
- fwd ? "FWD" : "BCK", peer2s (ch->t->peer),
+ fwd ? "FWD" : "BCK", GMT_2s (ch->t),
ch->gid);
msg.chid = htonl (ch->gid);
}
-/**
- * Send a message to all clients (local and remote) of this channel
- * notifying that the channel is no longer valid.
- *
- * If some peer or client should not receive the message,
- * should be zero'ed out before calling this function.
- *
- * @param ch The channel whose clients to notify.
- */
-static void
-channel_send_destroy (struct MeshChannel *ch)
-{
- struct GNUNET_MESH_ChannelManage msg;
-
- msg.header.size = htons (sizeof (msg));
- msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_CHANNEL_DESTROY);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- " sending channel destroy for channel %s:%X\n",
- peer2s (ch->t->peer),
- ch->gid);
-
- if (GMCH_is_terminal (ch, GNUNET_NO))
- {
- if (NULL != ch->root && GNUNET_NO == ch->root->shutting_down)
- {
- msg.chid = htonl (ch->lid_root);
- send_local_channel_destroy (ch, GNUNET_NO);
- }
- }
- else
- {
- msg.chid = htonl (ch->gid);
- GMCH_send_prebuilt_message (&msg.header, ch, GNUNET_NO);
- }
-
- if (GMCH_is_terminal (ch, GNUNET_YES))
- {
- if (NULL != ch->dest && GNUNET_NO == ch->dest->shutting_down)
- {
- msg.chid = htonl (ch->lid_dest);
- send_local_channel_destroy (ch, GNUNET_YES);
- }
- }
- else
- {
- msg.chid = htonl (ch->gid);
- GMCH_send_prebuilt_message (&msg.header, ch, GNUNET_YES);
- }
-}
-
-
/**
* Iterator for deleting each channel whose client endpoint disconnected.
*
struct MeshTunnel3 *t;
LOG (GNUNET_ERROR_TYPE_DEBUG,
- " Channel %X (%X / %X) destroy, due to client %u shutdown.\n",
- ch->gid, ch->lid_root, ch->lid_dest, c->id);
- channel_debug (ch);
+ " Channel %X (%X / %X) destroy, due to client %s shutdown.\n",
+ ch->gid, ch->lid_root, ch->lid_dest, GML_2s (c));
+ GMCH_debug (ch);
if (c == ch->dest)
{
- LOG (GNUNET_ERROR_TYPE_DEBUG, " Client %u is destination.\n", c->id);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " Client %s is destination.\n", GML_2s (c));
}
if (c == ch->root)
{
- LOG (GNUNET_ERROR_TYPE_DEBUG, " Client %u is owner.\n", c->id);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " Client %s is owner.\n", GML_2s (c));
}
t = ch->t;
GMCH_send_destroy (ch);
- channel_send_destroy (ch);
channel_destroy (ch);
- tunnel_destroy_if_empty (t);
+ GMT_destroy_if_empty (t);
return GNUNET_OK;
}
+/**
+ * Handle a loopback message: call the appropriate handler for the message type.
+ *
+ * @param ch Channel this message is on.
+ * @param msgh Message header.
+ * @param fwd Is this FWD traffic?
+ */
+void
+handle_loopback (struct MeshChannel *ch,
+ struct GNUNET_MessageHeader *msgh,
+ int fwd)
+{
+ uint16_t type;
+
+ type = ntohs (msgh->type);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Loopback %s message!\n",
+ GNUNET_MESH_DEBUG_M2S (type));
+
+ switch (type)
+ {
+ case GNUNET_MESSAGE_TYPE_MESH_DATA:
+ /* Don't send hop ACK, wait for client to ACK */
+ GMCH_handle_data (ch, (struct GNUNET_MESH_Data *) msgh, fwd);
+ break;
+
+ case GNUNET_MESSAGE_TYPE_MESH_DATA_ACK:
+ GMCH_handle_data_ack (ch, (struct GNUNET_MESH_DataACK *) msgh, fwd);
+ break;
+
+ case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_CREATE:
+ // FIXME store channel in loopback tunnel?
+ GMCH_handle_create ((struct GNUNET_MESH_ChannelCreate *) msgh,
+ fwd);
+ break;
+
+ case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_ACK:
+ GMCH_handle_ack (ch,
+ (struct GNUNET_MESH_ChannelManage *) msgh,
+ fwd);
+ break;
+
+ case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_DESTROY:
+ GMCH_handle_destroy (ch,
+ (struct GNUNET_MESH_ChannelManage *) msgh,
+ fwd);
+ break;
+
+ default:
+ GNUNET_break_op (0);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "end-to-end message not known (%u)\n",
+ ntohs (msgh->type));
+ }
+}
+
+
+
/******************************************************************************/
/******************************** API ***********************************/
/******************************************************************************/
GMCH_send_create (struct MeshChannel *ch)
{
struct GNUNET_MESH_ChannelMessage msg;
- struct MeshTunnel3 *t = ch->t;
uint32_t opt;
if (NULL == ch->dest)
opt |= GNUNET_YES == ch->reliable ? GNUNET_MESH_OPTION_RELIABLE : 0;
opt |= GNUNET_YES == ch->nobuffer ? GNUNET_MESH_OPTION_NOBUFFER : 0;
GML_send_channel_create (ch->dest, ch->lid_dest, ch->port, opt,
- GNUNET_PEER_resolve2 (t->peer->id));
+ GMT_get_destination (ch->t));
}
/**
* Notify a client that the channel is no longer valid.
+ * FIXME send on tunnel if some client == NULL?
*
* @param ch Channel that is destroyed.
- * @param fwd Forward notification (owner->dest)?
*/
void
-GMCH_send_destroy (struct MeshChannel *ch, int fwd)
+GMCH_send_destroy (struct MeshChannel *ch)
{
- struct GNUNET_MeshClient *c = fwd ? ch->dest : ch->root;
- uint32_t id = fwd ? ch->lid_dest : ch->lid_root;
-
- if (NULL == c)
- {
-// TODO: send on connection?
- return;
- }
+ if (NULL != ch->root)
+ GML_send_channel_destroy (ch->root, ch->lid_root);
- GML_send_channel_destroy (c, id);
+ if (NULL != ch->dest)
+ GML_send_channel_destroy (ch->dest, ch->lid_dest);
}
* @param ch Channel this is about.
* @param fwd Is for FWD traffic? (ACK dest->owner)
*/
-static void
+void
GMCH_send_ack (struct MeshChannel *ch, int fwd)
{
struct GNUNET_MESH_DataACK msg;
}
LOG (GNUNET_ERROR_TYPE_DEBUG, " final futures %llX\n", msg.futures);
- send_prebuilt_message_channel (&msg.header, ch, fwd);
+ GMCH_send_prebuilt_message (&msg.header, ch, fwd);
LOG (GNUNET_ERROR_TYPE_DEBUG, "send_data_ack END\n");
}
return;
}
LOG (GNUNET_ERROR_TYPE_DEBUG, "Channel %s:%X (%p)\n",
- peer2s (ch->t->peer), ch->gid, ch);
+ GMT_2s (ch->t), ch->gid, ch);
LOG (GNUNET_ERROR_TYPE_DEBUG, " root %p/%p\n",
ch->root, ch->root_rel);
if (NULL != ch->root)
{
- LOG (GNUNET_ERROR_TYPE_DEBUG, " cli %u\n", ch->root->id);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " cli %s\n", GML_2s (ch->root));
LOG (GNUNET_ERROR_TYPE_DEBUG, " ready %s\n",
ch->root_rel->client_ready ? "YES" : "NO");
LOG (GNUNET_ERROR_TYPE_DEBUG, " id %X\n", ch->lid_root);
ch->dest, ch->dest_rel);
if (NULL != ch->dest)
{
- LOG (GNUNET_ERROR_TYPE_DEBUG, " cli %u\n", ch->dest->id);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " cli %s\n", GML_2s (ch->dest));
LOG (GNUNET_ERROR_TYPE_DEBUG, " ready %s\n",
ch->dest_rel->client_ready ? "YES" : "NO");
LOG (GNUNET_ERROR_TYPE_DEBUG, " id %X\n", ch->lid_dest);
/**
* Handler for channel create messages.
*
- * @param t Tunnel this channel is to be created in.
* @param msg Message.
* @param fwd Is this FWD traffic? GNUNET_YES : GNUNET_NO;
*/
struct MeshClient *c;
uint32_t port;
- /* Check if channel exists */
chid = ntohl (msg->chid);
/* Create channel */
return;
}
- GMCH_send_destroy (ch, fwd);
+ GMCH_send_destroy (ch);
channel_destroy (ch);
}
/**
- * Sends an already built message on a channel, properly registering
- * all used resources and encrypting the message with the tunnel's key.
+ * Sends an already built message on a channel.
*
* @param message Message to send. Function makes a copy of it.
* @param ch Channel on which this message is transmitted.
GMCH_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
struct MeshChannel *ch, int fwd)
{
- struct GNUNET_MESH_Encrypted *msg;
size_t size = ntohs (message->size);
- char *cbuf[sizeof (struct GNUNET_MESH_Encrypted) + size];
- uint16_t type;
- uint64_t iv;
-
+
LOG (GNUNET_ERROR_TYPE_DEBUG, "Send on Channel %s:%X %s\n",
- peer2s (ch->t->peer), ch->gid, fwd ? "FWD" : "BCK");
+ GMT_2s (ch->t), ch->gid, fwd ? "FWD" : "BCK");
LOG (GNUNET_ERROR_TYPE_DEBUG, " %s\n",
GNUNET_MESH_DEBUG_M2S (ntohs (message->type)));
-
- if (GMCH_is_terminal (ch, fwd) || ch->t->peer->id == myid)
+
+ if (GMT_is_loopback (ch->t))
{
- GMT_handle_decrypted (ch->t, message, fwd);
+ handle_loopback (ch->t, message, fwd);
return;
}
-
- type = fwd ? GNUNET_MESSAGE_TYPE_MESH_FWD : GNUNET_MESSAGE_TYPE_MESH_BCK;
- iv = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_NONCE, UINT64_MAX);
-
- msg = (struct GNUNET_MESH_Encrypted *) cbuf;
- msg->header.type = htons (type);
- msg->header.size = htons (sizeof (struct GNUNET_MESH_Encrypted) + size);
- msg->iv = GNUNET_htonll (iv);
- GMT_encrypt (ch->t, &msg[1], message, size, iv, fwd);
- GMT_send_prebuilt_message (msg, ch->t, ch, fwd);
+
+ GMT_send_prebuilt_message (message, ch->t, ch, fwd);
}
}
}
-
-/**
- * Search for a channel by global ID using full PeerIdentities.
- *
- * @param t Tunnel containing the channel.
- * @param chid Public channel number.
- *
- * @return channel handler, NULL if doesn't exist
- */
-static struct MeshChannel *
-get_channel (struct MeshTunnel3 *t, MESH_ChannelNumber chid)
-{
- struct MeshTChannel *iter;
-
- if (NULL == t)
- return NULL;
-
- for (iter = t->channel_head; NULL != iter; iter = iter->next)
- {
- if (GMCH_get_id (iter->ch) == chid)
- break;
- }
-
- return NULL == iter ? NULL : iter->ch;
-}
-
-
/**
* Pick a connection on which send the next data message.
*
GNUNET_MESH_DEBUG_M2S (ntohs (msg[1].header.type)));
/* Check channel */
- ch = get_channel (t, ntohl (msg->chid));
+ ch = GMT_get_channel (t, ntohl (msg->chid));
if (NULL == ch)
{
GNUNET_STATISTICS_update (stats, "# data on unknown channel",
}
/* Check channel */
- ch = get_channel (t, ntohl (msg->chid));
+ ch = GMT_get_channel (t, ntohl (msg->chid));
if (NULL == ch)
{
GNUNET_STATISTICS_update (stats, "# data ack on unknown channel",
}
/* Check channel */
- ch = get_channel (t, ntohl (msg->chid));
+ ch = GMT_get_channel (t, ntohl (msg->chid));
if (NULL != ch)
{
/* Probably a retransmission, safe to ignore */
}
/* Check channel */
- ch = get_channel (t, ntohl (msg->chid));
+ ch = GMT_get_channel (t, ntohl (msg->chid));
if (NULL == ch)
{
GNUNET_STATISTICS_update (stats, "# channel ack on unknown channel",
}
/* Check channel */
- ch = get_channel (t, ntohl (msg->chid));
+ ch = GMT_get_channel (t, ntohl (msg->chid));
if (NULL == ch)
{
/* Probably a retransmission, safe to ignore */
}
+/**
+ * Add a channel to a tunnel.
+ *
+ * @param t Tunnel.
+ * @param ch Channel.
+ */
+void
+GMT_add_channel (struct MeshTunnel3 *t, struct MeshChannel *ch)
+{
+ struct MeshTChannel *aux;
+
+ for (aux = t->channel_head; aux != NULL; aux = aux->next)
+ if (aux->ch == ch)
+ return;
+
+ aux = GNUNET_new (struct MeshTChannel);
+ aux->ch = ch;
+ GNUNET_CONTAINER_DLL_insert_tail (t->channel_head, t->channel_tail, aux);
+}
+
+
+/**
+ * Remove a channel from a tunnel.
+ *
+ * @param t Tunnel.
+ * @param ch Channel.
+ */
+void
+GMT_remove_channel (struct MeshTunnel3 *t, struct MeshChannel *ch)
+{
+ struct MeshTChannel *aux;
+
+ for (aux = t->channel_head; aux != NULL; aux = aux->next)
+ if (aux->ch == ch)
+ {
+ GNUNET_CONTAINER_DLL_remove (t->channel_head, t->channel_tail, aux);
+ GNUNET_free (aux);
+ return;
+ }
+}
+
+
+/**
+ * Search for a channel by global ID.
+ *
+ * @param t Tunnel containing the channel.
+ * @param chid Public channel number.
+ *
+ * @return channel handler, NULL if doesn't exist
+ */
+struct MeshChannel *
+GMT_get_channel (struct MeshTunnel3 *t, MESH_ChannelNumber chid)
+{
+ struct MeshTChannel *iter;
+
+ if (NULL == t)
+ return NULL;
+
+ for (iter = t->channel_head; NULL != iter; iter = iter->next)
+ {
+ if (GMCH_get_id (iter->ch) == chid)
+ break;
+ }
+
+ return NULL == iter ? NULL : iter->ch;
+}
+
+
/**
* Tunnel is empty: destroy it.
*
/**
* FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME
* Encrypt data with the tunnel key.
+ * Make static?
*
* @param t Tunnel whose key to use.
* @param dst Destination for the encrypted data.
/**
* FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME
* Decrypt data with the tunnel key.
+ * Make static?
*
* @param t Tunnel whose key to use.
* @param dst Destination for the plaintext.
return buffer;
}
+
+/**
+ * Get the tunnel's destination.
+ *
+ * @param t Tunnel.
+ *
+ * @return ID of the destination peer.
+ */
+const struct GNUNET_PeerIdentity *
+GMT_get_destination (struct MeshTunnel3 *t)
+{
+ return GMP_get_id (t->peer);
+}
+
+
+
/**
- * Sends an already built message on a tunnel, choosing the best connection.
+ * Get the tunnel's next free Channel ID.
+ *
+ * @param t Tunnel.
+ *
+ * @return ID of a channel free to use.
+ */
+MESH_ChannelNumber
+GMT_get_next_chid (struct MeshTunnel3 *t)
+{
+ MESH_ChannelNumber chid;
+
+ while (NULL != GMT_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_MESH_LOCAL_CHANNEL_ID_CLI;
+ }
+ chid = t->next_chid;
+ t->next_chid = (t->next_chid + 1) & ~GNUNET_MESH_LOCAL_CHANNEL_ID_CLI;
+
+ return chid;
+}
+
+
+/**
+ * Sends an already built message on a tunnel, encrypting it and
+ * choosing the best connection.
*
* @param message Message to send. Function modifies it.
* @param t Tunnel on which this message is transmitted.
* @param fwd Is this a fwd message?
*/
void
-GMT_send_prebuilt_message (struct GNUNET_MESH_Encrypted *msg,
+GMT_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
struct MeshTunnel3 *t,
struct MeshChannel *ch,
int fwd)
{
struct MeshConnection *c;
+ struct GNUNET_MESH_Encrypted *msg;
+ size_t size = ntohs (message->size);
+ char *cbuf[sizeof (struct GNUNET_MESH_Encrypted) + size];
+ uint64_t iv;
uint16_t type;
LOG (GNUNET_ERROR_TYPE_DEBUG, "Send on Tunnel %s\n", GMP_2s (t->peer));
+
+ iv = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_NONCE, UINT64_MAX);
+ msg = (struct GNUNET_MESH_Encrypted *) cbuf;
+ msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_ENCRYPTED);
+ msg->header.size = htons (sizeof (struct GNUNET_MESH_Encrypted) + size);
+ msg->iv = GNUNET_htonll (iv);
+ GMT_encrypt (t, &msg[1], message, size, iv, fwd);
c = tunnel_get_connection (t, fwd);
if (NULL == c)
{
GNUNET_break (GNUNET_YES == t->destroy);
return;
}
- type = ntohs (msg->header.type);
+ type = ntohs (message->type);
switch (type)
{
case GNUNET_MESSAGE_TYPE_MESH_FWD:
GMC_send_prebuilt_message (&msg->header, c, ch, fwd);
}
+
+/**
+ * Is the tunnel directed towards the local peer?
+ *
+ * @param t Tunnel.
+ *
+ * @return GNUNET_YES if it is loopback.
+ */
+int
+GMT_is_loopback (const struct MeshTunnel3 *t)
+{
+ return (my_short_id == GMP_get_short_id(t->peer));
+}
+
+
+/**
+ * Get the static string for the peer this tunnel is directed.
+ *
+ * @param t Tunnel.
+ *
+ * @return Static string the destination peer's ID.
+ */
+const char *
+GMT_2s (const struct MeshTunnel3 *t)
+{
+ return GMP_2s (t->peer);
+}
\ No newline at end of file