• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "quiche/quic/core/quic_idle_network_detector.h"
6 
7 #include "quiche/quic/core/quic_constants.h"
8 #include "quiche/quic/core/quic_time.h"
9 #include "quiche/quic/platform/api/quic_flag_utils.h"
10 #include "quiche/quic/platform/api/quic_flags.h"
11 #include "quiche/common/platform/api/quiche_logging.h"
12 
13 namespace quic {
14 
15 namespace {
16 
17 class AlarmDelegate : public QuicAlarm::DelegateWithContext {
18  public:
AlarmDelegate(QuicIdleNetworkDetector * detector,QuicConnectionContext * context)19   explicit AlarmDelegate(QuicIdleNetworkDetector* detector,
20                          QuicConnectionContext* context)
21       : QuicAlarm::DelegateWithContext(context), detector_(detector) {}
22   AlarmDelegate(const AlarmDelegate&) = delete;
23   AlarmDelegate& operator=(const AlarmDelegate&) = delete;
24 
OnAlarm()25   void OnAlarm() override { detector_->OnAlarm(); }
26 
27  private:
28   QuicIdleNetworkDetector* detector_;
29 };
30 
31 }  // namespace
32 
QuicIdleNetworkDetector(Delegate * delegate,QuicTime now,QuicConnectionArena * arena,QuicAlarmFactory * alarm_factory,QuicConnectionContext * context)33 QuicIdleNetworkDetector::QuicIdleNetworkDetector(
34     Delegate* delegate, QuicTime now, QuicConnectionArena* arena,
35     QuicAlarmFactory* alarm_factory, QuicConnectionContext* context)
36     : delegate_(delegate),
37       start_time_(now),
38       handshake_timeout_(QuicTime::Delta::Infinite()),
39       time_of_last_received_packet_(now),
40       time_of_first_packet_sent_after_receiving_(QuicTime::Zero()),
41       idle_network_timeout_(QuicTime::Delta::Infinite()),
42       bandwidth_update_timeout_(QuicTime::Delta::Infinite()),
43       alarm_(alarm_factory->CreateAlarm(
44           arena->New<AlarmDelegate>(this, context), arena)) {}
45 
OnAlarm()46 void QuicIdleNetworkDetector::OnAlarm() {
47   if (!bandwidth_update_timeout_.IsInfinite()) {
48     QUICHE_DCHECK(handshake_timeout_.IsInfinite());
49     bandwidth_update_timeout_ = QuicTime::Delta::Infinite();
50     SetAlarm();
51     delegate_->OnBandwidthUpdateTimeout();
52     return;
53   }
54   if (handshake_timeout_.IsInfinite()) {
55     delegate_->OnIdleNetworkDetected();
56     return;
57   }
58   if (idle_network_timeout_.IsInfinite()) {
59     delegate_->OnHandshakeTimeout();
60     return;
61   }
62   if (last_network_activity_time() + idle_network_timeout_ >
63       start_time_ + handshake_timeout_) {
64     delegate_->OnHandshakeTimeout();
65     return;
66   }
67   delegate_->OnIdleNetworkDetected();
68 }
69 
SetTimeouts(QuicTime::Delta handshake_timeout,QuicTime::Delta idle_network_timeout)70 void QuicIdleNetworkDetector::SetTimeouts(
71     QuicTime::Delta handshake_timeout, QuicTime::Delta idle_network_timeout) {
72   handshake_timeout_ = handshake_timeout;
73   idle_network_timeout_ = idle_network_timeout;
74   bandwidth_update_timeout_ = QuicTime::Delta::Infinite();
75 
76   if (GetQuicRestartFlag(
77           quic_enable_sending_bandwidth_estimate_when_network_idle_v2) &&
78       handshake_timeout_.IsInfinite()) {
79     QUIC_RESTART_FLAG_COUNT_N(
80         quic_enable_sending_bandwidth_estimate_when_network_idle_v2, 1, 3);
81     bandwidth_update_timeout_ = idle_network_timeout_ * 0.5;
82   }
83 
84   SetAlarm();
85 }
86 
StopDetection()87 void QuicIdleNetworkDetector::StopDetection() {
88   alarm_->PermanentCancel();
89   handshake_timeout_ = QuicTime::Delta::Infinite();
90   idle_network_timeout_ = QuicTime::Delta::Infinite();
91   handshake_timeout_ = QuicTime::Delta::Infinite();
92   stopped_ = true;
93 }
94 
OnPacketSent(QuicTime now,QuicTime::Delta pto_delay)95 void QuicIdleNetworkDetector::OnPacketSent(QuicTime now,
96                                            QuicTime::Delta pto_delay) {
97   if (time_of_first_packet_sent_after_receiving_ >
98       time_of_last_received_packet_) {
99     return;
100   }
101   time_of_first_packet_sent_after_receiving_ =
102       std::max(time_of_first_packet_sent_after_receiving_, now);
103   if (shorter_idle_timeout_on_sent_packet_) {
104     MaybeSetAlarmOnSentPacket(pto_delay);
105     return;
106   }
107 
108   SetAlarm();
109 }
110 
OnPacketReceived(QuicTime now)111 void QuicIdleNetworkDetector::OnPacketReceived(QuicTime now) {
112   time_of_last_received_packet_ = std::max(time_of_last_received_packet_, now);
113 
114   SetAlarm();
115 }
116 
SetAlarm()117 void QuicIdleNetworkDetector::SetAlarm() {
118   if (stopped_) {
119     // TODO(wub): If this QUIC_BUG fires, it indicates a problem in the
120     // QuicConnection, which somehow called this function while disconnected.
121     // That problem needs to be fixed.
122     QUIC_BUG(quic_idle_detector_set_alarm_after_stopped)
123         << "SetAlarm called after stopped";
124     return;
125   }
126   // Set alarm to the nearer deadline.
127   QuicTime new_deadline = QuicTime::Zero();
128   if (!handshake_timeout_.IsInfinite()) {
129     new_deadline = start_time_ + handshake_timeout_;
130   }
131   if (!idle_network_timeout_.IsInfinite()) {
132     const QuicTime idle_network_deadline = GetIdleNetworkDeadline();
133     if (new_deadline.IsInitialized()) {
134       new_deadline = std::min(new_deadline, idle_network_deadline);
135     } else {
136       new_deadline = idle_network_deadline;
137     }
138   }
139   if (!bandwidth_update_timeout_.IsInfinite()) {
140     new_deadline = std::min(new_deadline, GetBandwidthUpdateDeadline());
141   }
142   alarm_->Update(new_deadline, kAlarmGranularity);
143 }
144 
MaybeSetAlarmOnSentPacket(QuicTime::Delta pto_delay)145 void QuicIdleNetworkDetector::MaybeSetAlarmOnSentPacket(
146     QuicTime::Delta pto_delay) {
147   QUICHE_DCHECK(shorter_idle_timeout_on_sent_packet_);
148   if (!handshake_timeout_.IsInfinite() || !alarm_->IsSet()) {
149     SetAlarm();
150     return;
151   }
152   // Make sure connection will be alive for another PTO.
153   const QuicTime deadline = alarm_->deadline();
154   const QuicTime min_deadline = last_network_activity_time() + pto_delay;
155   if (deadline > min_deadline) {
156     return;
157   }
158   alarm_->Update(min_deadline, kAlarmGranularity);
159 }
160 
GetIdleNetworkDeadline() const161 QuicTime QuicIdleNetworkDetector::GetIdleNetworkDeadline() const {
162   if (idle_network_timeout_.IsInfinite()) {
163     return QuicTime::Zero();
164   }
165   return last_network_activity_time() + idle_network_timeout_;
166 }
167 
GetBandwidthUpdateDeadline() const168 QuicTime QuicIdleNetworkDetector::GetBandwidthUpdateDeadline() const {
169   QUICHE_DCHECK(!bandwidth_update_timeout_.IsInfinite());
170   return last_network_activity_time() + bandwidth_update_timeout_;
171 }
172 
173 }  // namespace quic
174