+/**
+ * Task run whenever we hit the bandwidth limit for a tracker.
+ *
+ * @param cls the `struct GNUNET_BANDWIDTH_Tracker`
+ * @param tc scheduler context
+ */
+static void
+excess_trigger (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct GNUNET_BANDWIDTH_Tracker *av = cls;
+
+ av->excess_task = NULL;
+
+ if (NULL != av->excess_cb)
+ av->excess_cb (av->excess_cb_cls);
+}
+
+
+/**
+ * Recalculate when we might need to call the excess callback.
+ */
+static void
+update_excess (struct GNUNET_BANDWIDTH_Tracker *av)
+{
+ struct GNUNET_TIME_Relative delay;
+ struct GNUNET_TIME_Absolute now;
+ uint64_t delta_time;
+ uint64_t delta_avail;
+ int64_t left_bytes;
+ uint64_t max_carry;
+ int64_t current_consumption;
+
+ if (NULL == av->excess_cb)
+ return; /* nothing to do */
+ now = GNUNET_TIME_absolute_get ();
+ delta_time = now.abs_value_us - av->last_update__.abs_value_us;
+ delta_avail =
+ (delta_time * ((unsigned long long) av->available_bytes_per_s__) +
+ 500000LL) / 1000000LL;
+ current_consumption = av->consumption_since_last_update__ - delta_avail;
+ /* negative current_consumption means that we have savings */
+ max_carry = av->available_bytes_per_s__ * av->max_carry_s__;
+ if (max_carry < GNUNET_SERVER_MAX_MESSAGE_SIZE)
+ max_carry = GNUNET_SERVER_MAX_MESSAGE_SIZE;
+ left_bytes = max_carry + current_consumption;
+ /* left_bytes now contains the number of bytes needed until
+ we have more savings than allowed */
+ if (left_bytes < 0)
+ {
+ /* having excess already */
+ delay = GNUNET_TIME_UNIT_ZERO;
+ }
+ else
+ {
+ delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
+ left_bytes);
+ delay = GNUNET_TIME_relative_divide (delay,
+ av->available_bytes_per_s__);
+ }
+ if (NULL != av->excess_task)
+ GNUNET_SCHEDULER_cancel (av->excess_task);
+ av->excess_task = GNUNET_SCHEDULER_add_delayed (delay,
+ &excess_trigger,
+ av);
+}
+
+