• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2022 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_ping_manager.h"
6 
7 #include "quiche/quic/core/quic_one_block_arena.h"
8 #include "quiche/quic/platform/api/quic_test.h"
9 #include "quiche/quic/test_tools/quic_test_utils.h"
10 
11 namespace quic {
12 namespace test {
13 
14 class QuicPingManagerPeer {
15  public:
GetAlarm(QuicPingManager * manager)16   static QuicAlarm* GetAlarm(QuicPingManager* manager) {
17     return manager->alarm_.get();
18   }
19 
SetPerspective(QuicPingManager * manager,Perspective perspective)20   static void SetPerspective(QuicPingManager* manager,
21                              Perspective perspective) {
22     manager->perspective_ = perspective;
23   }
24 };
25 
26 namespace {
27 
28 const bool kShouldKeepAlive = true;
29 const bool kHasInflightPackets = true;
30 
31 class MockDelegate : public QuicPingManager::Delegate {
32  public:
33   MOCK_METHOD(void, OnKeepAliveTimeout, (), (override));
34   MOCK_METHOD(void, OnRetransmittableOnWireTimeout, (), (override));
35 };
36 
37 class QuicPingManagerTest : public QuicTest {
38  public:
QuicPingManagerTest()39   QuicPingManagerTest()
40       : manager_(Perspective::IS_CLIENT, &delegate_, &arena_, &alarm_factory_,
41                  /*context=*/nullptr),
42         alarm_(static_cast<MockAlarmFactory::TestAlarm*>(
43             QuicPingManagerPeer::GetAlarm(&manager_))) {
44     clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
45   }
46 
47  protected:
48   testing::StrictMock<MockDelegate> delegate_;
49   MockClock clock_;
50   QuicConnectionArena arena_;
51   MockAlarmFactory alarm_factory_;
52   QuicPingManager manager_;
53   MockAlarmFactory::TestAlarm* alarm_;
54 };
55 
TEST_F(QuicPingManagerTest,KeepAliveTimeout)56 TEST_F(QuicPingManagerTest, KeepAliveTimeout) {
57   EXPECT_FALSE(alarm_->IsSet());
58 
59   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
60   // Set alarm with in flight packets.
61   manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
62                     kHasInflightPackets);
63   EXPECT_TRUE(alarm_->IsSet());
64   EXPECT_EQ(QuicTime::Delta::FromSeconds(kPingTimeoutSecs),
65             alarm_->deadline() - clock_.ApproximateNow());
66 
67   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
68   // Reset alarm with no in flight packets.
69   manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
70                     !kHasInflightPackets);
71   EXPECT_TRUE(alarm_->IsSet());
72   // Verify the deadline is set slightly less than 15 seconds in the future,
73   // because of the 1s alarm granularity.
74   EXPECT_EQ(QuicTime::Delta::FromSeconds(kPingTimeoutSecs) -
75                 QuicTime::Delta::FromMilliseconds(5),
76             alarm_->deadline() - clock_.ApproximateNow());
77 
78   clock_.AdvanceTime(QuicTime::Delta::FromSeconds(kPingTimeoutSecs));
79   EXPECT_CALL(delegate_, OnKeepAliveTimeout());
80   alarm_->Fire();
81   EXPECT_FALSE(alarm_->IsSet());
82   // Reset alarm with in flight packets.
83   manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
84                     kHasInflightPackets);
85   EXPECT_TRUE(alarm_->IsSet());
86 
87   // Verify alarm is not armed if !kShouldKeepAlive.
88   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
89   manager_.SetAlarm(clock_.ApproximateNow(), !kShouldKeepAlive,
90                     kHasInflightPackets);
91   EXPECT_FALSE(alarm_->IsSet());
92 }
93 
TEST_F(QuicPingManagerTest,CustomizedKeepAliveTimeout)94 TEST_F(QuicPingManagerTest, CustomizedKeepAliveTimeout) {
95   EXPECT_FALSE(alarm_->IsSet());
96 
97   // Set customized keep-alive timeout.
98   manager_.set_keep_alive_timeout(QuicTime::Delta::FromSeconds(10));
99 
100   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
101   // Set alarm with in flight packets.
102   manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
103                     kHasInflightPackets);
104   EXPECT_TRUE(alarm_->IsSet());
105   EXPECT_EQ(QuicTime::Delta::FromSeconds(10),
106             alarm_->deadline() - clock_.ApproximateNow());
107 
108   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
109   // Set alarm with no in flight packets.
110   manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
111                     !kHasInflightPackets);
112   EXPECT_TRUE(alarm_->IsSet());
113   // The deadline is set slightly less than 10 seconds in the future, because
114   // of the 1s alarm granularity.
115   EXPECT_EQ(
116       QuicTime::Delta::FromSeconds(10) - QuicTime::Delta::FromMilliseconds(5),
117       alarm_->deadline() - clock_.ApproximateNow());
118 
119   clock_.AdvanceTime(QuicTime::Delta::FromSeconds(10));
120   EXPECT_CALL(delegate_, OnKeepAliveTimeout());
121   alarm_->Fire();
122   EXPECT_FALSE(alarm_->IsSet());
123   // Reset alarm with in flight packets.
124   manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
125                     kHasInflightPackets);
126   EXPECT_TRUE(alarm_->IsSet());
127 
128   // Verify alarm is not armed if !kShouldKeepAlive.
129   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
130   manager_.SetAlarm(clock_.ApproximateNow(), !kShouldKeepAlive,
131                     kHasInflightPackets);
132   EXPECT_FALSE(alarm_->IsSet());
133 }
134 
TEST_F(QuicPingManagerTest,RetransmittableOnWireTimeout)135 TEST_F(QuicPingManagerTest, RetransmittableOnWireTimeout) {
136   const QuicTime::Delta kRtransmittableOnWireTimeout =
137       QuicTime::Delta::FromMilliseconds(50);
138   manager_.set_initial_retransmittable_on_wire_timeout(
139       kRtransmittableOnWireTimeout);
140 
141   EXPECT_FALSE(alarm_->IsSet());
142 
143   // Set alarm with in flight packets.
144   manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
145                     kHasInflightPackets);
146   // Verify alarm is in keep-alive mode.
147   EXPECT_TRUE(alarm_->IsSet());
148   EXPECT_EQ(QuicTime::Delta::FromSeconds(kPingTimeoutSecs),
149             alarm_->deadline() - clock_.ApproximateNow());
150 
151   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
152   // Set alarm with no in flight packets.
153   manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
154                     !kHasInflightPackets);
155   EXPECT_TRUE(alarm_->IsSet());
156   // Verify alarm is in retransmittable-on-wire mode.
157   EXPECT_EQ(kRtransmittableOnWireTimeout,
158             alarm_->deadline() - clock_.ApproximateNow());
159 
160   clock_.AdvanceTime(kRtransmittableOnWireTimeout);
161   EXPECT_CALL(delegate_, OnRetransmittableOnWireTimeout());
162   alarm_->Fire();
163   EXPECT_FALSE(alarm_->IsSet());
164   // Reset alarm with in flight packets.
165   manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
166                     kHasInflightPackets);
167   // Verify the alarm is in keep-alive mode.
168   ASSERT_TRUE(alarm_->IsSet());
169   EXPECT_EQ(QuicTime::Delta::FromSeconds(kPingTimeoutSecs),
170             alarm_->deadline() - clock_.ApproximateNow());
171 }
172 
TEST_F(QuicPingManagerTest,RetransmittableOnWireTimeoutExponentiallyBackOff)173 TEST_F(QuicPingManagerTest, RetransmittableOnWireTimeoutExponentiallyBackOff) {
174   const int kMaxAggressiveRetransmittableOnWireCount = 5;
175   SetQuicFlag(quic_max_aggressive_retransmittable_on_wire_ping_count,
176               kMaxAggressiveRetransmittableOnWireCount);
177   const QuicTime::Delta initial_retransmittable_on_wire_timeout =
178       QuicTime::Delta::FromMilliseconds(200);
179   manager_.set_initial_retransmittable_on_wire_timeout(
180       initial_retransmittable_on_wire_timeout);
181 
182   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
183   EXPECT_FALSE(alarm_->IsSet());
184   manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
185                     kHasInflightPackets);
186   // Verify alarm is in keep-alive mode.
187   EXPECT_TRUE(alarm_->IsSet());
188   EXPECT_EQ(QuicTime::Delta::FromSeconds(kPingTimeoutSecs),
189             alarm_->deadline() - clock_.ApproximateNow());
190 
191   // Verify no exponential backoff on the first few retransmittable on wire
192   // timeouts.
193   for (int i = 0; i <= kMaxAggressiveRetransmittableOnWireCount; ++i) {
194     clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
195     // Reset alarm with no in flight packets.
196     manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
197                       !kHasInflightPackets);
198     EXPECT_TRUE(alarm_->IsSet());
199     // Verify alarm is in retransmittable-on-wire mode.
200     EXPECT_EQ(initial_retransmittable_on_wire_timeout,
201               alarm_->deadline() - clock_.ApproximateNow());
202     clock_.AdvanceTime(initial_retransmittable_on_wire_timeout);
203     EXPECT_CALL(delegate_, OnRetransmittableOnWireTimeout());
204     alarm_->Fire();
205     EXPECT_FALSE(alarm_->IsSet());
206     // Reset alarm with in flight packets.
207     manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
208                       kHasInflightPackets);
209   }
210 
211   QuicTime::Delta retransmittable_on_wire_timeout =
212       initial_retransmittable_on_wire_timeout;
213 
214   // Verify subsequent retransmittable-on-wire timeout is exponentially backed
215   // off.
216   while (retransmittable_on_wire_timeout * 2 <
217          QuicTime::Delta::FromSeconds(kPingTimeoutSecs)) {
218     retransmittable_on_wire_timeout = retransmittable_on_wire_timeout * 2;
219     clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
220     manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
221                       !kHasInflightPackets);
222     EXPECT_TRUE(alarm_->IsSet());
223     EXPECT_EQ(retransmittable_on_wire_timeout,
224               alarm_->deadline() - clock_.ApproximateNow());
225 
226     clock_.AdvanceTime(retransmittable_on_wire_timeout);
227     EXPECT_CALL(delegate_, OnRetransmittableOnWireTimeout());
228     alarm_->Fire();
229     EXPECT_FALSE(alarm_->IsSet());
230     // Reset alarm with in flight packets.
231     manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
232                       kHasInflightPackets);
233   }
234 
235   // Verify alarm is in keep-alive mode.
236   EXPECT_TRUE(alarm_->IsSet());
237   EXPECT_EQ(QuicTime::Delta::FromSeconds(kPingTimeoutSecs),
238             alarm_->deadline() - clock_.ApproximateNow());
239 
240   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
241   // Reset alarm with no in flight packets
242   manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
243                     !kHasInflightPackets);
244   EXPECT_TRUE(alarm_->IsSet());
245   // Verify alarm is in keep-alive mode because retransmittable-on-wire deadline
246   // is later.
247   EXPECT_EQ(QuicTime::Delta::FromSeconds(kPingTimeoutSecs) -
248                 QuicTime::Delta::FromMilliseconds(5),
249             alarm_->deadline() - clock_.ApproximateNow());
250   clock_.AdvanceTime(QuicTime::Delta::FromSeconds(kPingTimeoutSecs) -
251                      QuicTime::Delta::FromMilliseconds(5));
252   EXPECT_CALL(delegate_, OnKeepAliveTimeout());
253   alarm_->Fire();
254   EXPECT_FALSE(alarm_->IsSet());
255 }
256 
TEST_F(QuicPingManagerTest,ResetRetransmitableOnWireTimeoutExponentiallyBackOff)257 TEST_F(QuicPingManagerTest,
258        ResetRetransmitableOnWireTimeoutExponentiallyBackOff) {
259   const int kMaxAggressiveRetransmittableOnWireCount = 3;
260   SetQuicFlag(quic_max_aggressive_retransmittable_on_wire_ping_count,
261               kMaxAggressiveRetransmittableOnWireCount);
262   const QuicTime::Delta initial_retransmittable_on_wire_timeout =
263       QuicTime::Delta::FromMilliseconds(200);
264   manager_.set_initial_retransmittable_on_wire_timeout(
265       initial_retransmittable_on_wire_timeout);
266 
267   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
268   EXPECT_FALSE(alarm_->IsSet());
269   manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
270                     kHasInflightPackets);
271   // Verify alarm is in keep-alive mode.
272   EXPECT_TRUE(alarm_->IsSet());
273   EXPECT_EQ(QuicTime::Delta::FromSeconds(kPingTimeoutSecs),
274             alarm_->deadline() - clock_.ApproximateNow());
275 
276   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
277   manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
278                     !kHasInflightPackets);
279   EXPECT_TRUE(alarm_->IsSet());
280   // Verify alarm is in retransmittable-on-wire mode.
281   EXPECT_EQ(initial_retransmittable_on_wire_timeout,
282             alarm_->deadline() - clock_.ApproximateNow());
283 
284   EXPECT_CALL(delegate_, OnRetransmittableOnWireTimeout());
285   clock_.AdvanceTime(initial_retransmittable_on_wire_timeout);
286   alarm_->Fire();
287 
288   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
289   manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
290                     !kHasInflightPackets);
291   EXPECT_TRUE(alarm_->IsSet());
292   EXPECT_EQ(initial_retransmittable_on_wire_timeout,
293             alarm_->deadline() - clock_.ApproximateNow());
294 
295   manager_.reset_consecutive_retransmittable_on_wire_count();
296   manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
297                     !kHasInflightPackets);
298   EXPECT_EQ(initial_retransmittable_on_wire_timeout,
299             alarm_->deadline() - clock_.ApproximateNow());
300   EXPECT_CALL(delegate_, OnRetransmittableOnWireTimeout());
301   clock_.AdvanceTime(initial_retransmittable_on_wire_timeout);
302   alarm_->Fire();
303 
304   for (int i = 0; i < kMaxAggressiveRetransmittableOnWireCount; i++) {
305     manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
306                       !kHasInflightPackets);
307     EXPECT_TRUE(alarm_->IsSet());
308     EXPECT_EQ(initial_retransmittable_on_wire_timeout,
309               alarm_->deadline() - clock_.ApproximateNow());
310     clock_.AdvanceTime(initial_retransmittable_on_wire_timeout);
311     EXPECT_CALL(delegate_, OnRetransmittableOnWireTimeout());
312     alarm_->Fire();
313     // Reset alarm with in flight packets.
314     manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
315                       kHasInflightPackets);
316     // Advance 5ms to receive next packet.
317     clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
318   }
319 
320   manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
321                     !kHasInflightPackets);
322   EXPECT_TRUE(alarm_->IsSet());
323   EXPECT_EQ(initial_retransmittable_on_wire_timeout * 2,
324             alarm_->deadline() - clock_.ApproximateNow());
325 
326   clock_.AdvanceTime(2 * initial_retransmittable_on_wire_timeout);
327   EXPECT_CALL(delegate_, OnRetransmittableOnWireTimeout());
328   alarm_->Fire();
329 
330   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
331   manager_.reset_consecutive_retransmittable_on_wire_count();
332   manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
333                     !kHasInflightPackets);
334   EXPECT_TRUE(alarm_->IsSet());
335   EXPECT_EQ(initial_retransmittable_on_wire_timeout,
336             alarm_->deadline() - clock_.ApproximateNow());
337 }
338 
TEST_F(QuicPingManagerTest,RetransmittableOnWireLimit)339 TEST_F(QuicPingManagerTest, RetransmittableOnWireLimit) {
340   static constexpr int kMaxRetransmittableOnWirePingCount = 3;
341   SetQuicFlag(quic_max_retransmittable_on_wire_ping_count,
342               kMaxRetransmittableOnWirePingCount);
343   static constexpr QuicTime::Delta initial_retransmittable_on_wire_timeout =
344       QuicTime::Delta::FromMilliseconds(200);
345   static constexpr QuicTime::Delta kShortDelay =
346       QuicTime::Delta::FromMilliseconds(5);
347   ASSERT_LT(kShortDelay * 10, initial_retransmittable_on_wire_timeout);
348   manager_.set_initial_retransmittable_on_wire_timeout(
349       initial_retransmittable_on_wire_timeout);
350 
351   clock_.AdvanceTime(kShortDelay);
352   EXPECT_FALSE(alarm_->IsSet());
353   manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
354                     kHasInflightPackets);
355 
356   EXPECT_TRUE(alarm_->IsSet());
357   EXPECT_EQ(QuicTime::Delta::FromSeconds(kPingTimeoutSecs),
358             alarm_->deadline() - clock_.ApproximateNow());
359 
360   for (int i = 0; i <= kMaxRetransmittableOnWirePingCount; i++) {
361     clock_.AdvanceTime(kShortDelay);
362     manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
363                       !kHasInflightPackets);
364     EXPECT_TRUE(alarm_->IsSet());
365     EXPECT_EQ(initial_retransmittable_on_wire_timeout,
366               alarm_->deadline() - clock_.ApproximateNow());
367     clock_.AdvanceTime(initial_retransmittable_on_wire_timeout);
368     EXPECT_CALL(delegate_, OnRetransmittableOnWireTimeout());
369     alarm_->Fire();
370     manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
371                       kHasInflightPackets);
372   }
373 
374   manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
375                     !kHasInflightPackets);
376   EXPECT_TRUE(alarm_->IsSet());
377   // Verify alarm is in keep-alive mode.
378   EXPECT_EQ(QuicTime::Delta::FromSeconds(kPingTimeoutSecs),
379             alarm_->deadline() - clock_.ApproximateNow());
380   clock_.AdvanceTime(QuicTime::Delta::FromSeconds(kPingTimeoutSecs));
381   EXPECT_CALL(delegate_, OnKeepAliveTimeout());
382   alarm_->Fire();
383   EXPECT_FALSE(alarm_->IsSet());
384 }
385 
TEST_F(QuicPingManagerTest,MaxRetransmittableOnWireDelayShift)386 TEST_F(QuicPingManagerTest, MaxRetransmittableOnWireDelayShift) {
387   QuicPingManagerPeer::SetPerspective(&manager_, Perspective::IS_SERVER);
388   const int kMaxAggressiveRetransmittableOnWireCount = 3;
389   SetQuicFlag(quic_max_aggressive_retransmittable_on_wire_ping_count,
390               kMaxAggressiveRetransmittableOnWireCount);
391   const QuicTime::Delta initial_retransmittable_on_wire_timeout =
392       QuicTime::Delta::FromMilliseconds(200);
393   manager_.set_initial_retransmittable_on_wire_timeout(
394       initial_retransmittable_on_wire_timeout);
395 
396   for (int i = 0; i <= kMaxAggressiveRetransmittableOnWireCount; i++) {
397     manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
398                       !kHasInflightPackets);
399     EXPECT_TRUE(alarm_->IsSet());
400     EXPECT_EQ(initial_retransmittable_on_wire_timeout,
401               alarm_->deadline() - clock_.ApproximateNow());
402     clock_.AdvanceTime(initial_retransmittable_on_wire_timeout);
403     EXPECT_CALL(delegate_, OnRetransmittableOnWireTimeout());
404     alarm_->Fire();
405     manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
406                       kHasInflightPackets);
407   }
408   for (int i = 1; i <= 20; ++i) {
409     manager_.SetAlarm(clock_.ApproximateNow(), kShouldKeepAlive,
410                       !kHasInflightPackets);
411     EXPECT_TRUE(alarm_->IsSet());
412     if (i <= 10) {
413       EXPECT_EQ(initial_retransmittable_on_wire_timeout * (1 << i),
414                 alarm_->deadline() - clock_.ApproximateNow());
415     } else {
416       // Verify shift is capped.
417       EXPECT_EQ(initial_retransmittable_on_wire_timeout * (1 << 10),
418                 alarm_->deadline() - clock_.ApproximateNow());
419     }
420     clock_.AdvanceTime(alarm_->deadline() - clock_.ApproximateNow());
421     EXPECT_CALL(delegate_, OnRetransmittableOnWireTimeout());
422     alarm_->Fire();
423   }
424 }
425 
426 }  // namespace
427 
428 }  // namespace test
429 }  // namespace quic
430