- doxygen
[oweals/gnunet.git] / src / mesh / gnunet-service-mesh_channel.c
index be4f7d0c071bdd751169fadbf5b9e84edd630fa3..d33425489ca591080d318d8d157bc06d39c7f837 100644 (file)
@@ -54,7 +54,7 @@ enum MeshChannelState
   MESH_CHANNEL_SENT,
 
   /**
-   * Connection confirmed, ready to carry traffic..
+   * Connection confirmed, ready to carry traffic.
    */
   MESH_CHANNEL_READY,
 };
@@ -143,6 +143,11 @@ struct MeshChannelReliability
      */
   int                               client_ready;
 
+  /**
+   * Can the client send data to us?
+   */
+  int                               client_allowed;
+
     /**
      * Task to resend/poll in case no ACK is received.
      */
@@ -325,6 +330,36 @@ add_buffered_data (const struct GNUNET_MESH_Data *msg,
     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.
@@ -359,32 +394,90 @@ send_client_data (struct MeshChannel *ch,
 
 
 /**
- * Add a client to a channel, initializing all needed data structures.
+ * Send a buffered message to the client, for in order delivery or
+ * as result of client ACK.
  *
- * @param ch Channel to which add the client.
- * @param c Client which to add to the channel.
+ * @param ch Channel on which to empty the message buffer.
+ * @param c Client to send to.
+ * @param fwd Is this to send FWD data?.
  */
-void
-GMCH_add_client (struct MeshChannel *ch, struct MeshClient *c)
+static void
+send_client_buffered_data (struct MeshChannel *ch,
+                           struct MeshClient *c,
+                           int fwd)
 {
-  if (NULL != ch->dest)
+  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 (0);
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "client not ready\n");
     return;
   }
 
-  /* Assign local id as destination */
-  ch->lid_dest = GML_get_next_chid (c);
+  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 *) &copy[1];
 
-  /* Store in client's hashmap */
-  GML_channel_add (c, ch->lid_dest, ch);
+      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");
+}
 
-  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;
+/**
+ * Allow a client to send more data.
+ *
+ * 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
+send_client_ack (struct MeshChannel *ch, int fwd)
+{
+  struct MeshChannelReliability *rel = fwd ? ch->root_rel : ch->dest_rel;
+
+  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;
+  }
+
+  if (GNUNET_YES == rel->client_allowed)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "  already allowed\n");
+    return;
+  }
+  rel->client_allowed = GNUNET_YES;
+
+  GML_send_ack (fwd ? ch->root : ch->dest, fwd ? ch->lid_root : ch->lid_dest);
 }
 
 
@@ -603,7 +696,7 @@ rel_message_free (struct MeshReliableMessage *copy)
  * Confirm we got a channel create.
  *
  * @param ch The channel to confirm.
- * @param fwd Should we send the ACK fwd?
+ * @param fwd Should we send a FWD ACK? (going dest->root)
  */
 static void
 channel_send_ack (struct MeshChannel *ch, int fwd)
@@ -625,7 +718,7 @@ channel_send_ack (struct MeshChannel *ch, int fwd)
  * 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)
@@ -640,6 +733,7 @@ channel_confirm (struct MeshChannel *ch, int fwd)
   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;
@@ -652,7 +746,11 @@ channel_confirm (struct MeshChannel *ch, int fwd)
       /* TODO return? */
     }
   }
-  channel_send_ack (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);
 }
 
 
@@ -704,63 +802,6 @@ channel_save_copy (struct MeshChannel *ch,
 }
 
 
-
-/**
- * Send a buffered message to the client, for in order delivery or
- * as result of client ACK.
- *
- * @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 void
-send_client_buffered_data (struct MeshChannel *ch,
-                           struct MeshClient *c,
-                           int fwd)
-{
-  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)
-  {
-    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 *) &copy[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.
  *
@@ -811,7 +852,8 @@ channel_destroy (struct MeshChannel *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;
 
@@ -865,8 +907,8 @@ handle_loopback (struct MeshChannel *ch,
 
   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)
   {
@@ -880,8 +922,8 @@ handle_loopback (struct MeshChannel *ch,
       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;
 
@@ -911,6 +953,7 @@ handle_loopback (struct MeshChannel *ch,
 /********************************    API    ***********************************/
 /******************************************************************************/
 
+
 /**
  * Get channel ID.
  *
@@ -965,6 +1008,25 @@ GMCH_get_buffer (struct MeshChannel *ch, int fwd)
 }
 
 
+/**
+ * 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?
  *
@@ -1024,18 +1086,32 @@ GMCH_send_create (struct MeshChannel *ch)
 
 /**
  * Notify a client that the channel is no longer valid.
- * FIXME send on tunnel if some client == NULL?
  *
  * @param ch Channel that is destroyed.
  */
 void
 GMCH_send_destroy (struct MeshChannel *ch)
 {
+  struct GNUNET_MESH_ChannelManage msg;
+
+  msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_CHANNEL_DESTROY);
+  msg.header.size = htons (sizeof (msg));
+  msg.chid = htonl (ch->gid);
+
+  /* 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);
 }
 
 
@@ -1120,6 +1196,22 @@ GMCH_send_data_ack (struct MeshChannel *ch, int fwd)
 }
 
 
+/**
+ * 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.
  *
@@ -1175,7 +1267,7 @@ GMCH_handle_local_ack (struct MeshChannel *ch, int fwd)
 
   rel->client_ready = GNUNET_YES;
   send_client_buffered_data (ch, c, fwd);
-  GMC_send_ack (NULL, ch, fwd);
+  GMT_send_acks (ch->t, fwd);
 }
 
 
@@ -1187,6 +1279,8 @@ GMCH_handle_local_ack (struct MeshChannel *ch, int fwd)
  * 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.
@@ -1216,6 +1310,8 @@ GMCH_handle_local_data (struct MeshChannel *ch,
 
   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);
@@ -1225,12 +1321,14 @@ GMCH_handle_local_data (struct MeshChannel *ch,
   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);
+  GMCH_send_prebuilt_message (&payload->header, ch, fwd);
+
   if (GMT_get_buffer (ch->t, fwd) > 0)
-    GML_send_ack (c, fwd ? ch->lid_root : ch->lid_dest);
+  {
+    send_client_ack (ch, fwd);
+  }
 
   return GNUNET_OK;
 }
@@ -1329,8 +1427,7 @@ GMCH_handle_local_create (struct MeshClient *c,
   ch->root_rel->ch = ch;
   ch->root_rel->expected_delay = MESH_RETRANSMIT_TIME;
 
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "CREATED CHANNEL %s[%x]:%u (%x)\n",
-       GMT_2s (t), ch->gid, ch->port, ch->lid_root);
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "CREATED CHANNEL %s\n", GMCH_2s (ch));
 
   /* Send create channel */
   {
@@ -1351,7 +1448,7 @@ GMCH_handle_local_create (struct MeshClient *c,
  * Handler for mesh network payload traffic.
  *
  * @param ch Channel for the message.
- * @param message Unencryted data message.
+ * @param msg Unencryted data message.
  * @param fwd Is this FWD traffic? GNUNET_YES : GNUNET_NO;
  */
 void
@@ -1422,7 +1519,7 @@ GMCH_handle_data (struct MeshChannel *ch,
  * Handler for mesh network traffic end-to-end ACKs.
  *
  * @param t Tunnel on which we got this message.
- * @param message Data message.
+ * @param msg Data message.
  * @param fwd Is this a fwd ACK? (dest->orig)
  */
 void
@@ -1505,11 +1602,13 @@ GMCH_handle_data_ack (struct MeshChannel *ch,
 /**
  * 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;
@@ -1519,9 +1618,13 @@ GMCH_handle_create (const struct GNUNET_MESH_ChannelCreate *msg,
 
   chid = ntohl (msg->chid);
 
-  /* Create channel */
-  ch = channel_new (NULL, NULL, 0); /* FIXME pass 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 */
@@ -1535,20 +1638,19 @@ GMCH_handle_create (const struct GNUNET_MESH_ChannelCreate *msg,
     channel_destroy (ch);
     return NULL;
   }
+  else
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "  client %p has port registered\n", c);
+  }
 
-  GMCH_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_data_ack (ch, fwd);
-  channel_send_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;
-  }
+  channel_send_ack (ch, fwd);
 
   return ch;
 }
@@ -1617,10 +1719,9 @@ void
 GMCH_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
                             struct MeshChannel *ch, int fwd)
 {
-  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, "  %s\n",
-       GNUNET_MESH_DEBUG_M2S (ntohs (message->type)));
+  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))
   {