-indent, doxygen
[oweals/gnunet.git] / src / fragmentation / fragmentation.c
index 9c9fea251011eb3552c7566b5cbc44b3b44be843..bf749181590028406e5a75b3569f893cccaa1d8c 100644 (file)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet
-     (C) 2009, 2011 Christian Grothoff (and other contributing authors)
+     (C) 2009-2013 Christian Grothoff (and other contributing authors)
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
@@ -52,7 +52,12 @@ struct GNUNET_FRAGMENT_Context
   /**
    * Current expected delay for ACKs.
    */
-  struct GNUNET_TIME_Relative delay;
+  struct GNUNET_TIME_Relative ack_delay;
+
+  /**
+   * Current expected delay between messages.
+   */
+  struct GNUNET_TIME_Relative msg_delay;
 
   /**
    * Next allowed transmission time.
@@ -175,17 +180,17 @@ transmit_next (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
     delay = GNUNET_BANDWIDTH_tracker_get_delay (fc->tracker, fsize);
   else
     delay = GNUNET_TIME_UNIT_ZERO;
-  if (delay.rel_value > 0)
+  if (delay.rel_value_us > 0)
   {
     fc->task = GNUNET_SCHEDULER_add_delayed (delay, &transmit_next, fc);
     return;
   }
   fc->next_transmission = (fc->next_transmission + 1) % 64;
-  wrap |= (fc->next_transmission == 0);
+  wrap |= (0 == fc->next_transmission);
   while (0 == (fc->acks & (1LL << fc->next_transmission)))
   {
     fc->next_transmission = (fc->next_transmission + 1) % 64;
-    wrap |= (fc->next_transmission == 0);
+    wrap |= (0 == fc->next_transmission);
   }
 
   /* assemble fragmentation message */
@@ -202,7 +207,7 @@ transmit_next (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
     GNUNET_BANDWIDTH_tracker_consume (fc->tracker, fsize);
   GNUNET_STATISTICS_update (fc->stats, _("# fragments transmitted"), 1,
                             GNUNET_NO);
-  if (0 != fc->last_round.abs_value)
+  if (0 != fc->last_round.abs_value_us)
     GNUNET_STATISTICS_update (fc->stats, _("# fragments retransmitted"), 1,
                               GNUNET_NO);
 
@@ -217,14 +222,14 @@ transmit_next (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
     delay = GNUNET_BANDWIDTH_tracker_get_delay (fc->tracker, fsize);
   else
     delay = GNUNET_TIME_UNIT_ZERO;
+  delay = GNUNET_TIME_relative_max (delay,
+                                   GNUNET_TIME_relative_multiply (fc->msg_delay,
+                                                                  (1 << fc->num_rounds)));
   if (wrap)
   {
     /* full round transmitted wait 2x delay for ACK before going again */
     fc->num_rounds++;
-    delay =
-        GNUNET_TIME_relative_max (GNUNET_TIME_relative_multiply (delay, 2),
-                                  GNUNET_TIME_relative_multiply (fc->delay,
-                                                                 fc->num_rounds));
+    delay = GNUNET_TIME_relative_multiply (fc->ack_delay, 2);
     /* never use zero, need some time for ACK always */
     delay = GNUNET_TIME_relative_max (MIN_ACK_DELAY, delay);
     fc->wack = GNUNET_YES;
@@ -232,10 +237,6 @@ transmit_next (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
     GNUNET_STATISTICS_update (fc->stats, _("# fragments wrap arounds"), 1,
                               GNUNET_NO);
   }
-  GNUNET_STATISTICS_set (fc->stats, 
-                        _("# next delay for fragment transmission"), 
-                        delay.rel_value,
-                        GNUNET_NO);
   fc->proc_busy = GNUNET_YES;
   fc->delay_until = GNUNET_TIME_relative_to_absolute (delay);
   fc->num_transmissions++;
@@ -254,7 +255,9 @@ transmit_next (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  * @param stats statistics context
  * @param mtu the maximum message size for each fragment
  * @param tracker bandwidth tracker to use for flow control (can be NULL)
- * @param delay expected delay between fragment transmission
+ * @param msg_delay initial delay to insert between fragment transmissions
+ *              based on previous messages
+ * @param ack_delay expected delay between fragment transmission
  *              and ACK based on previous messages
  * @param msg the message to fragment
  * @param proc function to call for each fragment to transmit
@@ -265,7 +268,8 @@ struct GNUNET_FRAGMENT_Context *
 GNUNET_FRAGMENT_context_create (struct GNUNET_STATISTICS_Handle *stats,
                                 uint16_t mtu,
                                 struct GNUNET_BANDWIDTH_Tracker *tracker,
-                                struct GNUNET_TIME_Relative delay,
+                                struct GNUNET_TIME_Relative msg_delay,
+                                struct GNUNET_TIME_Relative ack_delay,
                                 const struct GNUNET_MessageHeader *msg,
                                 GNUNET_FRAGMENT_MessageProcessor proc,
                                 void *proc_cls)
@@ -273,9 +277,7 @@ GNUNET_FRAGMENT_context_create (struct GNUNET_STATISTICS_Handle *stats,
   struct GNUNET_FRAGMENT_Context *fc;
   size_t size;
   uint64_t bits;
-  
-  GNUNET_STATISTICS_set (stats, _("# expected ACK delay for fragments"), 
-                        delay.rel_value, GNUNET_NO);
+
   GNUNET_STATISTICS_update (stats, _("# messages fragmented"), 1, GNUNET_NO);
   GNUNET_assert (mtu >= 1024 + sizeof (struct FragmentHeader));
   size = ntohs (msg->size);
@@ -286,7 +288,8 @@ GNUNET_FRAGMENT_context_create (struct GNUNET_STATISTICS_Handle *stats,
   fc->stats = stats;
   fc->mtu = mtu;
   fc->tracker = tracker;
-  fc->delay = delay;
+  fc->ack_delay = ack_delay;
+  fc->msg_delay = msg_delay;
   fc->msg = (const struct GNUNET_MessageHeader *) &fc[1];
   fc->proc = proc;
   fc->proc_cls = proc_cls;
@@ -345,6 +348,9 @@ GNUNET_FRAGMENT_process_ack (struct GNUNET_FRAGMENT_Context *fc,
   const struct FragmentAcknowledgement *fa;
   uint64_t abits;
   struct GNUNET_TIME_Relative ndelay;
+  unsigned int ack_cnt;
+  unsigned int snd_cnt;
+  unsigned int i;
 
   if (sizeof (struct FragmentAcknowledgement) != ntohs (msg->size))
   {
@@ -361,9 +367,39 @@ GNUNET_FRAGMENT_process_ack (struct GNUNET_FRAGMENT_Context *fc,
     /* normal ACK, can update running average of delay... */
     fc->wack = GNUNET_NO;
     ndelay = GNUNET_TIME_absolute_get_duration (fc->last_round);
-    fc->delay.rel_value =
-        (ndelay.rel_value / fc->num_transmissions + 3 * fc->delay.rel_value) / 4;
+    fc->ack_delay.rel_value_us =
+        (ndelay.rel_value_us / fc->num_transmissions + 3 * fc->ack_delay.rel_value_us) / 4;
     fc->num_transmissions = 0;
+    /* calculate ratio msg sent vs. msg acked */
+    ack_cnt = 0;
+    snd_cnt = 0;
+    for (i=0;i<64;i++)
+    {
+      if (1 == (fc->acks_mask & (1 << i)))
+      {
+       snd_cnt++;
+       if (0 == (abits & (1 << i)))
+         ack_cnt++;
+      }
+    }
+    if (0 == ack_cnt)
+    {
+      /* complete loss */
+      fc->msg_delay = GNUNET_TIME_relative_multiply (fc->msg_delay,
+                                                    snd_cnt);
+    }
+    else if (snd_cnt > ack_cnt)
+    {
+      /* some loss, slow down proportionally */
+      fprintf (stderr, "Prop loss\n");
+      fc->msg_delay.rel_value_us = ((fc->msg_delay.rel_value_us * ack_cnt) / snd_cnt);
+    }
+    else if (100 < fc->msg_delay.rel_value_us)
+    {
+      fc->msg_delay.rel_value_us -= 100; /* try a bit faster */
+    }
+    fc->msg_delay = GNUNET_TIME_relative_min (fc->msg_delay,
+                                             GNUNET_TIME_UNIT_SECONDS);
   }
   GNUNET_STATISTICS_update (fc->stats,
                             _("# fragment acknowledgements received"), 1,
@@ -412,19 +448,24 @@ GNUNET_FRAGMENT_process_ack (struct GNUNET_FRAGMENT_Context *fc,
  * resources).
  *
  * @param fc fragmentation context
- * @return average delay between transmission and ACK for the
- *         last message, FOREVER if the message was not fully transmitted
+ * @param msg_delay where to store average delay between individual message transmissions the
+ *         last message (OUT only)
+ * @param ack_delay where to store average delay between transmission and ACK for the
+ *         last message, set to FOREVER if the message was not fully transmitted (OUT only)
  */
-struct GNUNET_TIME_Relative
-GNUNET_FRAGMENT_context_destroy (struct GNUNET_FRAGMENT_Context *fc)
+void
+GNUNET_FRAGMENT_context_destroy (struct GNUNET_FRAGMENT_Context *fc,
+                                struct GNUNET_TIME_Relative *msg_delay,
+                                struct GNUNET_TIME_Relative *ack_delay)
 {
-  struct GNUNET_TIME_Relative ret;
-
   if (fc->task != GNUNET_SCHEDULER_NO_TASK)
     GNUNET_SCHEDULER_cancel (fc->task);
-  ret = fc->delay;
+  if (NULL != ack_delay)
+    *ack_delay = fc->ack_delay;
+  if (NULL != msg_delay)
+    *msg_delay = GNUNET_TIME_relative_multiply (fc->msg_delay,
+                                               fc->num_rounds);
   GNUNET_free (fc);
-  return ret;
 }