Merge branch 'master' of ssh://gnunet.org/gnunet
[oweals/gnunet.git] / src / cadet / gnunet-service-cadet-new_channel.c
index f6ef50caa7067b017cf21321cf27e9191c6daa3e..8769601c201a4ddb6c8c4f4c9b3a0da44993fe31 100644 (file)
@@ -25,8 +25,6 @@
  *
  * TODO:
  * - Congestion/flow control:
- *   + calculate current RTT if possible, use that for initial retransmissions
- *     (NOTE: needs us to learn which connection the tunnel uses for the message!)
  *   + estimate max bandwidth using bursts and use to for CONGESTION CONTROL!
  *     (and figure out how/where to use this!)
  *   + figure out flow control without ACKs (unreliable traffic!)
@@ -78,7 +76,7 @@
 
 
 /**
- * All the states a connection can be in.
+ * All the states a channel can be in.
  */
 enum CadetChannelState
 {
@@ -88,7 +86,13 @@ enum CadetChannelState
   CADET_CHANNEL_NEW,
 
   /**
-   * Connection create message sent, waiting for ACK.
+   * Channel is to a port that is not open, we're waiting for the
+   * port to be opened.
+   */
+  CADET_CHANNEL_LOOSE,
+
+  /**
+   * CHANNEL_OPEN message sent, waiting for CHANNEL_OPEN_ACK.
    */
   CADET_CHANNEL_OPEN_SENT,
 
@@ -306,11 +310,6 @@ struct CadetChannel
    */
   struct GNUNET_TIME_Relative retry_time;
 
-  /**
-   * How long does it usually take to get an ACK.
-   */
-  struct GNUNET_TIME_Relative expected_delay;
-
   /**
    * Bitfield of already-received messages past @e mid_recv.
    */
@@ -573,6 +572,8 @@ send_channel_open (void *cls)
   msgcc.port = ch->port;
   msgcc.ctn = ch->ctn;
   ch->state = CADET_CHANNEL_OPEN_SENT;
+  if (NULL != ch->last_control_qe)
+    GCT_send_cancel (ch->last_control_qe);
   ch->last_control_qe = GCT_send (ch->t,
                                   &msgcc.header,
                                   &channel_open_sent_cb,
@@ -649,6 +650,7 @@ GCCH_channel_local_new (struct CadetClient *owner,
     if (NULL == c)
     {
       /* port closed, wait for it to possibly open */
+      ch->state = CADET_CHANNEL_LOOSE;
       (void) GNUNET_CONTAINER_multihashmap_put (loose_channels,
                                                 port,
                                                 ch,
@@ -659,11 +661,8 @@ GCCH_channel_local_new (struct CadetClient *owner,
     }
     else
     {
-      ch->dest = GNUNET_new (struct CadetChannelClient);
-      ch->dest->c = c;
-      ch->dest->client_ready = GNUNET_YES;
       GCCH_bind (ch,
-                 ch->dest->c);
+                 c);
     }
   }
   else
@@ -745,10 +744,12 @@ GCCH_channel_incoming_new (struct CadetTunnel *t,
   if (NULL == c)
   {
     /* port closed, wait for it to possibly open */
+    ch->state = CADET_CHANNEL_LOOSE;
     (void) GNUNET_CONTAINER_multihashmap_put (loose_channels,
                                               port,
                                               ch,
                                               GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
+    GNUNET_assert (NULL == ch->retry_control_task);
     ch->retry_control_task
       = GNUNET_SCHEDULER_add_delayed (TIMEOUT_CLOSED_PORT,
                                       &timeout_closed_cb,
@@ -808,13 +809,13 @@ send_channel_data_ack (struct CadetChannel *ch)
   msg.ctn = ch->ctn;
   msg.mid.mid = htonl (ntohl (ch->mid_recv.mid));
   msg.futures = GNUNET_htonll (ch->mid_futures);
-  if (NULL != ch->last_control_qe)
-    GCT_send_cancel (ch->last_control_qe);
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Sending DATA_ACK %u:%llX via %s\n",
        (unsigned int) ntohl (msg.mid.mid),
        (unsigned long long) ch->mid_futures,
        GCCH_2s (ch));
+  if (NULL != ch->last_control_qe)
+    GCT_send_cancel (ch->last_control_qe);
   ch->last_control_qe = GCT_send (ch->t,
                                   &msg.header,
                                   &send_ack_cb,
@@ -834,10 +835,10 @@ send_open_ack (void *cls)
   struct CadetChannel *ch = cls;
   struct GNUNET_CADET_ChannelManageMessage msg;
 
+  ch->retry_control_task = NULL;
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Sending CHANNEL_OPEN_ACK on %s\n",
        GCCH_2s (ch));
-  ch->retry_control_task = NULL;
   msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK);
   msg.header.size = htons (sizeof (msg));
   msg.reserved = htonl (0);
@@ -866,19 +867,19 @@ GCCH_handle_duplicate_open (struct CadetChannel *ch,
   if (NULL == ch->dest)
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Ignoring duplicate channel OPEN on %s: port is closed\n",
+         "Ignoring duplicate CHANNEL_OPEN on %s: port is closed\n",
          GCCH_2s (ch));
     return;
   }
   if (NULL != ch->retry_control_task)
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Ignoring duplicate channel OPEN on %s: control message is pending\n",
+         "Ignoring duplicate CHANNEL_OPEN on %s: control message is pending\n",
          GCCH_2s (ch));
     return;
   }
   LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Retransmitting OPEN_ACK on %s\n",
+       "Retransmitting CHANNEL_OPEN_ACK on %s\n",
        GCCH_2s (ch));
   ch->retry_control_task
     = GNUNET_SCHEDULER_add_now (&send_open_ack,
@@ -959,6 +960,7 @@ GCCH_bind (struct CadetChannel *ch,
   if (ch->out_of_order)
     options |= GNUNET_CADET_OPTION_OUT_OF_ORDER;
   cccd = GNUNET_new (struct CadetChannelClient);
+  GNUNET_assert (NULL == ch->dest);
   ch->dest = cccd;
   cccd->c = c;
   cccd->client_ready = GNUNET_YES;
@@ -982,6 +984,7 @@ GCCH_bind (struct CadetChannel *ch,
   else
   {
     /* notify other peer that we accepted the connection */
+    ch->state = CADET_CHANNEL_READY;
     ch->retry_control_task
       = GNUNET_SCHEDULER_add_now (&send_open_ack,
                                   ch);
@@ -995,6 +998,29 @@ GCCH_bind (struct CadetChannel *ch,
 }
 
 
+/**
+ * One of our clients has disconnected, tell the other one that we
+ * are finished. Done asynchronously to avoid concurrent modification
+ * issues if this is the same client.
+ *
+ * @param cls the `struct CadetChannel` where one of the ends is now dead
+ */
+static void
+signal_remote_destroy_cb (void *cls)
+{
+  struct CadetChannel *ch = cls;
+  struct CadetChannelClient *ccc;
+
+  /* Find which end is left... */
+  ch->retry_control_task = NULL;
+  ccc = (NULL != ch->owner) ? ch->owner : ch->dest;
+  GSC_handle_remote_channel_destroy (ccc->c,
+                                     ccc->ccn,
+                                     ch);
+  channel_destroy (ch);
+}
+
+
 /**
  * Destroy locally created channel.  Called by the local client, so no
  * need to tell the client.
@@ -1039,19 +1065,44 @@ GCCH_channel_local_destroy (struct CadetChannel *ch,
     channel_destroy (ch);
     return;
   }
-  if ( (NULL != ch->head_sent) ||
-       (NULL != ch->owner) ||
-       (NULL != ch->dest) )
+  if ( (NULL != ch->head_sent) &&
+       ( (NULL != ch->owner) ||
+         (NULL != ch->dest) ) )
   {
     /* Wait for other end to destroy us as well,
        and otherwise allow send queue to be transmitted first */
     ch->destroy = GNUNET_YES;
     return;
   }
-  /* If the we ever sent the CHANNEL_CREATE, we need to send a destroy message. */
-  if (CADET_CHANNEL_NEW != ch->state)
-    GCT_send_channel_destroy (ch->t,
-                              ch->ctn);
+  if ( (GNUNET_YES == ch->is_loopback) &&
+       ( (NULL != ch->owner) ||
+         (NULL != ch->dest) ) )
+  {
+    if (NULL != ch->retry_control_task)
+      GNUNET_SCHEDULER_cancel (ch->retry_control_task);
+    ch->retry_control_task
+      = GNUNET_SCHEDULER_add_now (&signal_remote_destroy_cb,
+                                  ch);
+    return;
+  }
+  if (GNUNET_NO == ch->is_loopback)
+  {
+    /* If the we ever sent the CHANNEL_CREATE, we need to send a destroy message. */
+    switch (ch->state)
+    {
+    case CADET_CHANNEL_NEW:
+      /* We gave up on a channel that we created as a client to a remote
+         target, but that never went anywhere. Nothing to do here. */
+      break;
+    case CADET_CHANNEL_LOOSE:
+      GSC_drop_loose_channel (&ch->port,
+                              ch);
+      break;
+    default:
+      GCT_send_channel_destroy (ch->t,
+                                ch->ctn);
+    }
+  }
   /* Nothing left to do, just finish destruction */
   channel_destroy (ch);
 }
@@ -1074,6 +1125,10 @@ GCCH_handle_channel_open_ack (struct CadetChannel *ch,
     /* this should be impossible */
     GNUNET_break (0);
     break;
+  case CADET_CHANNEL_LOOSE:
+    /* This makes no sense. */
+    GNUNET_break_op (0);
+    break;
   case CADET_CHANNEL_OPEN_SENT:
     if (NULL == ch->owner)
     {
@@ -1417,13 +1472,16 @@ handle_matching_ack (struct CadetChannel *ch,
     crm->qe = NULL;
   }
   if ( (1 == crm->num_transmissions) &&
-       (NULL != cti) &&
-       (0 == memcmp (cti,
-                     &crm->connection_taken,
-                     sizeof (struct GNUNET_CADET_ConnectionTunnelIdentifier))) )
+       (NULL != cti) )
   {
-    GCC_latency_observed (cti,
-                          GNUNET_TIME_absolute_get_duration (crm->first_transmission_time));
+    GCC_ack_observed (cti);
+    if (0 == memcmp (cti,
+                     &crm->connection_taken,
+                     sizeof (struct GNUNET_CADET_ConnectionTunnelIdentifier)))
+    {
+      GCC_latency_observed (cti,
+                            GNUNET_TIME_absolute_get_duration (crm->first_transmission_time));
+    }
   }
   GNUNET_free (crm->data_message);
   GNUNET_free (crm);
@@ -1560,7 +1618,8 @@ GCCH_handle_remote_destroy (struct CadetChannel *ch,
     return;
   }
   ccc = (NULL != ch->owner) ? ch->owner : ch->dest;
-  if (NULL != ccc->head_recv)
+  if ( (NULL != ccc) &&
+       (NULL != ccc->head_recv) )
   {
     LOG (GNUNET_ERROR_TYPE_WARNING,
          "Lost end of transmission due to remote shutdown on %s\n",
@@ -1568,9 +1627,10 @@ GCCH_handle_remote_destroy (struct CadetChannel *ch,
     /* FIXME: change API to notify client about truncated transmission! */
   }
   ch->destroy = GNUNET_YES;
-  GSC_handle_remote_channel_destroy (ccc->c,
-                                     ccc->ccn,
-                                     ch);
+  if (NULL != ccc)
+    GSC_handle_remote_channel_destroy (ccc->c,
+                                       ccc->ccn,
+                                       ch);
   channel_destroy (ch);
 }
 
@@ -1643,12 +1703,20 @@ data_sent_cb (void *cls,
     {
       crm->first_transmission_time = GNUNET_TIME_absolute_get ();
       crm->connection_taken = *cid;
+      GCC_ack_expected (cid);
     }
   }
-  if (0 == crm->retry_delay.rel_value_us)
-    crm->retry_delay = ch->expected_delay;
-  else
-    crm->retry_delay = GNUNET_TIME_STD_BACKOFF (crm->retry_delay);
+  if ( (0 == crm->retry_delay.rel_value_us) &&
+       (NULL != cid) )
+  {
+    struct CadetConnection *cc = GCC_lookup (cid);
+
+    if (NULL != cc)
+      crm->retry_delay = GCC_get_metrics (cc)->aged_latency;
+    else
+      crm->retry_delay = ch->retry_time;
+  }
+  crm->retry_delay = GNUNET_TIME_STD_BACKOFF (crm->retry_delay);
   crm->retry_delay = GNUNET_TIME_relative_max (crm->retry_delay,
                                                MIN_RTT_DELAY);
   crm->next_retry = GNUNET_TIME_relative_to_absolute (crm->retry_delay);
@@ -1704,6 +1772,11 @@ GCCH_handle_local_data (struct CadetChannel *ch,
     GNUNET_break (0);
     return GNUNET_SYSERR;
   }
+  if (GNUNET_YES == ch->destroy)
+  {
+    /* we are going down, drop messages */
+    return GNUNET_OK;
+  }
   ch->pending_messages++;
 
   if (GNUNET_YES == ch->is_loopback)
@@ -1711,23 +1784,29 @@ GCCH_handle_local_data (struct CadetChannel *ch,
     struct CadetChannelClient *receiver;
     struct GNUNET_MQ_Envelope *env;
     struct GNUNET_CADET_LocalData *ld;
-    int to_owner;
+    int ack_to_owner;
 
     env = GNUNET_MQ_msg_extra (ld,
                                buf_len,
                                GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA);
-    if (sender_ccn.channel_of_client ==
-        ch->owner->ccn.channel_of_client)
+    if ( (NULL != ch->owner) &&
+         (sender_ccn.channel_of_client ==
+          ch->owner->ccn.channel_of_client) )
     {
       receiver = ch->dest;
-      to_owner = GNUNET_NO;
+      ack_to_owner = GNUNET_YES;
     }
-    else
+    else if ( (NULL != ch->dest) &&
+              (sender_ccn.channel_of_client ==
+               ch->dest->ccn.channel_of_client) )
     {
-      GNUNET_assert (sender_ccn.channel_of_client ==
-                     ch->dest->ccn.channel_of_client);
       receiver = ch->owner;
-      to_owner = GNUNET_YES;
+      ack_to_owner = GNUNET_NO;
+    }
+    else
+    {
+      GNUNET_break (0);
+      return GNUNET_SYSERR;
     }
     ld->ccn = receiver->ccn;
     GNUNET_memcpy (&ld[1],
@@ -1735,10 +1814,11 @@ GCCH_handle_local_data (struct CadetChannel *ch,
                    buf_len);
     if (GNUNET_YES == receiver->client_ready)
     {
+      ch->pending_messages--;
       GSC_send_to_client (receiver->c,
                           env);
       send_ack_to_client (ch,
-                          to_owner);
+                          ack_to_owner);
     }
     else
     {