- fix #3091
[oweals/gnunet.git] / src / mesh / gnunet-service-mesh_channel.c
index 0c672a091961e8f6e339595086d6eab508f69fa4..e7fc0323b9a1ed3e5956c154ee3c5b2151ce2902 100644 (file)
@@ -481,6 +481,23 @@ send_client_ack (struct MeshChannel *ch, int fwd)
 }
 
 
+/**
+ * Notify the root that the destination rejected the channel.
+ *
+ * @param ch Rejected channel.
+ */
+static void
+send_client_nack (struct MeshChannel *ch)
+{
+  if (NULL == ch->root)
+  {
+    GNUNET_break (0);
+    return;
+  }
+  GML_send_nack (ch->root, ch->lid_root);
+}
+
+
 /**
  * Destroy all reliable messages queued for a channel,
  * during a channel destruction.
@@ -714,6 +731,27 @@ channel_send_ack (struct MeshChannel *ch, int 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.
  *
@@ -890,6 +928,15 @@ channel_set_options (struct MeshChannel *ch, uint32_t options)
                  GNUNET_YES : GNUNET_NO;
 }
 
+static int
+is_loopback (const struct MeshChannel *ch)
+{
+  if (NULL != ch->t)
+    return GMT_is_loopback (ch->t);
+
+  return (NULL != ch->root && NULL != ch->dest);
+}
+
 
 /**
  * Handle a loopback message: call the appropriate handler for the message type.
@@ -932,6 +979,10 @@ handle_loopback (struct MeshChannel *ch,
                        fwd);
       break;
 
+    case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_NACK:
+      GMCH_handle_nack (ch);
+      break;
+
     case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_DESTROY:
       GMCH_handle_destroy (ch,
                            (struct GNUNET_MESH_ChannelManage *) msgh,
@@ -1253,7 +1304,7 @@ GMCH_debug (struct MeshChannel *ch)
  * 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)
+ * @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)
@@ -1266,7 +1317,17 @@ GMCH_handle_local_ack (struct MeshChannel *ch, int fwd)
 
   rel->client_ready = GNUNET_YES;
   send_client_buffered_data (ch, c, fwd);
-  GMT_send_acks (ch->t, 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);
 }
 
 
@@ -1324,7 +1385,15 @@ GMCH_handle_local_data (struct MeshChannel *ch,
     channel_save_copy (ch, &payload->header, fwd);
   GMCH_send_prebuilt_message (&payload->header, ch, fwd);
 
-  if (GMT_get_buffer (ch->t, fwd) > 0)
+  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);
   }
@@ -1466,7 +1535,7 @@ GMCH_handle_data (struct MeshChannel *ch,
   /* If this is a remote (non-loopback) channel, find 'fwd'. */
   if (GNUNET_SYSERR == fwd)
   {
-    if (NULL != ch->dest && NULL != ch->root)
+    if (is_loopback (ch))
     {
       /* It is a loopback channel after all... */
       GNUNET_break (0);
@@ -1554,7 +1623,7 @@ GMCH_handle_data_ack (struct MeshChannel *ch,
   /* If this is a remote (non-loopback) channel, find 'fwd'. */
   if (GNUNET_SYSERR == fwd)
   {
-    if (NULL != ch->dest && NULL != ch->root)
+    if (is_loopback (ch))
     {
       /* It is a loopback channel after all... */
       GNUNET_break (0);
@@ -1665,7 +1734,15 @@ GMCH_handle_create (struct MeshTunnel3 *t,
   {
     /* TODO send reject */
     LOG (GNUNET_ERROR_TYPE_DEBUG, "  no client has port registered\n");
-    channel_destroy (ch);
+    if (is_loopback (ch))
+    {
+      channel_send_nack (ch);
+    }
+    else
+    {
+      channel_send_nack (ch);
+      channel_destroy (ch);
+    }
     return NULL;
   }
   else
@@ -1686,6 +1763,21 @@ GMCH_handle_create (struct MeshTunnel3 *t,
 }
 
 
+/**
+ * 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.
  *
@@ -1704,7 +1796,7 @@ GMCH_handle_ack (struct MeshChannel *ch,
   /* If this is a remote (non-loopback) channel, find 'fwd'. */
   if (GNUNET_SYSERR == fwd)
   {
-    if (NULL != ch->dest && NULL != ch->root)
+    if (is_loopback (ch))
     {
       /* It is a loopback channel after all... */
       GNUNET_break (0);
@@ -1737,7 +1829,7 @@ GMCH_handle_destroy (struct MeshChannel *ch,
   /* If this is a remote (non-loopback) channel, find 'fwd'. */
   if (GNUNET_SYSERR == fwd)
   {
-    if (NULL != ch->dest && NULL != ch->root)
+    if (is_loopback (ch))
     {
       /* It is a loopback channel after all... */
       GNUNET_break (0);