GNUnet  0.20.0
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 
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29 
30 
31 #define LOG(kind, ...) GNUNET_log_from (kind, "util-bandwidth", __VA_ARGS__)
32 
40 GNUNET_BANDWIDTH_value_init (uint32_t bytes_per_second)
41 {
43 
44  ret.value__ = htonl (bytes_per_second);
45  return ret;
46 }
47 
48 
59 {
61  GNUNET_MIN (ntohl (b1.value__), ntohl (b2.value__)));
62 }
63 
64 
75 {
77  GNUNET_MAX (ntohl (b1.value__), ntohl (b2.value__)));
78 }
79 
80 
91 {
92  return GNUNET_BANDWIDTH_value_init (ntohl (b1.value__) + ntohl (b2.value__));
93 }
94 
95 
96 uint64_t
98  struct GNUNET_BANDWIDTH_Value32NBO bps,
100 {
101  uint64_t b;
102 
103  b = ntohl (bps.value__);
105  "Bandwidth has %llu bytes available until deadline in %s\n",
106  (unsigned long long) ((b * deadline.rel_value_us + 500000LL)
107  / 1000000LL),
109  return (b * deadline.rel_value_us + 500000LL) / 1000000LL;
110 }
111 
112 
123  uint64_t size)
124 {
125  uint64_t b;
126  struct GNUNET_TIME_Relative ret;
127 
128  b = ntohl (bps.value__);
129  if (0 == b)
130  {
132  "Bandwidth suggests delay of infinity (zero bandwidth)\n");
134  }
135  ret.rel_value_us = size * 1000LL * 1000LL / b;
137  "Bandwidth suggests delay of %s for %llu bytes of traffic\n",
139  (unsigned long long) size);
140  return ret;
141 }
142 
143 
149 static void
150 excess_trigger (void *cls)
151 {
152  struct GNUNET_BANDWIDTH_Tracker *av = cls;
153 
154  av->excess_task = NULL;
155  if (NULL != av->excess_cb)
156  {
158  "Notifying application about excess bandwidth\n");
159  av->excess_cb (av->excess_cb_cls);
160  }
161 }
162 
163 
167 static void
169 {
171  struct GNUNET_TIME_Absolute now;
172  uint64_t delta_time;
173  uint64_t delta_avail;
174  int64_t left_bytes;
175  uint64_t max_carry;
176  int64_t current_consumption;
177 
178  if (NULL == av->excess_cb)
179  return; /* nothing to do */
180  now = GNUNET_TIME_absolute_get ();
181  delta_time = now.abs_value_us - av->last_update__.abs_value_us;
182  delta_avail =
183  (delta_time * ((unsigned long long) av->available_bytes_per_s__)
184  + 500000LL)
185  / 1000000LL;
186  current_consumption = av->consumption_since_last_update__ - delta_avail;
187  if (current_consumption > av->consumption_since_last_update__)
188  {
189  /* integer underflow, cap! */
190  current_consumption = INT64_MIN;
191  }
192  /* negative current_consumption means that we have savings */
193  max_carry = ((uint64_t) av->available_bytes_per_s__) * av->max_carry_s__;
194  if (max_carry < GNUNET_MAX_MESSAGE_SIZE)
195  max_carry = GNUNET_MAX_MESSAGE_SIZE;
196  if (max_carry > INT64_MAX)
197  max_carry = INT64_MAX;
198  left_bytes = current_consumption + max_carry;
199  if (left_bytes < current_consumption)
200  {
201  /* integer overflow, cap! */
202  left_bytes = INT64_MAX;
203  }
204  /* left_bytes now contains the number of bytes needed until
205  we have more savings than allowed */
206  if (left_bytes < 0)
207  {
208  /* having excess already */
210  }
211  else
212  {
213  double factor = 1.0 * left_bytes / (double) av->available_bytes_per_s__;
214  delay =
216  (unsigned long long) factor);
217  }
218  GNUNET_log (
220  "At %llu bps it will take us %s for %lld bytes to reach excess threshold\n",
221  (unsigned long long) av->available_bytes_per_s__,
223  (long long) left_bytes);
224  if (NULL != av->excess_task)
227 }
228 
229 
251 void
253  struct GNUNET_BANDWIDTH_Tracker *av,
255  void *update_cb_cls,
256  struct GNUNET_BANDWIDTH_Value32NBO bytes_per_second_limit,
257  uint32_t max_carry_s,
259  void *excess_cb_cls)
260 {
261  av->update_cb = update_cb;
262  av->update_cb_cls = update_cb_cls;
265  av->available_bytes_per_s__ = ntohl (bytes_per_second_limit.value__);
266  av->max_carry_s__ = max_carry_s;
267  av->excess_cb = excess_cb;
268  av->excess_cb_cls = excess_cb_cls;
270  "Tracker %p initialized with %u Bps and max carry %u\n",
271  av,
272  (unsigned int) av->available_bytes_per_s__,
273  (unsigned int) max_carry_s);
274  update_excess (av);
275 }
276 
277 
278 void
280  struct GNUNET_BANDWIDTH_Tracker *av,
282  void *update_cb_cls,
283  struct GNUNET_BANDWIDTH_Value32NBO bytes_per_second_limit,
284  uint32_t max_carry_s)
285 {
287  update_cb,
288  update_cb_cls,
289  bytes_per_second_limit,
290  max_carry_s,
291  NULL,
292  NULL);
293 }
294 
295 
301 void
303 {
304  if (NULL != av->excess_task)
306  av->excess_task = NULL;
307  av->excess_cb = NULL;
308  av->excess_cb_cls = NULL;
309  av->update_cb = NULL;
310  av->update_cb_cls = NULL;
311 }
312 
313 
320 static void
322 {
323  struct GNUNET_TIME_Absolute now;
324  uint64_t delta_time;
325  uint64_t delta_avail;
326  uint64_t left_bytes;
327  uint64_t max_carry;
328 
329  now = GNUNET_TIME_absolute_get ();
330  delta_time = now.abs_value_us - av->last_update__.abs_value_us;
331  delta_avail =
332  (delta_time * ((unsigned long long) av->available_bytes_per_s__)
333  + 500000LL)
334  / 1000000LL;
335  av->consumption_since_last_update__ -= delta_avail;
336  av->last_update__ = now;
338  {
339  left_bytes = -av->consumption_since_last_update__;
340  max_carry =
341  ((unsigned long long) av->available_bytes_per_s__) * av->max_carry_s__;
342  if (max_carry < GNUNET_MAX_MESSAGE_SIZE)
343  max_carry = GNUNET_MAX_MESSAGE_SIZE;
344  if (max_carry > INT64_MAX)
345  max_carry = INT64_MAX;
346  if (max_carry > left_bytes)
347  av->consumption_since_last_update__ = -left_bytes;
348  else
349  av->consumption_since_last_update__ = -max_carry;
350  }
351 #if ! defined(GNUNET_CULL_LOGGING)
352  {
354 
355  delta.rel_value_us = delta_time;
357  "Tracker %p updated, consumption at %lld at %u Bps, last update was %s ago\n",
358  av,
359  (long long) av->consumption_since_last_update__,
360  (unsigned int) av->available_bytes_per_s__,
362  }
363 #endif
364 }
365 
366 
367 int
369  ssize_t size)
370 {
371  int64_t nc;
372 
374  "Tracker %p consumes %d bytes\n",
375  av,
376  (int) size);
377  if (size > 0)
378  {
380  if (nc < av->consumption_since_last_update__)
381  {
382  /* integer overflow, very bad */
383  GNUNET_break (0);
384  return GNUNET_SYSERR;
385  }
387  update_tracker (av);
388  update_excess (av);
390  {
392  "Tracker %p consumption %llu bytes above limit\n",
393  av,
394  (unsigned long long) av->consumption_since_last_update__);
395  return GNUNET_YES;
396  }
397  }
398  else
399  {
402  {
403  /* integer underflow, very bad */
404  GNUNET_break (0);
405  return GNUNET_SYSERR;
406  }
408  update_excess (av);
409  }
410  return GNUNET_NO;
411 }
412 
413 
425  size_t size)
426 {
427  struct GNUNET_TIME_Relative ret;
428  int64_t bytes_needed;
429 
430  if (0 == av->available_bytes_per_s__)
431  {
432  LOG (GNUNET_ERROR_TYPE_DEBUG, "Tracker %p delay is infinity\n", av);
434  }
435  update_tracker (av);
436  bytes_needed = size + av->consumption_since_last_update__;
437  if (bytes_needed <= 0)
438  {
440  "Tracker %p delay for %u bytes is zero\n",
441  av,
442  (unsigned int) size);
443  return GNUNET_TIME_UNIT_ZERO;
444  }
445  ret.rel_value_us = (1000LL * 1000LL * bytes_needed)
446  / (unsigned long long) av->available_bytes_per_s__;
448  "Tracker %p delay for %u bytes is %s\n",
449  av,
450  (unsigned int) size,
452  return ret;
453 }
454 
455 
463 int64_t
465 {
466  struct GNUNET_BANDWIDTH_Value32NBO bps;
467  uint64_t avail;
468  int64_t used;
469 
470  update_tracker (av);
472  avail =
475  av->last_update__));
478  "Tracker %p available bandwidth is %lld bytes\n",
479  av,
480  (long long) (int64_t) (avail - used));
481  return (int64_t) (avail - used);
482 }
483 
484 
491 void
493  struct GNUNET_BANDWIDTH_Tracker *av,
494  struct GNUNET_BANDWIDTH_Value32NBO bytes_per_second_limit)
495 {
496  uint32_t old_limit;
497  uint32_t new_limit;
498 
499  new_limit = ntohl (bytes_per_second_limit.value__);
501  "Tracker %p bandwidth changed to %u Bps\n",
502  av,
503  (unsigned int) new_limit);
504  update_tracker (av);
505  old_limit = av->available_bytes_per_s__;
506  av->available_bytes_per_s__ = new_limit;
507  if (NULL != av->update_cb)
508  av->update_cb (av->update_cb_cls);
509  if (old_limit > new_limit)
510  update_tracker (av); /* maximum excess might be less now */
511  update_excess (av);
512 }
513 
514 
515 /* 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:168
static void excess_trigger(void *cls)
Task run whenever we hit the bandwidth limit for a tracker.
Definition: bandwidth.c:150
static void update_tracker(struct GNUNET_BANDWIDTH_Tracker *av)
Update the tracker, looking at the current time and bandwidth consumption data.
Definition: bandwidth.c:321
#define LOG(kind,...)
Definition: bandwidth.c:31
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:302
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:368
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:492
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:97
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:40
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:252
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:73
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:122
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:89
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:279
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:57
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:424
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:464
#define GNUNET_log(kind,...)
#define GNUNET_MAX(a, b)
#define GNUNET_MIN(a, b)
@ GNUNET_YES
@ GNUNET_NO
@ GNUNET_SYSERR
#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:975
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:1272
#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:436
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:531
#define GNUNET_TIME_UNIT_SECONDS
One second.
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_get(void)
Get the current time.
Definition: time.c:111
#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:569
static unsigned int size
Size of the "table".
Definition: peer.c:68
static struct GNUNET_TIME_Relative delta
Definition: speedup.c:36
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.