+/**
+ * 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_op (0);
+ return GNUNET_SYSERR;
+ }
+
+ rel = fwd ? ch->root_rel : ch->dest_rel;
+
+ if (GNUNET_NO == rel->client_allowed)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+
+ 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;
+}
+
+