aboutsummaryrefslogtreecommitdiff
path: root/src/util/bandwidth.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2016-07-26 12:00:14 +0000
committerChristian Grothoff <christian@grothoff.org>2016-07-26 12:00:14 +0000
commit874f5684e15a99d6ed4316088d33dca55f484c33 (patch)
tree323c35ba000fd07e456d0a89464c54d756ff7b3b /src/util/bandwidth.c
parentbbcfaabced541509ee15cadffa018105d4410ae8 (diff)
downloadgnunet-874f5684e15a99d6ed4316088d33dca55f484c33.tar.gz
gnunet-874f5684e15a99d6ed4316088d33dca55f484c33.zip
fix overflow/underflow handling in tracker to properly handle large bandwidths
Diffstat (limited to 'src/util/bandwidth.c')
-rw-r--r--src/util/bandwidth.c66
1 files changed, 48 insertions, 18 deletions
diff --git a/src/util/bandwidth.c b/src/util/bandwidth.c
index bc5c02d60..61677fdcf 100644
--- a/src/util/bandwidth.c
+++ b/src/util/bandwidth.c
@@ -40,9 +40,6 @@ GNUNET_BANDWIDTH_value_init (uint32_t bytes_per_second)
40{ 40{
41 struct GNUNET_BANDWIDTH_Value32NBO ret; 41 struct GNUNET_BANDWIDTH_Value32NBO ret;
42 42
43 LOG (GNUNET_ERROR_TYPE_DEBUG,
44 "Initializing bandwidth of %u Bps\n",
45 (unsigned int) bytes_per_second);
46 ret.value__ = htonl (bytes_per_second); 43 ret.value__ = htonl (bytes_per_second);
47 return ret; 44 return ret;
48} 45}
@@ -176,11 +173,23 @@ update_excess (struct GNUNET_BANDWIDTH_Tracker *av)
176 (delta_time * ((unsigned long long) av->available_bytes_per_s__) + 173 (delta_time * ((unsigned long long) av->available_bytes_per_s__) +
177 500000LL) / 1000000LL; 174 500000LL) / 1000000LL;
178 current_consumption = av->consumption_since_last_update__ - delta_avail; 175 current_consumption = av->consumption_since_last_update__ - delta_avail;
176 if (current_consumption > av->consumption_since_last_update__)
177 {
178 /* integer underflow, cap! */
179 current_consumption = INT64_MIN;
180 }
179 /* negative current_consumption means that we have savings */ 181 /* negative current_consumption means that we have savings */
180 max_carry = (uint64_t) av->available_bytes_per_s__ * av->max_carry_s__; 182 max_carry = ((uint64_t) av->available_bytes_per_s__) * av->max_carry_s__;
181 if (max_carry < GNUNET_SERVER_MAX_MESSAGE_SIZE) 183 if (max_carry < GNUNET_SERVER_MAX_MESSAGE_SIZE)
182 max_carry = GNUNET_SERVER_MAX_MESSAGE_SIZE; 184 max_carry = GNUNET_SERVER_MAX_MESSAGE_SIZE;
183 left_bytes = max_carry + current_consumption; 185 if (max_carry > INT64_MAX)
186 max_carry = INT64_MAX;
187 left_bytes = current_consumption + max_carry;
188 if (left_bytes < current_consumption)
189 {
190 /* integer overflow, cap! */
191 left_bytes = INT64_MAX;
192 }
184 /* left_bytes now contains the number of bytes needed until 193 /* left_bytes now contains the number of bytes needed until
185 we have more savings than allowed */ 194 we have more savings than allowed */
186 if (left_bytes < 0) 195 if (left_bytes < 0)
@@ -195,6 +204,12 @@ update_excess (struct GNUNET_BANDWIDTH_Tracker *av)
195 delay = GNUNET_TIME_relative_divide (delay, 204 delay = GNUNET_TIME_relative_divide (delay,
196 av->available_bytes_per_s__); 205 av->available_bytes_per_s__);
197 } 206 }
207 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
208 "At %llu bps it will take us %s for %lld bytes to reach excess threshold\n",
209 (unsigned long long) av->available_bytes_per_s__,
210 GNUNET_STRINGS_relative_time_to_string (delay,
211 GNUNET_NO),
212 (long long) left_bytes);
198 if (NULL != av->excess_task) 213 if (NULL != av->excess_task)
199 GNUNET_SCHEDULER_cancel (av->excess_task); 214 GNUNET_SCHEDULER_cancel (av->excess_task);
200 av->excess_task = GNUNET_SCHEDULER_add_delayed (delay, 215 av->excess_task = GNUNET_SCHEDULER_add_delayed (delay,
@@ -253,10 +268,10 @@ GNUNET_BANDWIDTH_tracker_init2 (struct GNUNET_BANDWIDTH_Tracker *av,
253/** 268/**
254 * Initialize bandwidth tracker. Note that in addition to the 269 * Initialize bandwidth tracker. Note that in addition to the
255 * 'max_carry_s' limit, we also always allow at least 270 * 'max_carry_s' limit, we also always allow at least
256 * GNUNET_SERVER_MAX_MESSAGE_SIZE to accumulate. So if the 271 * #GNUNET_SERVER_MAX_MESSAGE_SIZE to accumulate. So if the
257 * bytes-per-second limit is so small that within 'max_carry_s' not 272 * bytes-per-second limit is so small that within 'max_carry_s' not
258 * even GNUNET_SERVER_MAX_MESSAGE_SIZE is allowed to accumulate, it is 273 * even #GNUNET_SERVER_MAX_MESSAGE_SIZE is allowed to accumulate, it is
259 * ignored and replaced by GNUNET_SERVER_MAX_MESSAGE_SIZE (which is in 274 * ignored and replaced by #GNUNET_SERVER_MAX_MESSAGE_SIZE (which is in
260 * bytes). 275 * bytes).
261 * 276 *
262 * @param av tracker to initialize 277 * @param av tracker to initialize
@@ -299,7 +314,6 @@ GNUNET_BANDWIDTH_tracker_notification_stop (struct GNUNET_BANDWIDTH_Tracker *av)
299} 314}
300 315
301 316
302
303/** 317/**
304 * Update the tracker, looking at the current time and 318 * Update the tracker, looking at the current time and
305 * bandwidth consumption data. 319 * bandwidth consumption data.
@@ -325,20 +339,26 @@ update_tracker (struct GNUNET_BANDWIDTH_Tracker *av)
325 av->last_update__ = now; 339 av->last_update__ = now;
326 if (av->consumption_since_last_update__ < 0) 340 if (av->consumption_since_last_update__ < 0)
327 { 341 {
328 left_bytes = -av->consumption_since_last_update__; 342 left_bytes = - av->consumption_since_last_update__;
329 max_carry = av->available_bytes_per_s__ * av->max_carry_s__; 343 max_carry = ((unsigned long long) av->available_bytes_per_s__) *
344 av->max_carry_s__;
330 if (max_carry < GNUNET_SERVER_MAX_MESSAGE_SIZE) 345 if (max_carry < GNUNET_SERVER_MAX_MESSAGE_SIZE)
331 max_carry = GNUNET_SERVER_MAX_MESSAGE_SIZE; 346 max_carry = GNUNET_SERVER_MAX_MESSAGE_SIZE;
347 if (max_carry > INT64_MAX)
348 max_carry = INT64_MAX;
332 if (max_carry > left_bytes) 349 if (max_carry > left_bytes)
333 av->consumption_since_last_update__ = -left_bytes; 350 av->consumption_since_last_update__ = - left_bytes;
334 else 351 else
335 av->consumption_since_last_update__ = -max_carry; 352 av->consumption_since_last_update__ = - max_carry;
336 } 353 }
337 delta.rel_value_us = delta_time; 354 delta.rel_value_us = delta_time;
338 LOG (GNUNET_ERROR_TYPE_DEBUG, 355 LOG (GNUNET_ERROR_TYPE_DEBUG,
339 "Tracker %p updated, have %u Bps, last update was %s ago\n", av, 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__,
340 (unsigned int) av->available_bytes_per_s__, 359 (unsigned int) av->available_bytes_per_s__,
341 GNUNET_STRINGS_relative_time_to_string (delta, GNUNET_YES)); 360 GNUNET_STRINGS_relative_time_to_string (delta,
361 GNUNET_YES));
342} 362}
343 363
344 364
@@ -368,6 +388,7 @@ GNUNET_BANDWIDTH_tracker_consume (struct GNUNET_BANDWIDTH_Tracker *av,
368 nc = av->consumption_since_last_update__ + size; 388 nc = av->consumption_since_last_update__ + size;
369 if (nc < av->consumption_since_last_update__) 389 if (nc < av->consumption_since_last_update__)
370 { 390 {
391 /* integer overflow, very bad */
371 GNUNET_break (0); 392 GNUNET_break (0);
372 return GNUNET_SYSERR; 393 return GNUNET_SYSERR;
373 } 394 }
@@ -377,14 +398,22 @@ GNUNET_BANDWIDTH_tracker_consume (struct GNUNET_BANDWIDTH_Tracker *av,
377 if (av->consumption_since_last_update__ > 0) 398 if (av->consumption_since_last_update__ > 0)
378 { 399 {
379 LOG (GNUNET_ERROR_TYPE_DEBUG, 400 LOG (GNUNET_ERROR_TYPE_DEBUG,
380 "Tracker %p consumption %llu bytes above limit\n", av, 401 "Tracker %p consumption %llu bytes above limit\n",
402 av,
381 (unsigned long long) av->consumption_since_last_update__); 403 (unsigned long long) av->consumption_since_last_update__);
382 return GNUNET_YES; 404 return GNUNET_YES;
383 } 405 }
384 } 406 }
385 else 407 else
386 { 408 {
387 av->consumption_since_last_update__ += size; 409 nc = av->consumption_since_last_update__ + size;
410 if (nc > av->consumption_since_last_update__)
411 {
412 /* integer underflow, very bad */
413 GNUNET_break (0);
414 return GNUNET_SYSERR;
415 }
416 av->consumption_since_last_update__ = nc;
388 update_excess (av); 417 update_excess (av);
389 } 418 }
390 return GNUNET_NO; 419 return GNUNET_NO;
@@ -427,7 +456,8 @@ GNUNET_BANDWIDTH_tracker_get_delay (struct GNUNET_BANDWIDTH_Tracker *av,
427 (unsigned long long) av->available_bytes_per_s__; 456 (unsigned long long) av->available_bytes_per_s__;
428 LOG (GNUNET_ERROR_TYPE_DEBUG, 457 LOG (GNUNET_ERROR_TYPE_DEBUG,
429 "Tracker %p delay for %u bytes is %s\n", 458 "Tracker %p delay for %u bytes is %s\n",
430 av, (unsigned int) size, 459 av,
460 (unsigned int) size,
431 GNUNET_STRINGS_relative_time_to_string (ret, GNUNET_YES)); 461 GNUNET_STRINGS_relative_time_to_string (ret, GNUNET_YES));
432 return ret; 462 return ret;
433} 463}