implement keepalives
authorChristian Grothoff <christian@grothoff.org>
Wed, 25 Jan 2017 20:02:11 +0000 (21:02 +0100)
committerChristian Grothoff <christian@grothoff.org>
Wed, 25 Jan 2017 20:02:11 +0000 (21:02 +0100)
src/cadet/gnunet-service-cadet-new.c
src/cadet/gnunet-service-cadet-new_channel.c
src/cadet/gnunet-service-cadet-new_connection.c
src/cadet/gnunet-service-cadet-new_tunnels.c
src/cadet/test_cadet.c

index af5ac13aea0b681ce320aff0328174190d01c9a7..f24c9f5185b8be80c95cf93650714f76762cadc6 100644 (file)
@@ -1343,7 +1343,7 @@ run (void *cls,
   if (GNUNET_OK !=
       GNUNET_CONFIGURATION_get_value_time (c,
                                            "CADET",
-                                           "REFRESHC_CONNECTION_TIME",
+                                           "REFRESH_CONNECTION_TIME",
                                            &keepalive_period))
   {
     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
index 83911f530c61a40605d898a8edc11de3d9257e77..e55a9a77db4fa81ab9cd79667e5c8c72752a5452 100644 (file)
  *
  * TODO:
  * - Optimize ACKs by using 'mid_futures' properly!
+ * - calculate current RTT if possible, use that for initial retransmissions
+ *   (NOTE: needs us to learn which connection the tunnel uses for the message!)
  * - introduce shutdown so we can have half-closed channels, modify
  *   destroy to include MID to have FIN-ACK equivalents, etc.
  * - estimate max bandwidth using bursts and use to for CONGESTION CONTROL!
+ *   (and figure out how/where to use this!)
  * - check that '0xFFULL' really is sufficient for flow control!
+ *   (this is right now a big HACK!)
  * - revisit handling of 'unreliable' traffic!
+ *   (has not seen enough review)
+ * - revisit handling of 'unbuffered' traffic!
+ *   (has not seen enough review)
  * - revisit handling of 'out-of-order' option, especially in combination with/without 'reliable'.
  * - figure out flow control without ACKs (unreliable traffic!)
  */
index 60389008cd26955d7d34904a55b4927d010ef0b1..58922bc1e277333ed601867c1026733524aa9ac4 100644 (file)
  * @author Christian Grothoff
  *
  * TODO:
- * - Optimization: keepalive messages / timeout (timeout to be done @ peer level!)
+ * - Implement: keepalive messages / timeout (timeout to be done @ peer level!)
  * - Optimization: keep performance metrics (?)
  */
 #include "platform.h"
+#include "gnunet-service-cadet-new.h"
 #include "gnunet-service-cadet-new_channel.h"
 #include "gnunet-service-cadet-new_connection.h"
 #include "gnunet-service-cadet-new_paths.h"
 #include "gnunet-service-cadet-new_peer.h"
 #include "gnunet-service-cadet-new_tunnels.h"
 #include "gnunet_cadet_service.h"
+#include "gnunet_statistics_service.h"
 #include "cadet_protocol.h"
 
 
@@ -118,6 +120,11 @@ struct CadetConnection
    */
   struct GNUNET_SCHEDULER_Task *task;
 
+  /**
+   * Queue entry for keepalive messages.
+   */
+  struct CadetTunnelQueueEntry *keepalive_qe;
+
   /**
    * Function to call once we are ready to transmit.
    */
@@ -184,6 +191,11 @@ GCC_destroy (struct CadetConnection *cc)
     GNUNET_SCHEDULER_cancel (cc->task);
     cc->task = NULL;
   }
+  if (NULL != cc->keepalive_qe)
+  {
+    GCT_send_cancel (cc->keepalive_qe);
+    cc->keepalive_qe = NULL;
+  }
   GCPP_del_connection (cc->path,
                        cc->off,
                        cc);
@@ -209,7 +221,72 @@ GCC_get_ct (struct CadetConnection *cc)
 
 
 /**
- * A CADET_CONNECTION_ACK was received for this connection, implying
+ * Send a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE through the
+ * tunnel to prevent it from timing out.
+ *
+ * @param cls the `struct CadetConnection` to keep alive.
+ */
+static void
+send_keepalive (void *cls);
+
+
+/**
+ * Keepalive was transmitted.  Remember this, and possibly
+ * schedule the next one.
+ *
+ * @param cls the `struct CadetConnection` to keep alive.
+ */
+static void
+keepalive_done (void *cls)
+{
+  struct CadetConnection *cc = cls;
+
+  cc->keepalive_qe = NULL;
+  if ( (GNUNET_YES == cc->mqm_ready) &&
+       (NULL == cc->task) )
+    cc->task = GNUNET_SCHEDULER_add_delayed (keepalive_period,
+                                             &send_keepalive,
+                                             cc);
+}
+
+
+/**
+ * Send a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE through the
+ * tunnel to prevent it from timing out.
+ *
+ * @param cls the `struct CadetConnection` to keep alive.
+ */
+static void
+send_keepalive (void *cls)
+{
+  struct CadetConnection *cc = cls;
+  struct GNUNET_MessageHeader msg;
+
+  cc->task = NULL;
+  GNUNET_assert (NULL != cc->ct);
+  GNUNET_assert (GNUNET_YES == cc->mqm_ready);
+  GNUNET_assert (NULL == cc->keepalive_qe);
+  LOG (GNUNET_ERROR_TYPE_INFO,
+       "Sending KEEPALIVE on behalf of %s via %s\n",
+       GCC_2s (cc),
+       GCT_2s (cc->ct->t));
+  GNUNET_STATISTICS_update (stats,
+                            "# keepalives sent",
+                            1,
+                            GNUNET_NO);
+  msg.size = htons (sizeof (msg));
+  msg.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE);
+
+  cc->keepalive_qe
+    = GCT_send (cc->ct->t,
+                &msg,
+                &keepalive_done,
+                cc);
+}
+
+
+/**
+ * A #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK was received for this connection, implying
  * that the end-to-end connection is up.  Process it.
  *
  * @param cc the connection that got the ACK.
@@ -227,15 +304,18 @@ GCC_handle_connection_create_ack (struct CadetConnection *cc)
     GNUNET_SCHEDULER_cancel (cc->task);
     cc->task = NULL;
   }
-#if FIXME_KEEPALIVE
-  cc->task = GNUNET_SCHEDULER_add_delayed (cc->keepalive_period,
-                                           &send_keepalive,
-                                           cc);
-#endif
   cc->state = CADET_CONNECTION_READY;
   if (GNUNET_YES == cc->mqm_ready)
+  {
     cc->ready_cb (cc->ready_cb_cls,
                   GNUNET_YES);
+    if ( (NULL == cc->keepalive_qe) &&
+         (GNUNET_YES == cc->mqm_ready) &&
+         (NULL == cc->task) )
+      cc->task = GNUNET_SCHEDULER_add_delayed (keepalive_period,
+                                               &send_keepalive,
+                                               cc);
+  }
 }
 
 
@@ -288,7 +368,8 @@ GCC_handle_encrypted (struct CadetConnection *cc,
 
 
 /**
- * Send a CREATE message to the first hop.
+ * Send a #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE message to the
+ * first hop.
  *
  * @param cls the `struct CadetConnection` to initiate
  */
@@ -459,6 +540,19 @@ manage_first_hop_mq (void *cls,
   case CADET_CONNECTION_READY:
     cc->ready_cb (cc->ready_cb_cls,
                   GNUNET_YES);
+    if ( (NULL == cc->keepalive_qe) &&
+         (GNUNET_YES == cc->mqm_ready) &&
+         (NULL == cc->task) )
+    {
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "Scheduling keepalive for %s in %s\n",
+           GCC_2s (cc),
+           GNUNET_STRINGS_relative_time_to_string (keepalive_period,
+                                                   GNUNET_YES));
+      cc->task = GNUNET_SCHEDULER_add_delayed (keepalive_period,
+                                               &send_keepalive,
+                                               cc);
+    }
     break;
   }
 }
@@ -610,6 +704,11 @@ GCC_transmit (struct CadetConnection *cc,
   GNUNET_assert (GNUNET_YES == cc->mqm_ready);
   GNUNET_assert (CADET_CONNECTION_READY == cc->state);
   cc->mqm_ready = GNUNET_NO;
+  if (NULL != cc->task)
+  {
+    GNUNET_SCHEDULER_cancel (cc->task);
+    cc->task = NULL;
+  }
   GCP_send (cc->mq_man,
             env);
 }
index 3420c00dbb9b766d109348edbc7655534f001d41..03067a605279079c79bd7c491dfa9b04028ff896 100644 (file)
@@ -1963,7 +1963,7 @@ GCT_consider_path (struct CadetTunnel *t,
 
 
 /**
- * NOT IMPLEMENTED.
+ * We got a keepalive. Track in statistics.
  *
  * @param cls the `struct CadetTunnel` for which we decrypted the message
  * @param msg  the message we received on the tunnel
@@ -1974,7 +1974,13 @@ handle_plaintext_keepalive (void *cls,
 {
   struct CadetTunnel *t = cls;
 
-  GNUNET_break (0); // FIXME
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Received KEEPALIVE on tunnel %s\n",
+       GCT_2s (t));
+  GNUNET_STATISTICS_update (stats,
+                            "# keepalives received",
+                            1,
+                            GNUNET_NO);
 }
 
 
index df279d72adef71a84e5d5d1107a0a29e95c2af9c..efc4f96b30e33547162873bbc4349521226b9a92 100644 (file)
@@ -345,15 +345,21 @@ shutdown_task (void *cls)
  *          operation has executed successfully.
  */
 static void
-stats_cont (void *cls, struct GNUNET_TESTBED_Operation *op, const char *emsg)
+stats_cont (void *cls,
+            struct GNUNET_TESTBED_Operation *op,
+            const char *emsg)
 {
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
               " KA sent: %u, KA received: %u\n",
-              ka_sent, ka_received);
+              ka_sent,
+              ka_received);
   if ( (KEEPALIVE == test) &&
        ( (ka_sent < 2) ||
          (ka_sent > ka_received + 1)) )
+  {
+    GNUNET_break (0);
     ok--;
+  }
   GNUNET_TESTBED_operation_done (stats_op);
 
   if (NULL != disconnect_task)