GNUnet  0.10.x
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 {
41  struct GNUNET_BANDWIDTH_Value32NBO ret;
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 
103 uint64_t
105  struct GNUNET_BANDWIDTH_Value32NBO bps,
107 {
108  uint64_t b;
109 
110  b = ntohl(bps.value__);
112  "Bandwidth has %llu bytes available until deadline in %s\n",
113  (unsigned long long)((b * deadline.rel_value_us + 500000LL) /
114  1000000LL),
116  return (b * deadline.rel_value_us + 500000LL) / 1000000LL;
117 }
118 
119 
130  uint64_t size)
131 {
132  uint64_t b;
133  struct GNUNET_TIME_Relative ret;
134 
135  b = ntohl(bps.value__);
136  if (0 == b)
137  {
139  "Bandwidth suggests delay of infinity (zero bandwidth)\n");
141  }
142  ret.rel_value_us = size * 1000LL * 1000LL / b;
144  "Bandwidth suggests delay of %s for %llu bytes of traffic\n",
146  (unsigned long long)size);
147  return ret;
148 }
149 
150 
156 static void
157 excess_trigger(void *cls)
158 {
159  struct GNUNET_BANDWIDTH_Tracker *av = cls;
160 
161  av->excess_task = NULL;
162  if (NULL != av->excess_cb)
163  {
165  "Notifying application about excess bandwidth\n");
166  av->excess_cb(av->excess_cb_cls);
167  }
168 }
169 
170 
174 static void
176 {
177  struct GNUNET_TIME_Relative delay;
178  struct GNUNET_TIME_Absolute now;
179  uint64_t delta_time;
180  uint64_t delta_avail;
181  int64_t left_bytes;
182  uint64_t max_carry;
183  int64_t current_consumption;
184 
185  if (NULL == av->excess_cb)
186  return; /* nothing to do */
187  now = GNUNET_TIME_absolute_get();
188  delta_time = now.abs_value_us - av->last_update__.abs_value_us;
189  delta_avail =
190  (delta_time * ((unsigned long long)av->available_bytes_per_s__) +
191  500000LL) /
192  1000000LL;
193  current_consumption = av->consumption_since_last_update__ - delta_avail;
194  if (current_consumption > av->consumption_since_last_update__)
195  {
196  /* integer underflow, cap! */
197  current_consumption = INT64_MIN;
198  }
199  /* negative current_consumption means that we have savings */
200  max_carry = ((uint64_t)av->available_bytes_per_s__) * av->max_carry_s__;
201  if (max_carry < GNUNET_MAX_MESSAGE_SIZE)
202  max_carry = GNUNET_MAX_MESSAGE_SIZE;
203  if (max_carry > INT64_MAX)
204  max_carry = INT64_MAX;
205  left_bytes = current_consumption + max_carry;
206  if (left_bytes < current_consumption)
207  {
208  /* integer overflow, cap! */
209  left_bytes = INT64_MAX;
210  }
211  /* left_bytes now contains the number of bytes needed until
212  we have more savings than allowed */
213  if (left_bytes < 0)
214  {
215  /* having excess already */
216  delay = GNUNET_TIME_UNIT_ZERO;
217  }
218  else
219  {
220  double factor = 1.0 * left_bytes / (double)av->available_bytes_per_s__;
221  delay =
223  (unsigned long long)factor);
224  }
225  GNUNET_log(
227  "At %llu bps it will take us %s for %lld bytes to reach excess threshold\n",
228  (unsigned long long)av->available_bytes_per_s__,
230  (long long)left_bytes);
231  if (NULL != av->excess_task)
234 }
235 
236 
258 void
260  struct GNUNET_BANDWIDTH_Tracker *av,
262  void *update_cb_cls,
263  struct GNUNET_BANDWIDTH_Value32NBO bytes_per_second_limit,
264  uint32_t max_carry_s,
266  void *excess_cb_cls)
267 {
268  av->update_cb = update_cb;
269  av->update_cb_cls = update_cb_cls;
272  av->available_bytes_per_s__ = ntohl(bytes_per_second_limit.value__);
273  av->max_carry_s__ = max_carry_s;
274  av->excess_cb = excess_cb;
275  av->excess_cb_cls = excess_cb_cls;
277  "Tracker %p initialized with %u Bps and max carry %u\n",
278  av,
279  (unsigned int)av->available_bytes_per_s__,
280  (unsigned int)max_carry_s);
281  update_excess(av);
282 }
283 
284 
301 void
303  struct GNUNET_BANDWIDTH_Tracker *av,
305  void *update_cb_cls,
306  struct GNUNET_BANDWIDTH_Value32NBO bytes_per_second_limit,
307  uint32_t max_carry_s)
308 {
310  update_cb,
311  update_cb_cls,
312  bytes_per_second_limit,
313  max_carry_s,
314  NULL,
315  NULL);
316 }
317 
318 
324 void
326 {
327  if (NULL != av->excess_task)
329  av->excess_task = NULL;
330  av->excess_cb = NULL;
331  av->excess_cb_cls = NULL;
332  av->update_cb = NULL;
333  av->update_cb_cls = NULL;
334 }
335 
336 
343 static void
345 {
346  struct GNUNET_TIME_Absolute now;
347  uint64_t delta_time;
348  uint64_t delta_avail;
349  uint64_t left_bytes;
350  uint64_t max_carry;
351 
352  now = GNUNET_TIME_absolute_get();
353  delta_time = now.abs_value_us - av->last_update__.abs_value_us;
354  delta_avail =
355  (delta_time * ((unsigned long long)av->available_bytes_per_s__) +
356  500000LL) /
357  1000000LL;
358  av->consumption_since_last_update__ -= delta_avail;
359  av->last_update__ = now;
361  {
362  left_bytes = -av->consumption_since_last_update__;
363  max_carry =
364  ((unsigned long long)av->available_bytes_per_s__) * av->max_carry_s__;
365  if (max_carry < GNUNET_MAX_MESSAGE_SIZE)
366  max_carry = GNUNET_MAX_MESSAGE_SIZE;
367  if (max_carry > INT64_MAX)
368  max_carry = INT64_MAX;
369  if (max_carry > left_bytes)
370  av->consumption_since_last_update__ = -left_bytes;
371  else
372  av->consumption_since_last_update__ = -max_carry;
373  }
374 #if !defined(GNUNET_CULL_LOGGING)
375  {
376  struct GNUNET_TIME_Relative delta;
377 
378  delta.rel_value_us = delta_time;
380  "Tracker %p updated, consumption at %lld at %u Bps, last update was %s ago\n",
381  av,
382  (long long)av->consumption_since_last_update__,
383  (unsigned int)av->available_bytes_per_s__,
385  }
386 #endif
387 }
388 
389 
401 int
403  ssize_t size)
404 {
405  int64_t nc;
406 
408  "Tracker %p consumes %d bytes\n",
409  av,
410  (int)size);
411  if (size > 0)
412  {
414  if (nc < av->consumption_since_last_update__)
415  {
416  /* integer overflow, very bad */
417  GNUNET_break(0);
418  return GNUNET_SYSERR;
419  }
421  update_tracker(av);
422  update_excess(av);
424  {
426  "Tracker %p consumption %llu bytes above limit\n",
427  av,
428  (unsigned long long)av->consumption_since_last_update__);
429  return GNUNET_YES;
430  }
431  }
432  else
433  {
435  if (nc > av->consumption_since_last_update__)
436  {
437  /* integer underflow, very bad */
438  GNUNET_break(0);
439  return GNUNET_SYSERR;
440  }
442  update_excess(av);
443  }
444  return GNUNET_NO;
445 }
446 
447 
459  size_t size)
460 {
461  struct GNUNET_TIME_Relative ret;
462  int64_t bytes_needed;
463 
464  if (0 == av->available_bytes_per_s__)
465  {
466  LOG(GNUNET_ERROR_TYPE_DEBUG, "Tracker %p delay is infinity\n", av);
468  }
469  update_tracker(av);
470  bytes_needed = size + av->consumption_since_last_update__;
471  if (bytes_needed <= 0)
472  {
474  "Tracker %p delay for %u bytes is zero\n",
475  av,
476  (unsigned int)size);
477  return GNUNET_TIME_UNIT_ZERO;
478  }
479  ret.rel_value_us = (1000LL * 1000LL * bytes_needed) /
480  (unsigned long long)av->available_bytes_per_s__;
482  "Tracker %p delay for %u bytes is %s\n",
483  av,
484  (unsigned int)size,
486  return ret;
487 }
488 
489 
497 int64_t
499 {
500  struct GNUNET_BANDWIDTH_Value32NBO bps;
501  uint64_t avail;
502  int64_t used;
503 
504  update_tracker(av);
506  avail =
509  av->last_update__));
512  "Tracker %p available bandwidth is %lld bytes\n",
513  av,
514  (long long)(int64_t)(avail - used));
515  return (int64_t)(avail - used);
516 }
517 
518 
525 void
527  struct GNUNET_BANDWIDTH_Tracker *av,
528  struct GNUNET_BANDWIDTH_Value32NBO bytes_per_second_limit)
529 {
530  uint32_t old_limit;
531  uint32_t new_limit;
532 
533  new_limit = ntohl(bytes_per_second_limit.value__);
535  "Tracker %p bandwidth changed to %u Bps\n",
536  av,
537  (unsigned int)new_limit);
538  update_tracker(av);
539  old_limit = av->available_bytes_per_s__;
540  av->available_bytes_per_s__ = new_limit;
541  if (NULL != av->update_cb)
542  av->update_cb(av->update_cb_cls);
543  if (old_limit > new_limit)
544  update_tracker(av); /* maximum excess might be less now */
545  update_excess(av);
546 }
547 
548 
549 /* end of bandwidth.c */
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:402
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:302
uint64_t rel_value_us
The actual value.
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_tracker_update_quota(struct GNUNET_BANDWIDTH_Tracker *av, struct GNUNET_BANDWIDTH_Value32NBO bytes_per_second_limit)
Update quota of bandwidth tracker.
Definition: bandwidth.c:526
#define GNUNET_TIME_UNIT_SECONDS
One second.
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:498
struct GNUNET_SCHEDULER_Task * excess_task
Task scheduled to call the excess_cb once we have reached the maximum bandwidth the tracker can hold...
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
uint32_t max_carry_s__
Maximum number of seconds over which bandwidth may "accumulate".
Struct to track available bandwidth.
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
#define GNUNET_NO
Definition: gnunet_common.h:78
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:129
GNUNET_BANDWIDTH_ExcessNotificationCallback excess_cb
Function we call if the tracker is about to throw away bandwidth due to excess (max carry exceeded)...
static int ret
Final status code.
Definition: gnunet-arm.c:89
uint64_t abs_value_us
The actual value.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
uint32_t value__
The actual value (bytes per second).
struct GNUNET_TIME_Absolute last_update__
Time when we last updated the tracker.
void * update_cb_cls
Closure for update_cb.
void * excess_cb_cls
Closure for excess_cb.
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:1237
int64_t consumption_since_last_update__
Number of bytes consumed since we last updated the tracker.
#define GNUNET_MAX(a, b)
Definition: gnunet_common.h:82
#define GNUNET_MIN(a, b)
Definition: gnunet_common.h:80
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:686
#define LOG(kind,...)
Definition: bandwidth.c:30
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
void(* GNUNET_BANDWIDTH_TrackerUpdateCallback)(void *cls)
Callback to be called by the bandwidth tracker if the tracker was updated and the client should updat...
static void update_tracker(struct GNUNET_BANDWIDTH_Tracker *av)
Update the tracker, looking at the current time and bandwidth consumption data.
Definition: bandwidth.c:344
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:259
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_get(void)
Get the current time.
Definition: time.c:118
static void excess_trigger(void *cls)
Task run whenever we hit the bandwidth limit for a tracker.
Definition: bandwidth.c:157
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 &#39;size&#39; bytes of bandwidth in order to stay within the...
Definition: bandwidth.c:458
GNUNET_BANDWIDTH_TrackerUpdateCallback update_cb
Function we call if the tracker&#39;s bandwidth is increased and a previously returned timeout might now ...
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:104
#define GNUNET_SYSERR
Definition: gnunet_common.h:76
static struct GNUNET_PEERINFO_NotifyContext * nc
Iterator context.
static unsigned int size
Size of the "table".
Definition: peer.c:66
static void update_excess(struct GNUNET_BANDWIDTH_Tracker *av)
Recalculate when we might need to call the excess callback.
Definition: bandwidth.c:175
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
32-bit bandwidth used for network exchange by GNUnet, in bytes per second.
#define GNUNET_TIME_UNIT_ZERO
Relative time zero.
#define GNUNET_MAX_MESSAGE_SIZE
Largest supported message (to be precise, one byte more than the largest possible message...
uint32_t available_bytes_per_s__
Bandwidth limit to enforce in bytes per second.
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:373
void GNUNET_BANDWIDTH_tracker_notification_stop(struct GNUNET_BANDWIDTH_Tracker *av)
Stop notifying about tracker updates and excess notifications.
Definition: bandwidth.c:325
#define GNUNET_log(kind,...)
static struct GNUNET_TIME_Absolute deadline
Deadline for all consensuses.
Time for absolute times used by GNUnet, in microseconds.
#define GNUNET_YES
Definition: gnunet_common.h:77
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:499
Time for relative time used by GNUnet, in microseconds.
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:956