GNUnet  0.17.6
bandwidth.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 2010, 2013 GNUnet e.V.
4 
5  GNUnet is free software: you can redistribute it and/or modify it
6  under the terms of the GNU Affero General Public License as published
7  by the Free Software Foundation, either version 3 of the License,
8  or (at your option) any later version.
9 
10  GNUnet is distributed in the hope that it will be useful, but
11  WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Affero General Public License for more details.
14 
15  You should have received a copy of the GNU Affero General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  SPDX-License-Identifier: AGPL3.0-or-later
19  */
20 
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 
29 
30 #define LOG(kind, ...) GNUNET_log_from (kind, "util-bandwidth", __VA_ARGS__)
31 
39 GNUNET_BANDWIDTH_value_init (uint32_t bytes_per_second)
40 {
42 
43  ret.value__ = htonl (bytes_per_second);
44  return ret;
45 }
46 
47 
58 {
60  GNUNET_MIN (ntohl (b1.value__), ntohl (b2.value__)));
61 }
62 
63 
74 {
76  GNUNET_MAX (ntohl (b1.value__), ntohl (b2.value__)));
77 }
78 
79 
90 {
91  return GNUNET_BANDWIDTH_value_init (ntohl (b1.value__) + ntohl (b2.value__));
92 }
93 
94 
95 uint64_t
97  struct GNUNET_BANDWIDTH_Value32NBO bps,
99 {
100  uint64_t b;
101 
102  b = ntohl (bps.value__);
104  "Bandwidth has %llu bytes available until deadline in %s\n",
105  (unsigned long long) ((b * deadline.rel_value_us + 500000LL)
106  / 1000000LL),
108  return (b * deadline.rel_value_us + 500000LL) / 1000000LL;
109 }
110 
111 
122  uint64_t size)
123 {
124  uint64_t b;
125  struct GNUNET_TIME_Relative ret;
126 
127  b = ntohl (bps.value__);
128  if (0 == b)
129  {
131  "Bandwidth suggests delay of infinity (zero bandwidth)\n");
133  }
134  ret.rel_value_us = size * 1000LL * 1000LL / b;
136  "Bandwidth suggests delay of %s for %llu bytes of traffic\n",
138  (unsigned long long) size);
139  return ret;
140 }
141 
142 
148 static void
149 excess_trigger (void *cls)
150 {
151  struct GNUNET_BANDWIDTH_Tracker *av = cls;
152 
153  av->excess_task = NULL;
154  if (NULL != av->excess_cb)
155  {
157  "Notifying application about excess bandwidth\n");
158  av->excess_cb (av->excess_cb_cls);
159  }
160 }
161 
162 
166 static void
168 {
170  struct GNUNET_TIME_Absolute now;
171  uint64_t delta_time;
172  uint64_t delta_avail;
173  int64_t left_bytes;
174  uint64_t max_carry;
175  int64_t current_consumption;
176 
177  if (NULL == av->excess_cb)
178  return; /* nothing to do */
179  now = GNUNET_TIME_absolute_get ();
180  delta_time = now.abs_value_us - av->last_update__.abs_value_us;
181  delta_avail =
182  (delta_time * ((unsigned long long) av->available_bytes_per_s__)
183  + 500000LL)
184  / 1000000LL;
185  current_consumption = av->consumption_since_last_update__ - delta_avail;
186  if (current_consumption > av->consumption_since_last_update__)
187  {
188  /* integer underflow, cap! */
189  current_consumption = INT64_MIN;
190  }
191  /* negative current_consumption means that we have savings */
192  max_carry = ((uint64_t) av->available_bytes_per_s__) * av->max_carry_s__;
193  if (max_carry < GNUNET_MAX_MESSAGE_SIZE)
194  max_carry = GNUNET_MAX_MESSAGE_SIZE;
195  if (max_carry > INT64_MAX)
196  max_carry = INT64_MAX;
197  left_bytes = current_consumption + max_carry;
198  if (left_bytes < current_consumption)
199  {
200  /* integer overflow, cap! */
201  left_bytes = INT64_MAX;
202  }
203  /* left_bytes now contains the number of bytes needed until
204  we have more savings than allowed */
205  if (left_bytes < 0)
206  {
207  /* having excess already */
209  }
210  else
211  {
212  double factor = 1.0 * left_bytes / (double) av->available_bytes_per_s__;
213  delay =
215  (unsigned long long) factor);
216  }
217  GNUNET_log (
219  "At %llu bps it will take us %s for %lld bytes to reach excess threshold\n",
220  (unsigned long long) av->available_bytes_per_s__,
222  (long long) left_bytes);
223  if (NULL != av->excess_task)
226 }
227 
228 
250 void
252  struct GNUNET_BANDWIDTH_Tracker *av,
254  void *update_cb_cls,
255  struct GNUNET_BANDWIDTH_Value32NBO bytes_per_second_limit,
256  uint32_t max_carry_s,
258  void *excess_cb_cls)
259 {
260  av->update_cb = update_cb;
261  av->update_cb_cls = update_cb_cls;
264  av->available_bytes_per_s__ = ntohl (bytes_per_second_limit.value__);
265  av->max_carry_s__ = max_carry_s;
266  av->excess_cb = excess_cb;
267  av->excess_cb_cls = excess_cb_cls;
269  "Tracker %p initialized with %u Bps and max carry %u\n",
270  av,
271  (unsigned int) av->available_bytes_per_s__,
272  (unsigned int) max_carry_s);
273  update_excess (av);
274 }
275 
276 
277 void
279  struct GNUNET_BANDWIDTH_Tracker *av,
281  void *update_cb_cls,
282  struct GNUNET_BANDWIDTH_Value32NBO bytes_per_second_limit,
283  uint32_t max_carry_s)
284 {
286  update_cb,
287  update_cb_cls,
288  bytes_per_second_limit,
289  max_carry_s,
290  NULL,
291  NULL);
292 }
293 
294 
300 void
302 {
303  if (NULL != av->excess_task)
305  av->excess_task = NULL;
306  av->excess_cb = NULL;
307  av->excess_cb_cls = NULL;
308  av->update_cb = NULL;
309  av->update_cb_cls = NULL;
310 }
311 
312 
319 static void
321 {
322  struct GNUNET_TIME_Absolute now;
323  uint64_t delta_time;
324  uint64_t delta_avail;
325  uint64_t left_bytes;
326  uint64_t max_carry;
327 
328  now = GNUNET_TIME_absolute_get ();
329  delta_time = now.abs_value_us - av->last_update__.abs_value_us;
330  delta_avail =
331  (delta_time * ((unsigned long long) av->available_bytes_per_s__)
332  + 500000LL)
333  / 1000000LL;
334  av->consumption_since_last_update__ -= delta_avail;
335  av->last_update__ = now;
337  {
338  left_bytes = -av->consumption_since_last_update__;
339  max_carry =
340  ((unsigned long long) av->available_bytes_per_s__) * av->max_carry_s__;
341  if (max_carry < GNUNET_MAX_MESSAGE_SIZE)
342  max_carry = GNUNET_MAX_MESSAGE_SIZE;
343  if (max_carry > INT64_MAX)
344  max_carry = INT64_MAX;
345  if (max_carry > left_bytes)
346  av->consumption_since_last_update__ = -left_bytes;
347  else
348  av->consumption_since_last_update__ = -max_carry;
349  }
350 #if ! defined(GNUNET_CULL_LOGGING)
351  {
353 
354  delta.rel_value_us = delta_time;
356  "Tracker %p updated, consumption at %lld at %u Bps, last update was %s ago\n",
357  av,
358  (long long) av->consumption_since_last_update__,
359  (unsigned int) av->available_bytes_per_s__,
361  }
362 #endif
363 }
364 
365 
366 int
368  ssize_t size)
369 {
370  int64_t nc;
371 
373  "Tracker %p consumes %d bytes\n",
374  av,
375  (int) size);
376  if (size > 0)
377  {
379  if (nc < av->consumption_since_last_update__)
380  {
381  /* integer overflow, very bad */
382  GNUNET_break (0);
383  return GNUNET_SYSERR;
384  }
386  update_tracker (av);
387  update_excess (av);
389  {
391  "Tracker %p consumption %llu bytes above limit\n",
392  av,
393  (unsigned long long) av->consumption_since_last_update__);
394  return GNUNET_YES;
395  }
396  }
397  else
398  {
401  {
402  /* integer underflow, very bad */
403  GNUNET_break (0);
404  return GNUNET_SYSERR;
405  }
407  update_excess (av);
408  }
409  return GNUNET_NO;
410 }
411 
412 
424  size_t size)
425 {
426  struct GNUNET_TIME_Relative ret;
427  int64_t bytes_needed;
428 
429  if (0 == av->available_bytes_per_s__)
430  {
431  LOG (GNUNET_ERROR_TYPE_DEBUG, "Tracker %p delay is infinity\n", av);
433  }
434  update_tracker (av);
435  bytes_needed = size + av->consumption_since_last_update__;
436  if (bytes_needed <= 0)
437  {
439  "Tracker %p delay for %u bytes is zero\n",
440  av,
441  (unsigned int) size);
442  return GNUNET_TIME_UNIT_ZERO;
443  }
444  ret.rel_value_us = (1000LL * 1000LL * bytes_needed)
445  / (unsigned long long) av->available_bytes_per_s__;
447  "Tracker %p delay for %u bytes is %s\n",
448  av,
449  (unsigned int) size,
451  return ret;
452 }
453 
454 
462 int64_t
464 {
465  struct GNUNET_BANDWIDTH_Value32NBO bps;
466  uint64_t avail;
467  int64_t used;
468 
469  update_tracker (av);
471  avail =
474  av->last_update__));
477  "Tracker %p available bandwidth is %lld bytes\n",
478  av,
479  (long long) (int64_t) (avail - used));
480  return (int64_t) (avail - used);
481 }
482 
483 
490 void
492  struct GNUNET_BANDWIDTH_Tracker *av,
493  struct GNUNET_BANDWIDTH_Value32NBO bytes_per_second_limit)
494 {
495  uint32_t old_limit;
496  uint32_t new_limit;
497 
498  new_limit = ntohl (bytes_per_second_limit.value__);
500  "Tracker %p bandwidth changed to %u Bps\n",
501  av,
502  (unsigned int) new_limit);
503  update_tracker (av);
504  old_limit = av->available_bytes_per_s__;
505  av->available_bytes_per_s__ = new_limit;
506  if (NULL != av->update_cb)
507  av->update_cb (av->update_cb_cls);
508  if (old_limit > new_limit)
509  update_tracker (av); /* maximum excess might be less now */
510  update_excess (av);
511 }
512 
513 
514 /* end of bandwidth.c */
static void update_excess(struct GNUNET_BANDWIDTH_Tracker *av)
Recalculate when we might need to call the excess callback.
Definition: bandwidth.c:167
static void excess_trigger(void *cls)
Task run whenever we hit the bandwidth limit for a tracker.
Definition: bandwidth.c:149
static void update_tracker(struct GNUNET_BANDWIDTH_Tracker *av)
Update the tracker, looking at the current time and bandwidth consumption data.
Definition: bandwidth.c:320
#define LOG(kind,...)
Definition: bandwidth.c:30
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
static struct GNUNET_TIME_Absolute deadline
Deadline for all consensuses.
static struct GNUNET_TIME_Relative delay
When should dkg communication start?
static struct GNUNET_PEERINFO_NotifyContext * nc
Iterator context.
#define GNUNET_MAX_MESSAGE_SIZE
Largest supported message (to be precise, one byte more than the largest possible message,...
void GNUNET_BANDWIDTH_tracker_notification_stop(struct GNUNET_BANDWIDTH_Tracker *av)
Stop notifying about tracker updates and excess notifications.
Definition: bandwidth.c:301
int GNUNET_BANDWIDTH_tracker_consume(struct GNUNET_BANDWIDTH_Tracker *av, ssize_t size)
Notify the tracker that a certain number of bytes of bandwidth have been consumed.
Definition: bandwidth.c:367
void GNUNET_BANDWIDTH_tracker_update_quota(struct GNUNET_BANDWIDTH_Tracker *av, struct GNUNET_BANDWIDTH_Value32NBO bytes_per_second_limit)
Update quota of bandwidth tracker.
Definition: bandwidth.c:491
uint64_t GNUNET_BANDWIDTH_value_get_available_until(struct GNUNET_BANDWIDTH_Value32NBO bps, struct GNUNET_TIME_Relative deadline)
At the given bandwidth, calculate how much traffic will be available until the given deadline.
Definition: bandwidth.c:96
void(* GNUNET_BANDWIDTH_ExcessNotificationCallback)(void *cls)
Callback to be called by the bandwidth tracker if the tracker was updated and the client should updat...
struct GNUNET_BANDWIDTH_Value32NBO GNUNET_BANDWIDTH_value_init(uint32_t bytes_per_second)
Create a new bandwidth value.
Definition: bandwidth.c:39
void GNUNET_BANDWIDTH_tracker_init2(struct GNUNET_BANDWIDTH_Tracker *av, GNUNET_BANDWIDTH_TrackerUpdateCallback update_cb, void *update_cb_cls, struct GNUNET_BANDWIDTH_Value32NBO bytes_per_second_limit, uint32_t max_carry_s, GNUNET_BANDWIDTH_ExcessNotificationCallback excess_cb, void *excess_cb_cls)
Initialize bandwidth tracker.
Definition: bandwidth.c:251
struct GNUNET_BANDWIDTH_Value32NBO GNUNET_BANDWIDTH_value_max(struct GNUNET_BANDWIDTH_Value32NBO b1, struct GNUNET_BANDWIDTH_Value32NBO b2)
Compute the MAX of two bandwidth values.
Definition: bandwidth.c:72
struct GNUNET_TIME_Relative GNUNET_BANDWIDTH_value_get_delay_for(struct GNUNET_BANDWIDTH_Value32NBO bps, uint64_t size)
At the given bandwidth, calculate how long it would take for size bytes to be transmitted.
Definition: bandwidth.c:121
struct GNUNET_BANDWIDTH_Value32NBO GNUNET_BANDWIDTH_value_sum(struct GNUNET_BANDWIDTH_Value32NBO b1, struct GNUNET_BANDWIDTH_Value32NBO b2)
Compute the SUM of two bandwidth values.
Definition: bandwidth.c:88
void GNUNET_BANDWIDTH_tracker_init(struct GNUNET_BANDWIDTH_Tracker *av, GNUNET_BANDWIDTH_TrackerUpdateCallback update_cb, void *update_cb_cls, struct GNUNET_BANDWIDTH_Value32NBO bytes_per_second_limit, uint32_t max_carry_s)
Initialize bandwidth tracker.
Definition: bandwidth.c:278
struct GNUNET_BANDWIDTH_Value32NBO GNUNET_BANDWIDTH_value_min(struct GNUNET_BANDWIDTH_Value32NBO b1, struct GNUNET_BANDWIDTH_Value32NBO b2)
Compute the MIN of two bandwidth values.
Definition: bandwidth.c:56
void(* GNUNET_BANDWIDTH_TrackerUpdateCallback)(void *cls)
Callback to be called by the bandwidth tracker if the tracker was updated and the client should updat...
struct GNUNET_TIME_Relative GNUNET_BANDWIDTH_tracker_get_delay(struct GNUNET_BANDWIDTH_Tracker *av, size_t size)
Compute how long we should wait until consuming 'size' bytes of bandwidth in order to stay within the...
Definition: bandwidth.c:423
int64_t GNUNET_BANDWIDTH_tracker_get_available(struct GNUNET_BANDWIDTH_Tracker *av)
Compute how many bytes are available for consumption right now.
Definition: bandwidth.c:463
#define GNUNET_log(kind,...)
#define GNUNET_MAX(a, b)
#define GNUNET_MIN(a, b)
@ GNUNET_YES
@ GNUNET_NO
Definition: gnunet_common.h:98
@ GNUNET_SYSERR
Definition: gnunet_common.h:97
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
@ GNUNET_ERROR_TYPE_DEBUG
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:957
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_delayed(struct GNUNET_TIME_Relative delay, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay.
Definition: scheduler.c:1254
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
struct GNUNET_TIME_Relative GNUNET_TIME_absolute_get_duration(struct GNUNET_TIME_Absolute whence)
Get the duration of an operation as the difference of the current time and the given start time "henc...
Definition: time.c:435
struct GNUNET_TIME_Relative GNUNET_TIME_relative_saturating_multiply(struct GNUNET_TIME_Relative rel, unsigned long long factor)
Saturating multiply relative time by a given factor.
Definition: time.c:530
#define GNUNET_TIME_UNIT_SECONDS
One second.
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_get(void)
Get the current time.
Definition: time.c:110
#define GNUNET_TIME_UNIT_ZERO
Relative time zero.
const char * GNUNET_STRINGS_relative_time_to_string(struct GNUNET_TIME_Relative delta, int do_round)
Give relative time in human-readable fancy format.
Definition: strings.c:570
static unsigned int size
Size of the "table".
Definition: peer.c:67
static struct GNUNET_TIME_Relative delta
Definition: speedup.c:35
Struct to track available bandwidth.
struct GNUNET_SCHEDULER_Task * excess_task
Task scheduled to call the excess_cb once we have reached the maximum bandwidth the tracker can hold.
int64_t consumption_since_last_update__
Number of bytes consumed since we last updated the tracker.
GNUNET_BANDWIDTH_ExcessNotificationCallback excess_cb
Function we call if the tracker is about to throw away bandwidth due to excess (max carry exceeded).
void * update_cb_cls
Closure for update_cb.
struct GNUNET_TIME_Absolute last_update__
Time when we last updated the tracker.
void * excess_cb_cls
Closure for excess_cb.
GNUNET_BANDWIDTH_TrackerUpdateCallback update_cb
Function we call if the tracker's bandwidth is increased and a previously returned timeout might now ...
uint32_t available_bytes_per_s__
Bandwidth limit to enforce in bytes per second.
uint32_t max_carry_s__
Maximum number of seconds over which bandwidth may "accumulate".
32-bit bandwidth used for network exchange by GNUnet, in bytes per second.
uint32_t value__
The actual value (bytes per second).
Time for absolute times used by GNUnet, in microseconds.
uint64_t abs_value_us
The actual value.
Time for relative time used by GNUnet, in microseconds.
uint64_t rel_value_us
The actual value.