#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__)
*/
extern struct GNUNET_STATISTICS_Handle *stats;
+/**
+ * Local peer own ID (memory efficient handle).
+ */
+extern GNUNET_PEER_Id myid;
+
/******************************************************************************/
/******************************** STATIC ***********************************/
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);
}
void
GMCH_add_client (struct MeshChannel *ch, struct MeshClient *c)
{
- struct MeshTunnel3 *t = ch->t;
-
if (NULL != ch->dest)
{
GNUNET_break (0);
{
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;
* is stalled.
*/
// FIXME access to queue elements is limited
-// payload = (struct GNUNET_MESH_Data *) ©[1];
-// fwd = (rel == ch->root_rel);
+ payload = (struct GNUNET_MESH_Data *) ©[1];
+ fwd = (rel == ch->root_rel);
// c = GMT_get_connection (ch->t, fwd);
// hop = connection_get_hop (c, fwd);
// for (q = hop->queue_head; NULL != q; q = q->next)
}
+/**
+ * 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);
+}
+
/**
* Channel was ACK'd by remote peer, mark as ready and cancel retransmission.
/* TODO return? */
}
}
- send_ack (NULL, ch, fwd);
+
+ /* In case of a FWD ACk (SYNACK) send a BCK ACK (ACK). */
+ if (fwd)
+ channel_send_ack (ch, !fwd);
}
*
* @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 fwd Is this to send FWD data?.
*/
static void
send_client_buffered_data (struct MeshChannel *ch,
- struct MeshClient *c,
- int fwd)
+ struct MeshClient *c,
+ int fwd)
{
struct MeshReliableMessage *copy;
struct MeshChannelReliability *rel;
*/
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;
}
-
-/**
- * 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)
-{
- 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:%X\n",
- fwd ? "FWD" : "BCK", GMT_2s (ch->t),
- ch->gid);
-
- msg.chid = htonl (ch->gid);
- GMCH_send_prebuilt_message (&msg.header, ch, !fwd);
-}
-
-
-/**
- * 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;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- " 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 %s is destination.\n", GML_2s (c));
- }
- if (c == ch->root)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " Client %s is owner.\n", GML_2s (c));
- }
-
- t = ch->t;
- GMCH_send_destroy (ch);
- channel_destroy (ch);
- GMT_destroy_if_empty (t);
-
- return GNUNET_OK;
-}
-
-
/**
* Handle a loopback message: call the appropriate handler for the message type.
*
*/
void
handle_loopback (struct MeshChannel *ch,
- struct GNUNET_MessageHeader *msgh,
+ const 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));
+ "Loopback %s %s message!\n",
+ fwd ? "FWD" : "BCK", GNUNET_MESH_DEBUG_M2S (type));
switch (type)
{
break;
case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_CREATE:
- // FIXME store channel in loopback tunnel?
- GMCH_handle_create ((struct GNUNET_MESH_ChannelCreate *) msgh,
+ GMCH_handle_create (ch->t,
+ (struct GNUNET_MESH_ChannelCreate *) msgh,
fwd);
break;
void
GMCH_send_create (struct MeshChannel *ch)
{
- struct GNUNET_MESH_ChannelMessage msg;
uint32_t opt;
if (NULL == ch->dest)
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 fwd Is for FWD traffic? (ACK dest->owner)
*/
void
-GMCH_send_ack (struct MeshChannel *ch, int fwd)
+GMCH_send_data_ack (struct MeshChannel *ch, int fwd)
{
struct GNUNET_MESH_DataACK msg;
struct MeshChannelReliability *rel;
}
+/**
+ * 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 root 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);
+ GMC_send_ack (NULL, ch, fwd);
+}
+
+
+/**
+ * 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 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;
+
+ /* 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");
+ GMCH_send_prebuilt_message (&payload->header, ch, fwd);
+
+ if (GNUNET_YES == ch->reliable)
+ channel_save_copy (ch, &payload->header, fwd);
+ if (GMT_get_buffer (ch->t, fwd) > 0)
+ GML_send_ack (c, fwd ? ch->lid_root : ch->lid_dest);
+
+ 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_queue_data (t, ch, &msgcc.header, GNUNET_YES);
+ }
+ return GNUNET_OK;
+}
+
/**
* Handler for mesh network payload traffic.
*
struct MeshChannelReliability *rel;
struct MeshClient *c;
uint32_t mid;
- uint16_t type;
- size_t size;
/* 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 channel create messages.
*
+ * @param t Tunnel this channel will be in.
* @param msg Message.
* @param fwd Is this FWD traffic? GNUNET_YES : GNUNET_NO;
*/
struct MeshChannel *
-GMCH_handle_create (const struct GNUNET_MESH_ChannelCreate *msg,
+GMCH_handle_create (struct MeshTunnel3 *t,
+ const struct GNUNET_MESH_ChannelCreate *msg,
int fwd)
{
MESH_ChannelNumber chid;
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;
+ channel_destroy (ch);
+ return NULL;
}
- channel_add_client (ch, c);
+ GMCH_add_client (ch, c);
if (GNUNET_YES == ch->reliable)
LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! Reliable\n");
GMCH_send_create (ch);
- GMCH_send_ack (ch, fwd);
- GML_send_ack (ch, !fwd);
+ channel_send_ack (ch, fwd);
+ GMCH_send_data_ack (ch, fwd);
+
+ if (GNUNET_NO == ch->dest_rel->client_ready)
+ {
+ GML_send_ack (ch->dest, ch->lid_dest);
+ ch->dest_rel->client_ready = GNUNET_YES;
+ }
return ch;
}
const struct GNUNET_MESH_ChannelManage *msg,
int fwd)
{
- MESH_ChannelNumber chid;
+ struct MeshTunnel3 *t;
- /* Check if channel exists */
- chid = ntohl (msg->chid);
+ 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;
}
+ t = ch->t;
GMCH_send_destroy (ch);
channel_destroy (ch);
+ GMT_destroy_if_empty (t);
}
/**
* 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.
* @param fwd Is this a fwd message?
GMCH_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
struct MeshChannel *ch, int fwd)
{
- size_t size = ntohs (message->size);
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Send on Channel %s:%X %s\n",
- GMT_2s (ch->t), ch->gid, fwd ? "FWD" : "BCK");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Send %s on channel %s\n",
+ fwd ? "FWD" : "BCK", GMCH_2s (ch));
LOG (GNUNET_ERROR_TYPE_DEBUG, " %s\n",
GNUNET_MESH_DEBUG_M2S (ntohs (message->type)));
if (GMT_is_loopback (ch->t))
{
- handle_loopback (ch->t, message, fwd);
+ handle_loopback (ch, message, fwd);
return;
}
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;
+}