| // Copyright (c) 2020 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "quic/core/quic_network_blackhole_detector.h" |
| |
| #include "quic/core/quic_constants.h" |
| |
| namespace quic { |
| |
| namespace { |
| |
| class AlarmDelegate : public QuicAlarm::DelegateWithContext { |
| public: |
| explicit AlarmDelegate(QuicNetworkBlackholeDetector* detector, |
| QuicConnectionContext* context) |
| : QuicAlarm::DelegateWithContext(context), detector_(detector) {} |
| AlarmDelegate(const AlarmDelegate&) = delete; |
| AlarmDelegate& operator=(const AlarmDelegate&) = delete; |
| |
| void OnAlarm() override { detector_->OnAlarm(); } |
| |
| private: |
| QuicNetworkBlackholeDetector* detector_; |
| }; |
| |
| } // namespace |
| |
| QuicNetworkBlackholeDetector::QuicNetworkBlackholeDetector( |
| Delegate* delegate, QuicConnectionArena* arena, |
| QuicAlarmFactory* alarm_factory, QuicConnectionContext* context) |
| : delegate_(delegate), |
| alarm_(alarm_factory->CreateAlarm( |
| arena->New<AlarmDelegate>(this, context), arena)) {} |
| |
| void QuicNetworkBlackholeDetector::OnAlarm() { |
| QuicTime next_deadline = GetEarliestDeadline(); |
| if (!next_deadline.IsInitialized()) { |
| QUIC_BUG(quic_bug_10328_1) << "BlackholeDetector alarm fired unexpectedly"; |
| return; |
| } |
| |
| QUIC_DVLOG(1) << "BlackholeDetector alarm firing. next_deadline:" |
| << next_deadline |
| << ", path_degrading_deadline_:" << path_degrading_deadline_ |
| << ", path_mtu_reduction_deadline_:" |
| << path_mtu_reduction_deadline_ |
| << ", blackhole_deadline_:" << blackhole_deadline_; |
| if (path_degrading_deadline_ == next_deadline) { |
| path_degrading_deadline_ = QuicTime::Zero(); |
| delegate_->OnPathDegradingDetected(); |
| } |
| |
| if (path_mtu_reduction_deadline_ == next_deadline) { |
| path_mtu_reduction_deadline_ = QuicTime::Zero(); |
| delegate_->OnPathMtuReductionDetected(); |
| } |
| |
| if (blackhole_deadline_ == next_deadline) { |
| blackhole_deadline_ = QuicTime::Zero(); |
| delegate_->OnBlackholeDetected(); |
| } |
| |
| UpdateAlarm(); |
| } |
| |
| void QuicNetworkBlackholeDetector::StopDetection(bool permanent) { |
| if (permanent) { |
| alarm_->PermanentCancel(); |
| } else { |
| alarm_->Cancel(); |
| } |
| path_degrading_deadline_ = QuicTime::Zero(); |
| blackhole_deadline_ = QuicTime::Zero(); |
| path_mtu_reduction_deadline_ = QuicTime::Zero(); |
| } |
| |
| void QuicNetworkBlackholeDetector::RestartDetection( |
| QuicTime path_degrading_deadline, |
| QuicTime blackhole_deadline, |
| QuicTime path_mtu_reduction_deadline) { |
| path_degrading_deadline_ = path_degrading_deadline; |
| blackhole_deadline_ = blackhole_deadline; |
| path_mtu_reduction_deadline_ = path_mtu_reduction_deadline; |
| |
| QUIC_BUG_IF(quic_bug_12708_1, blackhole_deadline_.IsInitialized() && |
| blackhole_deadline_ != GetLastDeadline()) |
| << "Blackhole detection deadline should be the last deadline."; |
| |
| UpdateAlarm(); |
| } |
| |
| QuicTime QuicNetworkBlackholeDetector::GetEarliestDeadline() const { |
| QuicTime result = QuicTime::Zero(); |
| for (QuicTime t : {path_degrading_deadline_, blackhole_deadline_, |
| path_mtu_reduction_deadline_}) { |
| if (!t.IsInitialized()) { |
| continue; |
| } |
| |
| if (!result.IsInitialized() || t < result) { |
| result = t; |
| } |
| } |
| |
| return result; |
| } |
| |
| QuicTime QuicNetworkBlackholeDetector::GetLastDeadline() const { |
| return std::max({path_degrading_deadline_, blackhole_deadline_, |
| path_mtu_reduction_deadline_}); |
| } |
| |
| void QuicNetworkBlackholeDetector::UpdateAlarm() const { |
| // If called after OnBlackholeDetected(), the alarm may have been permanently |
| // cancelled and is not safe to be armed again. |
| if (alarm_->IsPermanentlyCancelled()) { |
| return; |
| } |
| |
| QuicTime next_deadline = GetEarliestDeadline(); |
| |
| QUIC_DVLOG(1) << "Updating alarm. next_deadline:" << next_deadline |
| << ", path_degrading_deadline_:" << path_degrading_deadline_ |
| << ", path_mtu_reduction_deadline_:" |
| << path_mtu_reduction_deadline_ |
| << ", blackhole_deadline_:" << blackhole_deadline_; |
| |
| alarm_->Update(next_deadline, kAlarmGranularity); |
| } |
| |
| bool QuicNetworkBlackholeDetector::IsDetectionInProgress() const { |
| return alarm_->IsSet(); |
| } |
| |
| } // namespace quic |