diff options
author | Christian Grothoff <christian@grothoff.org> | 2016-07-26 12:00:14 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2016-07-26 12:00:14 +0000 |
commit | 874f5684e15a99d6ed4316088d33dca55f484c33 (patch) | |
tree | 323c35ba000fd07e456d0a89464c54d756ff7b3b /src/util/bandwidth.c | |
parent | bbcfaabced541509ee15cadffa018105d4410ae8 (diff) | |
download | gnunet-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.c | 66 |
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 | } |