#include "gnunet-service-mesh_channel.h"
#include "gnunet-service-mesh_local.h"
#include "gnunet-service-mesh_tunnel.h"
+#include "gnunet-service-mesh_peer.h"
#define LOG(level, ...) GNUNET_log_from(level,"mesh-chn",__VA_ARGS__)
+#define MESH_RETRANSMIT_TIME GNUNET_TIME_UNIT_SECONDS
+#define MESH_RETRANSMIT_MARGIN 4
+
+
/**
* All the states a connection can be in.
*/
MESH_CHANNEL_SENT,
/**
- * Connection confirmed, ready to carry traffic..
+ * Connection confirmed, ready to carry traffic.
*/
MESH_CHANNEL_READY,
};
*/
int client_ready;
+ /**
+ * Can the client send data to us?
+ */
+ int client_allowed;
+
/**
* Task to resend/poll in case no ACK is received.
*/
*/
extern struct GNUNET_STATISTICS_Handle *stats;
+/**
+ * Local peer own ID (memory efficient handle).
+ */
+extern GNUNET_PEER_Id myid;
+
/******************************************************************************/
/******************************** 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, "add_buffered_data END\n");
}
+/**
+ * Add a destination client to a channel, initializing all data structures
+ * in the channel and the client.
+ *
+ * @param ch Channel to which add the destination.
+ * @param c Client which to add to the channel.
+ */
+static void
+add_destination (struct MeshChannel *ch, struct MeshClient *c)
+{
+ if (NULL != ch->dest)
+ {
+ GNUNET_break (0);
+ return;
+ }
+
+ /* Assign local id as destination */
+ ch->lid_dest = GML_get_next_chid (c);
+
+ /* Store in client's hashmap */
+ GML_channel_add (c, ch->lid_dest, ch);
+
+ GNUNET_break (NULL == ch->dest_rel);
+ ch->dest_rel = GNUNET_new (struct MeshChannelReliability);
+ ch->dest_rel->ch = ch;
+ ch->dest_rel->expected_delay = MESH_RETRANSMIT_TIME;
+
+ ch->dest = c;
+}
+
/**
* Send data to a client.
if (fwd)
{
if (ch->dest_rel->client_ready)
- GML_send_data (ch, msg, ch->dest, ch->lid_dest);
+ GML_send_data (ch->dest, msg, ch->lid_dest);
else
add_buffered_data (msg, ch->dest_rel);
}
else
{
if (ch->root_rel->client_ready)
- GML_send_data (ch, msg, ch->root, ch->lid_root);
+ GML_send_data (ch->root, msg, ch->lid_root);
else
add_buffered_data (msg, ch->root_rel);
}
/**
- * Search for a channel among the channels for a client
- *
- * @param c the client whose channels to search in
- * @param chid the local id of the channel
+ * Send a buffered message to the client, for in order delivery or
+ * as result of client ACK.
*
- * @return channel handler, NULL if doesn't exist
+ * @param ch Channel on which to empty the message buffer.
+ * @param c Client to send to.
+ * @param fwd Is this to send FWD data?.
*/
-static struct MeshChannel *
-channel_get_by_local_id (struct MeshClient *c, MESH_ChannelNumber chid)
+static void
+send_client_buffered_data (struct MeshChannel *ch,
+ struct MeshClient *c,
+ int fwd)
{
- LOG (GNUNET_ERROR_TYPE_DEBUG, " -- get CHID %X\n", chid);
- if (0 == (chid & GNUNET_MESH_LOCAL_CHANNEL_ID_CLI))
+ struct MeshReliableMessage *copy;
+ struct MeshChannelReliability *rel;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "send_buffered_data\n");
+ rel = fwd ? ch->dest_rel : ch->root_rel;
+ if (GNUNET_NO == rel->client_ready)
{
- GNUNET_break_op (0);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "CHID %X not a local chid\n", chid);
- return NULL;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "client not ready\n");
+ return;
+ }
+
+ copy = rel->head_recv;
+ /* We never buffer channel management messages */
+ if (NULL != copy)
+ {
+ if (copy->mid == rel->mid_recv || GNUNET_NO == ch->reliable)
+ {
+ struct GNUNET_MESH_Data *msg = (struct GNUNET_MESH_Data *) ©[1];
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ " have %u! now expecting %u\n",
+ copy->mid, rel->mid_recv + 1);
+ send_client_data (ch, msg, fwd);
+ rel->n_recv--;
+ rel->mid_recv++;
+ GNUNET_CONTAINER_DLL_remove (rel->head_recv, rel->tail_recv, copy);
+ GNUNET_free (copy);
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ " reliable && don't have %u, next is %u\n",
+ rel->mid_recv,
+ copy->mid);
+ return;
+ }
}
- if (chid >= GNUNET_MESH_LOCAL_CHANNEL_ID_SERV)
- return GNUNET_CONTAINER_multihashmap32_get (c->incoming_channels, chid);
- return GNUNET_CONTAINER_multihashmap32_get (c->own_channels, chid);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "send_buffered_data END\n");
}
/**
- * Add a client to a channel, initializing all needed data structures.
+ * Allow a client to send more data.
*
- * @param ch Channel to which add the client.
- * @param c Client which to add to the channel.
+ * In case the client was already allowed to send data, do nothing.
+ *
+ * @param ch Channel.
+ * @param fwd Is this a FWD ACK? (FWD ACKs are sent to root)
*/
static void
-channel_add_client (struct MeshChannel *ch, struct MeshClient *c)
+send_client_ack (struct MeshChannel *ch, int fwd)
{
- struct MeshTunnel3 *t = ch->t;
+ struct MeshChannelReliability *rel = fwd ? ch->root_rel : ch->dest_rel;
- if (NULL != ch->dest)
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ " sending %s ack to client on channel %s\n",
+ fwd ? "FWD" : "BCK", GMCH_2s (ch));
+
+ if (NULL == rel)
{
GNUNET_break (0);
return;
}
- /* Assign local id as destination */
- while (NULL != channel_get_by_local_id (c, t->next_local_chid))
- t->next_local_chid = (t->next_local_chid + 1) | GNUNET_MESH_LOCAL_CHANNEL_ID_SERV;
- ch->lid_dest = t->next_local_chid++;
- t->next_local_chid = t->next_local_chid | GNUNET_MESH_LOCAL_CHANNEL_ID_SERV;
-
- /* Store in client's hashmap */
- if (GNUNET_OK !=
- GNUNET_CONTAINER_multihashmap32_put (c->incoming_channels,
- ch->lid_dest, ch,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
+ if (GNUNET_YES == rel->client_allowed)
{
- GNUNET_break (0);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " already allowed\n");
return;
}
+ rel->client_allowed = GNUNET_YES;
- GNUNET_break (NULL == ch->dest_rel);
- ch->dest_rel = GNUNET_new (struct MeshChannelReliability);
- ch->dest_rel->ch = ch;
- ch->dest_rel->expected_delay = MESH_RETRANSMIT_TIME;
-
- ch->dest = c;
-}
-
-
-
-/**
- * Is the root client for this channel on this peer?
- *
- * @param ch Channel.
- * @param fwd Is this for fwd traffic?
- *
- * @return GNUNET_YES in case it is.
- */
-static int
-channel_is_origin (struct MeshChannel *ch, int fwd)
-{
- struct MeshClient *c;
-
- c = fwd ? ch->root : ch->dest;
- return NULL != c;
+ GML_send_ack (fwd ? ch->root : ch->dest, fwd ? ch->lid_root : ch->lid_dest);
}
/**
- * Is the destination client for this channel on this peer?
- *
- * @param ch Channel.
- * @param fwd Is this for fwd traffic?
+ * Notify the root that the destination rejected the channel.
*
- * @return GNUNET_YES in case it is.
+ * @param ch Rejected channel.
*/
-static int
-channel_is_terminal (struct MeshChannel *ch, int fwd)
+static void
+send_client_nack (struct MeshChannel *ch)
{
- struct MeshClient *c;
-
- c = fwd ? ch->dest : ch->root;
- return NULL != c;
+ if (NULL == ch->root)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ GML_send_nack (ch->root, ch->lid_root);
}
{
struct MeshChannelReliability *rel = cls;
struct MeshReliableMessage *copy;
- struct MeshPeerQueue *q;
struct MeshChannel *ch;
- struct MeshConnection *c;
struct GNUNET_MESH_Data *payload;
- struct MeshPeer *hop;
int fwd;
rel->retry_task = GNUNET_SCHEDULER_NO_TASK;
* - not sending the new one could cause terrible delays the old connection
* is stalled.
*/
+// FIXME access to queue elements is limited
payload = (struct GNUNET_MESH_Data *) ©[1];
fwd = (rel == ch->root_rel);
- c = tunnel_get_connection (ch->t, fwd);
- hop = connection_get_hop (c, fwd);
- for (q = hop->queue_head; NULL != q; q = q->next)
- {
- if (ntohs (payload->header.type) == q->type && ch == q->ch)
- {
- struct GNUNET_MESH_Data *queued_data = q->cls;
-
- if (queued_data->mid == payload->mid)
- break;
- }
- }
+// c = GMT_get_connection (ch->t, fwd);
+// hop = connection_get_hop (c, fwd);
+// for (q = hop->queue_head; NULL != q; q = q->next)
+// {
+// if (ntohs (payload->header.type) == q->type && ch == q->ch)
+// {
+// struct GNUNET_MESH_Data *queued_data = q->cls;
+//
+// if (queued_data->mid == payload->mid)
+// break;
+// }
+// }
/* Message not found in the queue that we are going to use. */
- if (NULL == q)
- {
+// if (NULL == q)
+// {
LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! RETRANSMIT %u\n", copy->mid);
- send_prebuilt_message_channel (&payload->header, ch, fwd);
+ GMCH_send_prebuilt_message (&payload->header, ch, fwd);
GNUNET_STATISTICS_update (stats, "# data retransmitted", 1, GNUNET_NO);
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! ALREADY IN QUEUE %u\n", copy->mid);
- }
+// }
+// else
+// {
+// LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! ALREADY IN QUEUE %u\n", copy->mid);
+// }
rel->retry_timer = GNUNET_TIME_STD_BACKOFF (rel->retry_timer);
rel->retry_task = GNUNET_SCHEDULER_add_delayed (rel->retry_timer,
}
-/**
- * Send ACK on one or more connections due to buffer space to the client.
- *
- * Iterates all connections of the tunnel and sends ACKs appropriately.
- *
- * @param ch Channel which has some free buffer space.
- * @param fwd Is this in for FWD traffic? (ACK goes dest->root)
- */
-static void
-channel_send_connections_ack (struct MeshChannel *ch,
- unsigned int buffer,
- int fwd)
-{
- struct MeshTunnel3 *t = ch->t;
- struct MeshConnection *c;
- struct MeshFlowControl *fc;
- uint32_t allowed;
- uint32_t to_allow;
- uint32_t allow_per_connection;
- unsigned int cs;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Channel send connection %s ack on %s:%X\n",
- fwd ? "FWD" : "BCK", peer2s (ch->t->peer), ch->gid);
-
- /* Count connections, how many messages are already allowed */
- for (cs = 0, allowed = 0, c = t->connection_head; NULL != c; c = c->next)
- {
- fc = fwd ? &c->fwd_fc : &c->bck_fc;
- if (GMC_is_pid_bigger(fc->last_pid_recv, fc->last_ack_sent))
- {
- GNUNET_break (0);
- continue;
- }
- allowed += fc->last_ack_sent - fc->last_pid_recv;
- cs++;
- }
-
- /* Make sure there is no overflow */
- if (allowed > buffer)
- {
- GNUNET_break (0);
- return;
- }
-
- /* Authorize connections to send more data */
- to_allow = buffer - allowed;
-
- for (c = t->connection_head; NULL != c && to_allow > 0; c = c->next)
- {
- allow_per_connection = to_allow/cs;
- to_allow -= allow_per_connection;
- cs--;
- fc = fwd ? &c->fwd_fc : &c->bck_fc;
- if (fc->last_ack_sent - fc->last_pid_recv > 64 / 3)
- {
- continue;
- }
- connection_send_ack (c, allow_per_connection, fwd);
- }
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Channel send connection %s ack on %s:%X\n",
- fwd ? "FWD" : "BCK", peer2s (ch->t->peer), ch->gid);
- GNUNET_break (to_allow == 0);
-}
-
-
/**
* Destroy a reliable message after it has been acknowledged, either by
* direct mid ACK or bitfield. Updates the appropriate data structures and
}
+/**
+ * Confirm we got a channel create.
+ *
+ * @param ch The channel to confirm.
+ * @param fwd Should we send a FWD ACK? (going dest->root)
+ */
+static void
+channel_send_ack (struct MeshChannel *ch, int fwd)
+{
+ struct GNUNET_MESH_ChannelManage msg;
+
+ msg.header.size = htons (sizeof (msg));
+ msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_CHANNEL_ACK);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ " sending channel %s ack for channel %s\n",
+ fwd ? "FWD" : "BCK", GMCH_2s (ch));
+
+ msg.chid = htonl (ch->gid);
+ GMCH_send_prebuilt_message (&msg.header, ch, !fwd);
+}
+
+
+/**
+ * Notify that a channel create didn't succeed.
+ *
+ * @param ch The channel to reject.
+ */
+static void
+channel_send_nack (struct MeshChannel *ch)
+{
+ struct GNUNET_MESH_ChannelManage msg;
+
+ msg.header.size = htons (sizeof (msg));
+ msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_CHANNEL_NACK);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ " sending channel NACK for channel %s\n",
+ GMCH_2s (ch));
+
+ msg.chid = htonl (ch->gid);
+ GMCH_send_prebuilt_message (&msg.header, ch, GNUNET_NO);
+}
+
/**
* Channel was ACK'd by remote peer, mark as ready and cancel retransmission.
*
* @param ch Channel to mark as ready.
- * @param fwd Was the CREATE message sent fwd?
+ * @param fwd Was the ACK message a FWD ACK? (dest->root, SYNACK)
*/
static void
channel_confirm (struct MeshChannel *ch, int fwd)
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;
+ rel->client_ready = GNUNET_YES;
for (copy = rel->head_sent; NULL != copy; copy = next)
{
struct GNUNET_MessageHeader *msg;
/* TODO return? */
}
}
- send_ack (NULL, ch, fwd);
+ send_client_ack (ch, fwd);
+
+ /* In case of a FWD ACK (SYNACK) send a BCK ACK (ACK). */
+ if (fwd)
+ channel_send_ack (ch, !fwd);
}
}
-
/**
- * Send a buffered message to the client, for in order delivery or
- * as result of client ACK.
+ * Destroy a channel and free all resources.
*
- * @param ch Channel on which to empty the message buffer.
- * @param c Client to send to.
- * @param rel Reliability structure to corresponding peer.
- * If rel == bck_rel, this is FWD data.
+ * @param ch Channel to destroy.
*/
static void
-send_client_buffered_data (struct MeshChannel *ch,
- struct MeshClient *c,
- int fwd)
+channel_destroy (struct MeshChannel *ch)
{
- struct MeshReliableMessage *copy;
- struct MeshChannelReliability *rel;
+ struct MeshClient *c;
- LOG (GNUNET_ERROR_TYPE_DEBUG, "send_buffered_data\n");
- rel = fwd ? ch->dest_rel : ch->root_rel;
- if (GNUNET_NO == rel->client_ready)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "client not ready\n");
+ if (NULL == ch)
return;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "destroying channel %s:%u\n",
+ GMT_2s (ch->t), ch->gid);
+ GMCH_debug (ch);
+
+ c = ch->root;
+ if (NULL != c)
+ {
+ GML_channel_remove (c, ch->lid_root, ch);
}
- copy = rel->head_recv;
- /* We never buffer channel management messages */
- if (NULL != copy)
+ c = ch->dest;
+ if (NULL != c)
{
- if (copy->mid == rel->mid_recv || GNUNET_NO == ch->reliable)
- {
- struct GNUNET_MESH_Data *msg = (struct GNUNET_MESH_Data *) ©[1];
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- " have %u! now expecting %u\n",
- copy->mid, rel->mid_recv + 1);
- send_client_data (ch, msg, fwd);
- rel->n_recv--;
- rel->mid_recv++;
- GNUNET_CONTAINER_DLL_remove (rel->head_recv, rel->tail_recv, copy);
- GNUNET_free (copy);
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- " reliable && don't have %u, next is %u\n",
- rel->mid_recv,
- copy->mid);
- return;
- }
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, "send_buffered_data END\n");
-}
-
-
-
-
-/**
- * Destroy a channel and free all resources.
- *
- * @param ch Channel to destroy.
- */
-static void
-channel_destroy (struct MeshChannel *ch)
-{
- struct MeshClient *c;
-
- if (NULL == ch)
- return;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "destroying channel %s:%u\n",
- peer2s (ch->t->peer), 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);
- }
- }
-
- 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);
*/
static struct MeshChannel *
channel_new (struct MeshTunnel3 *t,
- struct MeshClient *owner, MESH_ChannelNumber lid_root)
+ struct MeshClient *owner,
+ MESH_ChannelNumber lid_root)
{
struct MeshChannel *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;
}
GNUNET_YES : GNUNET_NO;
}
-
-
-/**
- * Confirm we got a channel create.
- *
- * @param ch The channel to confirm.
- * @param fwd Should we send the ACK fwd?
- */
-static void
-channel_send_ack (struct MeshChannel *ch, int fwd)
+static int
+is_loopback (const struct MeshChannel *ch)
{
- struct GNUNET_MESH_ChannelManage msg;
+ if (NULL != ch->t)
+ return GMT_is_loopback (ch->t);
- msg.header.size = htons (sizeof (msg));
- 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),
- ch->gid);
-
- msg.chid = htonl (ch->gid);
- GMCH_send_prebuilt_message (&msg.header, ch, !fwd);
+ return (NULL != ch->root && NULL != ch->dest);
}
/**
- * 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.
+ * Handle a loopback message: call the appropriate handler for the message type.
*
- * @param ch The channel whose clients to notify.
+ * @param ch Channel this message is on.
+ * @param msgh Message header.
+ * @param fwd Is this FWD traffic?
*/
-static void
-channel_send_destroy (struct MeshChannel *ch)
+void
+handle_loopback (struct MeshChannel *ch,
+ const struct GNUNET_MessageHeader *msgh,
+ int fwd)
{
- struct GNUNET_MESH_ChannelManage msg;
+ uint16_t type;
- msg.header.size = htons (sizeof (msg));
- msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_CHANNEL_DESTROY);
+ type = ntohs (msgh->type);
LOG (GNUNET_ERROR_TYPE_DEBUG,
- " sending channel destroy for channel %s:%X\n",
- peer2s (ch->t->peer),
- ch->gid);
+ "Loopback %s %s message!\n",
+ fwd ? "FWD" : "BCK", GNUNET_MESH_DEBUG_M2S (type));
- if (channel_is_terminal (ch, GNUNET_NO))
+ switch (type)
{
- 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 (channel_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);
- }
-}
+ 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;
-/**
- * Iterator for deleting each channel whose client endpoint disconnected.
- *
- * @param cls Closure (client that has disconnected).
- * @param key The local channel id (used to access the hashmap).
- * @param value The value stored at the key (channel to destroy).
- *
- * @return GNUNET_OK, keep iterating.
- */
-static int
-channel_destroy_iterator (void *cls,
- uint32_t key,
- void *value)
-{
- struct MeshChannel *ch = value;
- struct MeshClient *c = cls;
- struct MeshTunnel3 *t;
+ case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_CREATE:
+ GMCH_handle_create (ch->t,
+ (struct GNUNET_MESH_ChannelCreate *) msgh);
+ break;
- 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);
+ case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_ACK:
+ GMCH_handle_ack (ch,
+ (struct GNUNET_MESH_ChannelManage *) msgh,
+ fwd);
+ break;
- if (c == ch->dest)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " Client %u is destination.\n", c->id);
- }
- if (c == ch->root)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " Client %u is owner.\n", c->id);
- }
+ case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_NACK:
+ GMCH_handle_nack (ch);
+ break;
- t = ch->t;
- GMCH_send_destroy (ch);
- channel_send_destroy (ch);
- channel_destroy (ch);
- tunnel_destroy_if_empty (t);
+ case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_DESTROY:
+ GMCH_handle_destroy (ch,
+ (struct GNUNET_MESH_ChannelManage *) msgh,
+ fwd);
+ break;
- return GNUNET_OK;
+ default:
+ GNUNET_break_op (0);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "end-to-end message not known (%u)\n",
+ ntohs (msgh->type));
+ }
}
+
/******************************************************************************/
/******************************** API ***********************************/
/******************************************************************************/
+
/**
* Get channel ID.
*
}
+/**
+ * Get the channel tunnel.
+ *
+ * @param ch Channel to get the tunnel from.
+ *
+ * @return tunnel of the channel.
+ */
+struct MeshTunnel3 *
+GMCH_get_tunnel (const struct MeshChannel *ch)
+{
+ return ch->t;
+}
+
+
/**
* Get free buffer space towards the client on a specific channel.
*
GMCH_get_buffer (struct MeshChannel *ch, int fwd)
{
struct MeshChannelReliability *rel;
-
+
rel = fwd ? ch->dest_rel : ch->root_rel;
-
+
/* If rel is NULL it means that the end is not yet created,
* most probably is a loopback channel at the point of sending
* the ChannelCreate to itself.
*/
if (NULL == rel)
return 64;
-
+
return (64 - rel->n_recv);
}
+/**
+ * Get flow control status of end point: is client allow to send?
+ *
+ * @param ch Channel.
+ * @param fwd Is query about FWD traffic? (Request root status).
+ *
+ * @return #GNUNET_YES if client is allowed to send us data.
+ */
+int
+GMCH_get_allowed (struct MeshChannel *ch, int fwd)
+{
+ struct MeshChannelReliability *rel;
+
+ rel = fwd ? ch->root_rel : ch->dest_rel;
+
+ return rel->client_allowed;
+}
+
+
+/**
+ * Is the root client for this channel on this peer?
+ *
+ * @param ch Channel.
+ * @param fwd Is this for fwd traffic?
+ *
+ * @return #GNUNET_YES in case it is.
+ */
+int
+GMCH_is_origin (struct MeshChannel *ch, int fwd)
+{
+ struct MeshClient *c;
+
+ c = fwd ? ch->root : ch->dest;
+ return NULL != c;
+}
+
+
+/**
+ * Is the destination client for this channel on this peer?
+ *
+ * @param ch Channel.
+ * @param fwd Is this for fwd traffic?
+ *
+ * @return #GNUNET_YES in case it is.
+ */
+int
+GMCH_is_terminal (struct MeshChannel *ch, int fwd)
+{
+ struct MeshClient *c;
+
+ c = fwd ? ch->dest : ch->root;
+ return NULL != c;
+}
+
+
/**
* Notify the destination client that a new incoming channel was created.
*
void
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.
*
* @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;
+ struct GNUNET_MESH_ChannelManage msg;
- if (NULL == c)
- {
-// TODO: send on connection?
- return;
- }
+ msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_CHANNEL_DESTROY);
+ msg.header.size = htons (sizeof (msg));
+ msg.chid = htonl (ch->gid);
- GML_send_channel_destroy (c, id);
+ /* If root is not NULL, notify.
+ * If it's NULL, check lid_root. When a local destroy comes in, root
+ * is set to NULL but lid_root is left untouched. In this case, do nothing,
+ * the client is the one who reuqested the channel to be destroyed.
+ */
+ if (NULL != ch->root)
+ GML_send_channel_destroy (ch->root, ch->lid_root);
+ else if (0 == ch->lid_root)
+ GMCH_send_prebuilt_message (&msg.header, ch, GNUNET_NO);
+
+ if (NULL != ch->dest)
+ GML_send_channel_destroy (ch->dest, ch->lid_dest);
+ else if (0 == ch->lid_dest)
+ GMCH_send_prebuilt_message (&msg.header, ch, GNUNET_YES);
}
const struct GNUNET_MESH_Data *msg,
int fwd)
{
+ if (GMCH_is_terminal (ch, fwd))
+ {
+ GML_send_data (fwd ? ch->dest : ch->root,
+ msg,
+ fwd ? ch->lid_dest : ch->lid_root);
+ }
+ else
+ {
+ GMT_send_prebuilt_message (&msg->header, ch->t, ch, fwd);
+ }
}
* @param ch Channel this is about.
* @param fwd Is for FWD traffic? (ACK dest->owner)
*/
-static void
-GMCH_send_ack (struct MeshChannel *ch, int fwd)
+void
+GMCH_send_data_ack (struct MeshChannel *ch, int fwd)
{
struct GNUNET_MESH_DataACK msg;
struct MeshChannelReliability *rel;
}
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");
}
+/**
+ * Allow a client to send us more data, in case it was choked.
+ *
+ * @param ch Channel.
+ * @param fwd Is this about FWD traffic? (Root client).
+ */
+void
+GMCH_allow_client (struct MeshChannel *ch, int fwd)
+{
+ if (MESH_CHANNEL_READY != ch->state)
+ return;
+
+ send_client_ack (ch, fwd);
+}
+
+
/**
* Log channel info.
*
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);
}
+/**
+ * Handle an ACK given by a client.
+ *
+ * Mark client as ready and send him any buffered data we could have for him.
+ *
+ * @param ch Channel.
+ * @param fwd Is this a "FWD ACK"? (FWD ACKs are sent by dest and go BCK)
+ */
+void
+GMCH_handle_local_ack (struct MeshChannel *ch, int fwd)
+{
+ struct MeshChannelReliability *rel;
+ struct MeshClient *c;
+
+ rel = fwd ? ch->dest_rel : ch->root_rel;
+ c = fwd ? ch->dest : ch->root;
+
+ rel->client_ready = GNUNET_YES;
+ send_client_buffered_data (ch, c, fwd);
+ if (is_loopback (ch))
+ {
+ unsigned int buffer;
+
+ buffer = GMCH_get_buffer (ch, fwd);
+ if (0 < buffer)
+ GMCH_allow_client (ch, fwd);
+
+ return;
+ }
+ GMT_send_connection_acks (ch->t);
+}
+
+
+/**
+ * Handle data given by a client.
+ *
+ * Check whether the client is allowed to send in this tunnel, save if channel
+ * is reliable and send an ACK to the client if there is still buffer space
+ * in the tunnel.
+ *
+ * @param ch Channel.
+ * @param c Client which sent the data.
+ * @param message Message.
+ * @param fwd Is this a FWD data?
+ *
+ * @return GNUNET_OK if everything goes well, GNUNET_SYSERR in case of en error.
+ */
+int
+GMCH_handle_local_data (struct MeshChannel *ch,
+ struct MeshClient *c,
+ struct GNUNET_MessageHeader *message,
+ int fwd)
+{
+ struct MeshChannelReliability *rel;
+ struct GNUNET_MESH_Data *payload;
+ size_t size = ntohs (message->size);
+ uint16_t p2p_size = sizeof(struct GNUNET_MESH_Data) + size;
+ unsigned char cbuf[p2p_size];
+
+ /* Is the client in the channel? */
+ if ( !( (fwd &&
+ ch->root == c)
+ ||
+ (!fwd &&
+ ch->dest == c) ) )
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+
+ rel = fwd ? ch->root_rel : ch->dest_rel;
+
+ rel->client_allowed = GNUNET_NO;
+
+ /* Ok, everything is correct, send the message. */
+ payload = (struct GNUNET_MESH_Data *) cbuf;
+ payload->mid = htonl (rel->mid_send);
+ rel->mid_send++;
+ memcpy (&payload[1], message, size);
+ payload->header.size = htons (p2p_size);
+ payload->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_DATA);
+ payload->chid = htonl (ch->gid);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " sending on channel...\n");
+ if (GNUNET_YES == ch->reliable)
+ channel_save_copy (ch, &payload->header, fwd);
+ GMCH_send_prebuilt_message (&payload->header, ch, fwd);
+
+ if (is_loopback (ch))
+ {
+ if (GMCH_get_buffer (ch, fwd) > 0);
+ send_client_ack (ch, fwd);
+
+ return GNUNET_OK;
+ }
+
+ if (GMT_get_connections_buffer (ch->t) > 0)
+ {
+ send_client_ack (ch, fwd);
+ }
+
+ return GNUNET_OK;
+}
+
+
+/**
+ * Handle a channel destroy requested by a client.
+ *
+ * Destroy the channel and the tunnel in case this was the last channel.
+ *
+ * @param ch Channel.
+ * @param c Client that requested the destruction (to avoid notifying him).
+ */
+void
+GMCH_handle_local_destroy (struct MeshChannel *ch,
+ struct MeshClient *c)
+{
+ struct MeshTunnel3 *t;
+
+ /* Cleanup after the tunnel */
+ if (c == ch->dest)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " Client %s is destination.\n", GML_2s (c));
+ GML_client_delete_channel (c, ch, ch->lid_dest);
+ ch->dest = NULL;
+ }
+ if (c == ch->root)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " Client %s is owner.\n", GML_2s (c));
+ GML_client_delete_channel (c, ch, ch->lid_root);
+ ch->root = NULL;
+ }
+
+ t = ch->t;
+ GMCH_send_destroy (ch);
+ channel_destroy (ch);
+ GMT_destroy_if_empty (t);
+}
+
+
+/**
+ * Handle a channel create requested by a client.
+ *
+ * Create the channel and the tunnel in case this was the first0 channel.
+ *
+ * @param c Client that requested the creation (will be the root).
+ * @param msg Create Channel message.
+ *
+ * @return GNUNET_OK if everything went fine, GNUNET_SYSERR otherwise.
+ */
+int
+GMCH_handle_local_create (struct MeshClient *c,
+ struct GNUNET_MESH_ChannelMessage *msg)
+{
+ struct MeshChannel *ch;
+ struct MeshTunnel3 *t;
+ struct MeshPeer *peer;
+ MESH_ChannelNumber chid;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " towards %s:%u\n",
+ GNUNET_i2s (&msg->peer), ntohl (msg->port));
+ chid = ntohl (msg->channel_id);
+
+ /* Sanity check for duplicate channel IDs */
+ if (NULL != GML_channel_get (c, chid))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+
+ peer = GMP_get (&msg->peer);
+ GMP_add_tunnel (peer);
+ t = GMP_get_tunnel (peer);
+
+ if (GMP_get_short_id (peer) == myid)
+ {
+ GMT_change_state (t, MESH_TUNNEL3_READY);
+ }
+ else
+ {
+ GMP_connect (peer);
+ }
+
+ /* Create channel */
+ ch = channel_new (t, c, chid);
+ if (NULL == ch)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ ch->port = ntohl (msg->port);
+ channel_set_options (ch, ntohl (msg->opt));
+
+ /* In unreliable channels, we'll use the DLL to buffer BCK data */
+ ch->root_rel = GNUNET_new (struct MeshChannelReliability);
+ ch->root_rel->ch = ch;
+ ch->root_rel->expected_delay = MESH_RETRANSMIT_TIME;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "CREATED CHANNEL %s\n", GMCH_2s (ch));
+
+ /* Send create channel */
+ {
+ struct GNUNET_MESH_ChannelCreate msgcc;
+
+ msgcc.header.size = htons (sizeof (msgcc));
+ msgcc.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_CHANNEL_CREATE);
+ msgcc.chid = htonl (ch->gid);
+ msgcc.port = msg->port;
+ msgcc.opt = msg->opt;
+
+ GMT_send_prebuilt_message (&msgcc.header, t, ch, GNUNET_YES);
+ }
+ return GNUNET_OK;
+}
+
+
/**
* Handler for mesh network payload traffic.
*
* @param ch Channel for the message.
- * @param message Unencryted data message.
- * @param fwd Is this FWD traffic? GNUNET_YES : GNUNET_NO;
+ * @param msg Unencryted data message.
+ * @param fwd Is this message fwd? This only is meaningful in loopback channels.
+ * #GNUNET_YES if message is FWD on the respective channel (loopback)
+ * #GNUNET_NO if message is BCK on the respective channel (loopback)
+ * #GNUNET_SYSERR if message on a one-ended channel (remote)
*/
void
GMCH_handle_data (struct MeshChannel *ch,
struct MeshChannelReliability *rel;
struct MeshClient *c;
uint32_t mid;
- uint16_t type;
- size_t size;
+
+ /* If this is a remote (non-loopback) channel, find 'fwd'. */
+ if (GNUNET_SYSERR == fwd)
+ {
+ if (is_loopback (ch))
+ {
+ /* It is a loopback channel after all... */
+ GNUNET_break (0);
+ return;
+ }
+ fwd = (NULL != ch->dest) ? GNUNET_YES : GNUNET_NO;
+ }
/* Initialize FWD/BCK data */
c = fwd ? ch->dest : ch->root;
mid, rel->mid_recv, rel->mid_recv + 64);
}
- GMCH_send_ack (ch, fwd);
+ GMCH_send_data_ack (ch, fwd);
}
/**
* Handler for mesh network traffic end-to-end ACKs.
*
- * @param t Tunnel on which we got this message.
- * @param message Data message.
- * @param fwd Is this a fwd ACK? (dest->orig)
+ * @param ch Channel on which we got this message.
+ * @param msg Data message.
+ * @param fwd Is this message fwd? This only is meaningful in loopback channels.
+ * #GNUNET_YES if message is FWD on the respective channel (loopback)
+ * #GNUNET_NO if message is BCK on the respective channel (loopback)
+ * #GNUNET_SYSERR if message on a one-ended channel (remote)
*/
void
GMCH_handle_data_ack (struct MeshChannel *ch,
uint32_t ack;
int work;
+ /* If this is a remote (non-loopback) channel, find 'fwd'. */
+ if (GNUNET_SYSERR == fwd)
+ {
+ if (is_loopback (ch))
+ {
+ /* It is a loopback channel after all... */
+ GNUNET_break (0);
+ return;
+ }
+ fwd = (NULL != ch->dest) ? GNUNET_YES : GNUNET_NO;
+ }
+
ack = ntohl (msg->mid);
LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! %s ACK %u\n",
- (GNUNET_YES == fwd) ? "FWD" : "BCK", ack);
+ (GNUNET_YES == fwd) ? "FWD" : "BCK", ack);
if (GNUNET_YES == fwd)
{
/**
* 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;
+ * Does not have fwd parameter because it's always 'FWD': channel is incoming.
+ *
+ * @param t Tunnel this channel will be in.
+ * @param msg Channel crate message.
*/
struct MeshChannel *
-GMCH_handle_create (const struct GNUNET_MESH_ChannelCreate *msg,
- int fwd)
+GMCH_handle_create (struct MeshTunnel3 *t,
+ const struct GNUNET_MESH_ChannelCreate *msg)
{
MESH_ChannelNumber chid;
struct MeshChannel *ch;
struct MeshClient *c;
uint32_t port;
- /* Check if channel exists */
chid = ntohl (msg->chid);
- /* Create channel */
- ch = channel_new (NULL, NULL, 0); /* FIXME t */
- ch->gid = chid;
+ ch = GMT_get_channel (t, chid);
+ if (NULL == ch)
+ {
+ /* Create channel */
+ ch = channel_new (t, NULL, 0);
+ ch->gid = chid;
+ }
channel_set_options (ch, ntohl (msg->opt));
/* Find a destination client */
{
/* TODO send reject */
LOG (GNUNET_ERROR_TYPE_DEBUG, " no client has port registered\n");
- /* TODO free ch */
- return;
+ if (is_loopback (ch))
+ {
+ channel_send_nack (ch);
+ }
+ else
+ {
+ channel_send_nack (ch);
+ channel_destroy (ch);
+ }
+ return NULL;
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " client %p has port registered\n", c);
}
- channel_add_client (ch, c);
+ add_destination (ch, c);
if (GNUNET_YES == ch->reliable)
LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! Reliable\n");
+ else
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! Not Reliable\n");
GMCH_send_create (ch);
- GMCH_send_ack (ch, fwd);
- GML_send_ack (ch, !fwd);
+ channel_send_ack (ch, GNUNET_YES);
return ch;
}
+/**
+ * Handler for channel NACK messages.
+ *
+ * NACK messages always go dest -> root, no need for 'fwd' or 'msg' parameter.
+ *
+ * @param ch Channel.
+ */
+void
+GMCH_handle_nack (struct MeshChannel *ch)
+{
+ send_client_nack (ch);
+ channel_destroy (ch);
+}
+
+
/**
* Handler for channel ack messages.
*
* @param ch Channel.
* @param msg Message.
- * @param fwd Is this FWD traffic? GNUNET_YES : GNUNET_NO;
+ * @param fwd Is this message fwd? This only is meaningful in loopback channels.
+ * #GNUNET_YES if message is FWD on the respective channel (loopback)
+ * #GNUNET_NO if message is BCK on the respective channel (loopback)
+ * #GNUNET_SYSERR if message on a one-ended channel (remote)
*/
void
GMCH_handle_ack (struct MeshChannel *ch,
const struct GNUNET_MESH_ChannelManage *msg,
int fwd)
{
+ /* If this is a remote (non-loopback) channel, find 'fwd'. */
+ if (GNUNET_SYSERR == fwd)
+ {
+ if (is_loopback (ch))
+ {
+ /* It is a loopback channel after all... */
+ GNUNET_break (0);
+ return;
+ }
+ fwd = (NULL != ch->dest) ? GNUNET_YES : GNUNET_NO;
+ }
+
channel_confirm (ch, !fwd);
}
*
* @param ch Channel to be destroyed of.
* @param msg Message.
- * @param fwd Is this FWD traffic? GNUNET_YES : GNUNET_NO;
+ * @param fwd Is this message fwd? This only is meaningful in loopback channels.
+ * #GNUNET_YES if message is FWD on the respective channel (loopback)
+ * #GNUNET_NO if message is BCK on the respective channel (loopback)
+ * #GNUNET_SYSERR if message on a one-ended channel (remote)
*/
void
GMCH_handle_destroy (struct MeshChannel *ch,
const struct GNUNET_MESH_ChannelManage *msg,
int fwd)
{
- MESH_ChannelNumber chid;
+ struct MeshTunnel3 *t;
- /* Check if channel exists */
- chid = ntohl (msg->chid);
+ /* If this is a remote (non-loopback) channel, find 'fwd'. */
+ if (GNUNET_SYSERR == fwd)
+ {
+ if (is_loopback (ch))
+ {
+ /* It is a loopback channel after all... */
+ GNUNET_break (0);
+ return;
+ }
+ fwd = (NULL != ch->dest) ? GNUNET_YES : GNUNET_NO;
+ }
+
+ GMCH_debug (ch);
if ( (fwd && NULL == ch->dest) || (!fwd && NULL == ch->root) )
{
/* Not for us (don't destroy twice a half-open loopback channel) */
return;
}
- GMCH_send_destroy (ch, fwd);
+ t = ch->t;
+ GMCH_send_destroy (ch);
channel_destroy (ch);
+ GMT_destroy_if_empty (t);
}
/**
- * 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.
+ *
+ * If the channel is on a loopback tunnel, notifies the appropriate destination
+ * client locally.
+ *
+ * On a normal channel passes the message to the tunnel for encryption and
+ * sending on a connection.
+ *
+ * This function DOES NOT save the message for retransmission.
*
* @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");
- LOG (GNUNET_ERROR_TYPE_DEBUG, " %s\n",
- GNUNET_MESH_DEBUG_M2S (ntohs (message->type)));
-
- if (channel_is_terminal (ch, fwd) || ch->t->peer->id == myid)
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "GMCH Send %s %s on channel %s\n",
+ fwd ? "FWD" : "BCK", GNUNET_MESH_DEBUG_M2S (ntohs (message->type)),
+ GMCH_2s (ch));
+
+ if (GMT_is_loopback (ch->t))
{
- GMT_handle_decrypted (ch->t, message, fwd);
+ handle_loopback (ch, 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);
+}
+
+
+/**
+ * Get the static string for identification of the channel.
+ *
+ * @param ch Channel.
+ *
+ * @return Static string with the channel IDs.
+ */
+const char *
+GMCH_2s (const struct MeshChannel *ch)
+{
+ static char buf[64];
+
+ if (NULL == ch)
+ return "(NULL Channel)";
+
+ sprintf (buf, "%s:%X (%X / %X)",
+ GMT_2s (ch->t), ch->gid, ch->lid_root, ch->lid_dest);
+
+ return buf;
}