GNUnet 0.21.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
40GNUNET_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
96uint64_t
99 struct GNUNET_TIME_Relative deadline)
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;
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
149static void
150excess_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
167static void
169{
170 struct GNUNET_TIME_Relative delay;
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 */
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 */
209 delay = GNUNET_TIME_UNIT_ZERO;
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
251void
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
278void
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
301void
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
320static 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
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
367int
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{
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);
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
463int64_t
465{
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
491void
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
Final status code.
Definition: gnunet-arm.c:94
static struct GNUNET_NotificationContext * nc
Notification context for broadcasting to monitors.
#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.
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
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.
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.