implement random packet drop option, fix retransmission logic
authorChristian Grothoff <christian@grothoff.org>
Thu, 26 Jan 2017 17:34:29 +0000 (18:34 +0100)
committerChristian Grothoff <christian@grothoff.org>
Thu, 26 Jan 2017 17:34:29 +0000 (18:34 +0100)
src/cadet/gnunet-service-cadet-new.c
src/cadet/gnunet-service-cadet-new.h
src/cadet/gnunet-service-cadet-new_channel.c
src/cadet/gnunet-service-cadet-new_peer.c
src/cadet/gnunet-service-cadet-new_tunnels.c

index f24c9f5185b8be80c95cf93650714f76762cadc6..d40d4f10e8deabc40911e2d72e1062ab869f3ab1 100644 (file)
@@ -188,6 +188,11 @@ struct GNUNET_TIME_Relative ratchet_time;
  */
 struct GNUNET_TIME_Relative keepalive_period;
 
+/**
+ * Set to non-zero values to create random drops to test retransmissions.
+ */
+unsigned long long drop_percent;
+
 
 /**
  * Send a message to a client.
@@ -1352,7 +1357,22 @@ run (void *cls,
                                "need delay value");
     keepalive_period = GNUNET_TIME_UNIT_MINUTES;
   }
-
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_number (c,
+                                             "CADET",
+                                             "DROP_PERCENT",
+                                             &drop_percent))
+  {
+    drop_percent = 0;
+  }
+  else
+  {
+    LOG (GNUNET_ERROR_TYPE_WARNING, "**************************************\n");
+    LOG (GNUNET_ERROR_TYPE_WARNING, "Cadet is running with DROP enabled.\n");
+    LOG (GNUNET_ERROR_TYPE_WARNING, "This is NOT a good idea!\n");
+    LOG (GNUNET_ERROR_TYPE_WARNING, "Remove DROP_PERCENT from config file.\n");
+    LOG (GNUNET_ERROR_TYPE_WARNING, "**************************************\n");
+  }
   my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (c);
   if (NULL == my_private_key)
   {
index 721044ac425dc0e67d5f64d9fdc98e59cae8d40c..dff0d3c8c0c9368e735abb8d97d78000731e6aa8 100644 (file)
@@ -235,6 +235,11 @@ extern struct GNUNET_TIME_Relative keepalive_period;
  */
 extern int shutting_down;
 
+/**
+ * Set to non-zero values to create random drops to test retransmissions.
+ */
+extern unsigned long long drop_percent;
+
 
 /**
  * Send a message to a client.
index e55a9a77db4fa81ab9cd79667e5c8c72752a5452..a923f19dce778099f518faace365b6564de8616a 100644 (file)
@@ -1190,6 +1190,8 @@ GCCH_handle_channel_plaintext_data (struct CadetChannel *ch,
                               1,
                               GNUNET_NO);
     GNUNET_MQ_discard (env);
+    if (GNUNET_YES == ch->reliable)
+      send_channel_data_ack (ch);
     return;
   }
 
@@ -1348,16 +1350,38 @@ GCCH_handle_channel_plaintext_data_ack (struct CadetChannel *ch,
     crmn = crm->next;
     if (ack->mid.mid == crm->data_message->mid.mid)
     {
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "Got DATA_ACK with base %u matching message %u on %s\n",
+           (unsigned int) mid_base,
+           ntohl (crm->data_message->mid.mid),
+           GCCH_2s (ch));
       handle_matching_ack (ch,
                            crm);
       found = GNUNET_YES;
       continue;
     }
     delta = (unsigned int) (ntohl (crm->data_message->mid.mid) - mid_base) - 1;
+    if (delta >= UINT_MAX - ch->max_pending_messages)
+    {
+      /* overflow, means crm was way in the past, so this ACK counts for it. */
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "Got DATA_ACK with base %u past %u on %s\n",
+           (unsigned int) mid_base,
+           ntohl (crm->data_message->mid.mid),
+           GCCH_2s (ch));
+      handle_matching_ack (ch,
+                           crm);
+      found = GNUNET_YES;
+      continue;
+    }
     if (delta >= 64)
       continue;
     if (0 != (mid_mask & (1LLU << delta)))
     {
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "Got DATA_ACK with mask for %u on %s\n",
+           ntohl (crm->data_message->mid.mid),
+           GCCH_2s (ch));
       handle_matching_ack (ch,
                            crm);
       found = GNUNET_YES;
@@ -1498,9 +1522,8 @@ data_sent_cb (void *cls)
        GCCH_2s (ch),
        GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (ch->head_sent->next_retry),
                                                GNUNET_YES));
-  if (crm == ch->head_sent)
+  if (NULL == ch->head_sent->qe)
   {
-    /* We are the new head, need to reschedule retry task */
     if (NULL != ch->retry_data_task)
       GNUNET_SCHEDULER_cancel (ch->retry_data_task);
     ch->retry_data_task
@@ -1698,7 +1721,7 @@ GCCH_handle_local_ack (struct CadetChannel *ch,
   }
 
   LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Got LOCAL ACK, passing payload message %u to %s-%X on %s\n",
+       "Got LOCAL_ACK, passing payload message %u to %s-%X on %s\n",
        ntohl (com->mid.mid),
        GSC_2s (ccc->c),
        ntohl (ccc->ccn.channel_of_client),
index fe40d76b65c51d23ac55bd6580e8ba6f8e5d83a7..97bb1378ef3c1879f1e0a1f5c4339414fb905926 100644 (file)
@@ -502,6 +502,34 @@ GCP_set_mq (struct CadetPeer *cp,
 }
 
 
+/**
+ * Debug function should NEVER return true in production code, useful to
+ * simulate losses for testcases.
+ *
+ * @return #GNUNET_YES or #GNUNET_NO with the decision to drop.
+ */
+static int
+should_I_drop (void)
+{
+  if (0 == drop_percent)
+    return GNUNET_NO;
+  if (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
+                                101) < drop_percent)
+    return GNUNET_YES;
+  return GNUNET_NO;
+}
+
+
+/**
+ * Function called when CORE took one of the messages from
+ * a message queue manager and transmitted it.
+ *
+ * @param cls the `struct CadetPeeer` where we made progress
+ */
+static void
+mqm_send_done (void *cls);
+
+
 /**
  * Transmit current envelope from this @a mqm.
  *
@@ -512,10 +540,6 @@ mqm_execute (struct GCP_MessageQueueManager *mqm)
 {
   struct CadetPeer *cp = mqm->cp;
 
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Sending to peer %s from MQM %p\n",
-       GCP_2s (cp),
-       mqm);
   /* Move entry to the end of the DLL, to be fair. */
   if (mqm != cp->mqm_tail)
   {
@@ -526,10 +550,27 @@ mqm_execute (struct GCP_MessageQueueManager *mqm)
                                       cp->mqm_tail,
                                       mqm);
   }
-  GNUNET_MQ_send (cp->core_mq,
-                  mqm->env);
-  mqm->env = NULL;
   cp->mqm_ready_counter--;
+  if (GNUNET_YES == should_I_drop ())
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "DROPPING message to peer %s from MQM %p\n",
+         GCP_2s (cp),
+         mqm);
+    GNUNET_MQ_discard (mqm->env);
+    mqm->env = NULL;
+    mqm_send_done (cp);
+  }
+  else
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Sending to peer %s from MQM %p\n",
+         GCP_2s (cp),
+         mqm);
+    GNUNET_MQ_send (cp->core_mq,
+                    mqm->env);
+    mqm->env = NULL;
+  }
   mqm->cb (mqm->cb_cls,
            GNUNET_YES);
 }
index 03067a605279079c79bd7c491dfa9b04028ff896..592a8c6838b50c81bc0c7d696a21c7641e179e58 100644 (file)
@@ -361,17 +361,6 @@ struct CadetTunnel
    */
   struct CadetTunnelQueueEntry *tq_tail;
 
-
-  /**
-   * Ephemeral message in the queue (to avoid queueing more than one).
-   */
-  struct CadetConnectionQueue *ephm_hKILL;
-
-  /**
-   * Pong message in the queue.
-   */
-  struct CadetConnectionQueue *pong_hKILL;
-
   /**
    * How long do we wait until we retry the KX?
    */