blob: 2d9fc2d3a619fdd3b432aacfe963954bc52c7320 [file] [log] [blame]
// 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