diff options
Diffstat (limited to 'src/fragmentation/fragmentation.c')
-rw-r--r-- | src/fragmentation/fragmentation.c | 89 |
1 files changed, 68 insertions, 21 deletions
diff --git a/src/fragmentation/fragmentation.c b/src/fragmentation/fragmentation.c index 4749f53..f859b32 100644 --- a/src/fragmentation/fragmentation.c +++ b/src/fragmentation/fragmentation.c @@ -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. @@ -181,11 +186,11 @@ transmit_next (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) 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 */ @@ -217,16 +222,16 @@ 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); + delay = GNUNET_TIME_relative_max (MIN_ACK_DELAY, delay); fc->wack = GNUNET_YES; fc->last_round = GNUNET_TIME_absolute_get (); GNUNET_STATISTICS_update (fc->stats, _("# fragments wrap arounds"), 1, @@ -250,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 @@ -261,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) @@ -280,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; @@ -339,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)) { @@ -355,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 = + (ndelay.rel_value / fc->num_transmissions + 3 * fc->ack_delay.rel_value) / 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 = ((fc->msg_delay.rel_value * ack_cnt) / snd_cnt); + } + else if (1 < fc->msg_delay.rel_value) + { + fc->msg_delay.rel_value--; /* 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, @@ -406,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; } |