Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/base/backoff_entry.h" | 5 #include "net/base/backoff_entry.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <cmath> | 8 #include <cmath> |
| 9 #include <limits> | 9 #include <limits> |
| 10 | 10 |
| 11 #include "base/basictypes.h" | |
| 11 #include "base/logging.h" | 12 #include "base/logging.h" |
| 13 #include "base/numerics/safe_math.h" | |
| 12 #include "base/rand_util.h" | 14 #include "base/rand_util.h" |
| 13 | 15 |
| 14 namespace net { | 16 namespace net { |
| 15 | 17 |
| 16 BackoffEntry::BackoffEntry(const BackoffEntry::Policy* const policy) | 18 BackoffEntry::BackoffEntry(const BackoffEntry::Policy* const policy) |
| 17 : policy_(policy) { | 19 : policy_(policy) { |
| 18 DCHECK(policy_); | 20 DCHECK(policy_); |
| 19 Reset(); | 21 Reset(); |
| 20 } | 22 } |
| 21 | 23 |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 125 | 127 |
| 126 if (effective_failure_count == 0) { | 128 if (effective_failure_count == 0) { |
| 127 // Never reduce previously set release horizon, e.g. due to Retry-After | 129 // Never reduce previously set release horizon, e.g. due to Retry-After |
| 128 // header. | 130 // header. |
| 129 return std::max(ImplGetTimeNow(), exponential_backoff_release_time_); | 131 return std::max(ImplGetTimeNow(), exponential_backoff_release_time_); |
| 130 } | 132 } |
| 131 | 133 |
| 132 // The delay is calculated with this formula: | 134 // The delay is calculated with this formula: |
| 133 // delay = initial_backoff * multiply_factor^( | 135 // delay = initial_backoff * multiply_factor^( |
| 134 // effective_failure_count - 1) * Uniform(1 - jitter_factor, 1] | 136 // effective_failure_count - 1) * Uniform(1 - jitter_factor, 1] |
| 135 double delay = policy_->initial_delay_ms; | 137 // Note: if the failure count is too high, |delay_ms| will become infinity |
| 136 delay *= pow(policy_->multiply_factor, effective_failure_count - 1); | 138 // after the exponential calculation, and then NaN after the jitter is |
| 137 delay -= base::RandDouble() * policy_->jitter_factor * delay; | 139 // accounted for. Both cases are handled by using CheckedNumeric<int64> to |
| 140 // perform the conversion to integers. | |
| 141 double delay_ms = policy_->initial_delay_ms; | |
| 142 delay_ms *= pow(policy_->multiply_factor, effective_failure_count - 1); | |
| 143 delay_ms -= base::RandDouble() * policy_->jitter_factor * delay_ms; | |
| 138 | 144 |
| 139 const int64 kMaxInt64 = std::numeric_limits<int64>::max(); | 145 // Do overflow checking in microseconds, the internal unit of TimeTicks. |
| 140 int64 delay_int = (delay > kMaxInt64) ? | 146 const int64 kTimeTicksNowUs = |
| 141 kMaxInt64 : static_cast<int64>(delay + 0.5); | 147 (ImplGetTimeNow() - base::TimeTicks()).InMicroseconds(); |
| 148 base::internal::CheckedNumeric<int64> checked_release_time_us = | |
|
cbentzel
2014/06/16 21:08:32
NaN to integer conversion is undefined, not sure i
Nicolas Zea
2014/06/17 00:33:29
CheckedNumeric, from my understanding of the code,
Ryan Sleevi
2014/06/17 20:02:12
I believe Nicolas is correct.
That is, it invokes
| |
| 149 delay_ms + 0.5; | |
| 150 checked_release_time_us *= base::Time::kMicrosecondsPerMillisecond; | |
| 151 checked_release_time_us += kTimeTicksNowUs; | |
| 142 | 152 |
| 143 // Ensure that we do not exceed maximum delay. | 153 // Ensure that we do not exceed maximum delay once overflow is accounted for. |
| 144 if (policy_->maximum_backoff_ms >= 0) | 154 int64 release_time_us = (policy_->maximum_backoff_ms >= 0 |
| 145 delay_int = std::min(delay_int, policy_->maximum_backoff_ms); | 155 ? kTimeTicksNowUs + |
| 156 base::Time::kMicrosecondsPerMillisecond * | |
| 157 policy_->maximum_backoff_ms | |
|
Ryan Sleevi
2014/06/16 22:12:47
Can't this still overflow?
Nicolas Zea
2014/06/17 00:33:29
Hmm, I suppose if a developer gives a massive/inva
Ryan Sleevi
2014/06/17 20:02:12
*shrug* I agree, it's likely an error in policy, b
Nicolas Zea
2014/06/17 21:31:43
Done.
| |
| 158 : kint64max); | |
| 159 release_time_us = | |
| 160 std::min(checked_release_time_us.ValueOrDefault(release_time_us), | |
| 161 release_time_us); | |
| 146 | 162 |
| 147 // Never reduce previously set release horizon, e.g. due to Retry-After | 163 // Never reduce previously set release horizon, e.g. due to Retry-After |
| 148 // header. | 164 // header. |
| 149 return std::max( | 165 return std::max( |
| 150 ImplGetTimeNow() + base::TimeDelta::FromMilliseconds(delay_int), | 166 base::TimeTicks() + base::TimeDelta::FromMicroseconds(release_time_us), |
|
Ryan Sleevi
2014/06/16 22:12:47
Can't this still overflow?
Nicolas Zea
2014/06/17 00:33:29
base::TimeTicks() is a 0 value, this is just for c
| |
| 151 exponential_backoff_release_time_); | 167 exponential_backoff_release_time_); |
| 152 } | 168 } |
| 153 | 169 |
| 154 } // namespace net | 170 } // namespace net |
| OLD | NEW |