gfe-relnote: In QUIC, enforce packets be ACKed in the correct packet number space. Protected by enabling multiple packet number spaces.
PiperOrigin-RevId: 243853453
Change-Id: Iee8f806247f85ed784f4872f380f334754bc7e22
diff --git a/quic/core/congestion_control/general_loss_algorithm_test.cc b/quic/core/congestion_control/general_loss_algorithm_test.cc
index 0172dfc..a249679 100644
--- a/quic/core/congestion_control/general_loss_algorithm_test.cc
+++ b/quic/core/congestion_control/general_loss_algorithm_test.cc
@@ -59,7 +59,7 @@
const std::vector<uint64_t>& losses_expected) {
if (unacked_packets_.use_uber_loss_algorithm()) {
unacked_packets_.MaybeUpdateLargestAckedOfPacketNumberSpace(
- ENCRYPTION_INITIAL, QuicPacketNumber(largest_newly_acked));
+ APPLICATION_DATA, QuicPacketNumber(largest_newly_acked));
} else if (!unacked_packets_.largest_acked().IsInitialized() ||
QuicPacketNumber(largest_newly_acked) >
unacked_packets_.largest_acked()) {
@@ -217,7 +217,7 @@
// Early retransmit when the final packet gets acked and the first is nacked.
if (unacked_packets_.use_uber_loss_algorithm()) {
unacked_packets_.MaybeUpdateLargestAckedOfPacketNumberSpace(
- ENCRYPTION_INITIAL, QuicPacketNumber(2));
+ APPLICATION_DATA, QuicPacketNumber(2));
} else {
unacked_packets_.IncreaseLargestAcked(QuicPacketNumber(2));
}
@@ -240,7 +240,7 @@
// Early retransmit when the final packet gets acked and the first is nacked.
if (unacked_packets_.use_uber_loss_algorithm()) {
unacked_packets_.MaybeUpdateLargestAckedOfPacketNumberSpace(
- ENCRYPTION_INITIAL, QuicPacketNumber(2));
+ APPLICATION_DATA, QuicPacketNumber(2));
} else {
unacked_packets_.IncreaseLargestAcked(QuicPacketNumber(2));
}
@@ -272,7 +272,7 @@
clock_.AdvanceTime(rtt_stats_.smoothed_rtt());
if (unacked_packets_.use_uber_loss_algorithm()) {
unacked_packets_.MaybeUpdateLargestAckedOfPacketNumberSpace(
- ENCRYPTION_INITIAL, QuicPacketNumber(2));
+ APPLICATION_DATA, QuicPacketNumber(2));
} else {
unacked_packets_.IncreaseLargestAcked(QuicPacketNumber(2));
}
diff --git a/quic/core/congestion_control/uber_loss_algorithm_test.cc b/quic/core/congestion_control/uber_loss_algorithm_test.cc
index 2945214..33b9393 100644
--- a/quic/core/congestion_control/uber_loss_algorithm_test.cc
+++ b/quic/core/congestion_control/uber_loss_algorithm_test.cc
@@ -90,7 +90,7 @@
AckPackets({1, 4});
unacked_packets_->MaybeUpdateLargestAckedOfPacketNumberSpace(
- ENCRYPTION_INITIAL, QuicPacketNumber(4));
+ HANDSHAKE_DATA, QuicPacketNumber(4));
// Verify no packet is detected lost.
VerifyLosses(4, packets_acked_, std::vector<uint64_t>{});
EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
@@ -106,7 +106,7 @@
AckPackets({4});
unacked_packets_->MaybeUpdateLargestAckedOfPacketNumberSpace(
- ENCRYPTION_ZERO_RTT, QuicPacketNumber(4));
+ APPLICATION_DATA, QuicPacketNumber(4));
// No packet loss by acking 4.
VerifyLosses(4, packets_acked_, std::vector<uint64_t>{});
EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
@@ -114,7 +114,7 @@
// Acking 6 causes 3 to be detected loss.
AckPackets({6});
unacked_packets_->MaybeUpdateLargestAckedOfPacketNumberSpace(
- ENCRYPTION_FORWARD_SECURE, QuicPacketNumber(6));
+ APPLICATION_DATA, QuicPacketNumber(6));
VerifyLosses(6, packets_acked_, std::vector<uint64_t>{3});
EXPECT_EQ(clock_.Now() + 1.25 * rtt_stats_.smoothed_rtt(),
loss_algorithm_.GetLossTimeout());
@@ -140,9 +140,9 @@
AckPackets({4, 5});
unacked_packets_->MaybeUpdateLargestAckedOfPacketNumberSpace(
- ENCRYPTION_FORWARD_SECURE, QuicPacketNumber(4));
+ APPLICATION_DATA, QuicPacketNumber(4));
unacked_packets_->MaybeUpdateLargestAckedOfPacketNumberSpace(
- ENCRYPTION_ZERO_RTT, QuicPacketNumber(5));
+ HANDSHAKE_DATA, QuicPacketNumber(5));
// No packet loss by acking 5.
VerifyLosses(5, packets_acked_, std::vector<uint64_t>{});
EXPECT_EQ(clock_.Now() + 1.25 * rtt_stats_.smoothed_rtt(),
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc
index 307104d..efc89d3 100644
--- a/quic/core/quic_connection.cc
+++ b/quic/core/quic_connection.cc
@@ -1122,8 +1122,17 @@
QUIC_DLOG(INFO) << ENDPOINT << "Received an old ack frame: ignoring";
return true;
}
- bool acked_new_packet =
- sent_packet_manager_.OnAckFrameEnd(time_of_last_received_packet_);
+ const AckResult ack_result = sent_packet_manager_.OnAckFrameEnd(
+ time_of_last_received_packet_, last_decrypted_packet_level_);
+ if (ack_result != PACKETS_NEWLY_ACKED &&
+ ack_result != NO_PACKETS_NEWLY_ACKED) {
+ // Error occurred (e.g., this ACK tries to ack packets in wrong packet
+ // number space), and this would cause the connection to be closed.
+ QUIC_DLOG(ERROR) << ENDPOINT
+ << "Error occurred when processing an ACK frame: "
+ << QuicUtils::AckResultToString(ack_result);
+ return false;
+ }
// Cancel the send alarm because new packets likely have been acked, which
// may change the congestion window and/or pacing rate. Canceling the alarm
// causes CanWrite to recalculate the next send time.
@@ -1141,7 +1150,8 @@
// If the incoming ack's packets set expresses received packets: peer is still
// acking packets which we never care about.
// Send an ack to raise the high water mark.
- PostProcessAfterAckFrame(GetLeastUnacked() > start, acked_new_packet);
+ PostProcessAfterAckFrame(GetLeastUnacked() > start,
+ ack_result == PACKETS_NEWLY_ACKED);
processing_ack_frame_ = false;
return connected_;
diff --git a/quic/core/quic_sent_packet_manager.cc b/quic/core/quic_sent_packet_manager.cc
index f227190..456e81c 100644
--- a/quic/core/quic_sent_packet_manager.cc
+++ b/quic/core/quic_sent_packet_manager.cc
@@ -273,7 +273,7 @@
}
}
-void QuicSentPacketManager::PostProcessAfterMarkingPacketHandled(
+void QuicSentPacketManager::PostProcessNewlyAckedPackets(
const QuicAckFrame& ack_frame,
QuicTime ack_receive_time,
bool rtt_updated,
@@ -1139,7 +1139,9 @@
}
}
-bool QuicSentPacketManager::OnAckFrameEnd(QuicTime ack_receive_time) {
+AckResult QuicSentPacketManager::OnAckFrameEnd(
+ QuicTime ack_receive_time,
+ EncryptionLevel ack_decrypted_level) {
QuicByteCount prior_bytes_in_flight = unacked_packets_.bytes_in_flight();
// Reverse packets_acked_ so that it is in ascending order.
reverse(packets_acked_.begin(), packets_acked_.end());
@@ -1154,20 +1156,37 @@
<< ", least_unacked: " << unacked_packets_.GetLeastUnacked()
<< ", packets_acked_: " << packets_acked_;
} else {
- QUIC_PEER_BUG << "Received ack for unackable packet: "
+ QUIC_PEER_BUG << "Received "
+ << QuicUtils::EncryptionLevelToString(ack_decrypted_level)
+ << " ack for unackable packet: "
<< acked_packet.packet_number << " with state: "
<< QuicUtils::SentPacketStateToString(info->state);
+ if (supports_multiple_packet_number_spaces()) {
+ if (info->state == NEVER_SENT) {
+ return UNSENT_PACKETS_ACKED;
+ }
+ return UNACKABLE_PACKETS_ACKED;
+ }
}
continue;
}
- QUIC_DVLOG(1) << ENDPOINT << "Got an ack for packet "
- << acked_packet.packet_number;
+ QUIC_DVLOG(1) << ENDPOINT << "Got an "
+ << QuicUtils::EncryptionLevelToString(ack_decrypted_level)
+ << " ack for packet " << acked_packet.packet_number;
+ const PacketNumberSpace packet_number_space =
+ unacked_packets_.use_uber_loss_algorithm()
+ ? unacked_packets_.GetPacketNumberSpace(info->encryption_level)
+ : NUM_PACKET_NUMBER_SPACES;
+ if (supports_multiple_packet_number_spaces() &&
+ QuicUtils::GetPacketNumberSpace(ack_decrypted_level) !=
+ packet_number_space) {
+ return PACKETS_ACKED_IN_WRONG_PACKET_NUMBER_SPACE;
+ }
last_ack_frame_.packets.Add(acked_packet.packet_number);
largest_packet_peer_knows_is_acked_.UpdateMax(info->largest_acked);
if (supports_multiple_packet_number_spaces()) {
- largest_packets_peer_knows_is_acked_[QuicUtils::GetPacketNumberSpace(
- info->encryption_level)]
- .UpdateMax(info->largest_acked);
+ largest_packets_peer_knows_is_acked_[packet_number_space].UpdateMax(
+ info->largest_acked);
}
// If data is associated with the most recent transmission of this
// packet, then inform the caller.
@@ -1179,16 +1198,16 @@
}
if (unacked_packets_.use_uber_loss_algorithm()) {
unacked_packets_.MaybeUpdateLargestAckedOfPacketNumberSpace(
- info->encryption_level, acked_packet.packet_number);
+ packet_number_space, acked_packet.packet_number);
}
MarkPacketHandled(acked_packet.packet_number, info,
last_ack_frame_.ack_delay_time);
}
const bool acked_new_packet = !packets_acked_.empty();
- PostProcessAfterMarkingPacketHandled(last_ack_frame_, ack_receive_time,
- rtt_updated_, prior_bytes_in_flight);
+ PostProcessNewlyAckedPackets(last_ack_frame_, ack_receive_time, rtt_updated_,
+ prior_bytes_in_flight);
- return acked_new_packet;
+ return acked_new_packet ? PACKETS_NEWLY_ACKED : NO_PACKETS_NEWLY_ACKED;
}
void QuicSentPacketManager::SetDebugDelegate(DebugDelegate* debug_delegate) {
diff --git a/quic/core/quic_sent_packet_manager.h b/quic/core/quic_sent_packet_manager.h
index 039ee59..7e10b77 100644
--- a/quic/core/quic_sent_packet_manager.h
+++ b/quic/core/quic_sent_packet_manager.h
@@ -271,9 +271,9 @@
// the timestamp field is set. Otherwise, the timestamp is ignored.
void OnAckTimestamp(QuicPacketNumber packet_number, QuicTime timestamp);
- // Called when an ack frame is parsed completely. Returns true if a previously
- // -unacked packet is acked.
- bool OnAckFrameEnd(QuicTime ack_receive_time);
+ // Called when an ack frame is parsed completely.
+ AckResult OnAckFrameEnd(QuicTime ack_receive_time,
+ EncryptionLevel ack_decrypted_level);
// Called to enable/disable letting session decide what to write.
void SetSessionDecideWhatToWrite(bool session_decides_what_to_write) {
@@ -491,11 +491,10 @@
QuicTransmissionInfo* transmission_info);
// Called after packets have been marked handled with last received ack frame.
- void PostProcessAfterMarkingPacketHandled(
- const QuicAckFrame& ack_frame,
- QuicTime ack_receive_time,
- bool rtt_updated,
- QuicByteCount prior_bytes_in_flight);
+ void PostProcessNewlyAckedPackets(const QuicAckFrame& ack_frame,
+ QuicTime ack_receive_time,
+ bool rtt_updated,
+ QuicByteCount prior_bytes_in_flight);
// Notify observers that packet with QuicTransmissionInfo |info| is a spurious
// retransmission. It is caller's responsibility to guarantee the packet with
diff --git a/quic/core/quic_sent_packet_manager_test.cc b/quic/core/quic_sent_packet_manager_test.cc
index 4624a8a..08e307c 100644
--- a/quic/core/quic_sent_packet_manager_test.cc
+++ b/quic/core/quic_sent_packet_manager_test.cc
@@ -366,7 +366,8 @@
manager_.OnAckFrameStart(QuicPacketNumber(2), QuicTime::Delta::Infinite(),
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(2), QuicPacketNumber(3));
- EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
if (manager_.session_decides_what_to_write()) {
EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false));
}
@@ -397,7 +398,8 @@
manager_.OnAckFrameStart(QuicPacketNumber(1), QuicTime::Delta::Infinite(),
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
- EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
// There should no longer be a pending retransmission.
EXPECT_FALSE(manager_.HasPendingRetransmissions());
@@ -451,7 +453,8 @@
manager_.OnAckFrameStart(QuicPacketNumber(1), QuicTime::Delta::Infinite(),
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
- EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
if (manager_.session_decides_what_to_write()) {
EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false));
}
@@ -467,7 +470,8 @@
manager_.OnAckFrameStart(QuicPacketNumber(2), QuicTime::Delta::Infinite(),
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(3));
- EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
}
EXPECT_EQ(1u, stats_.packets_spuriously_retransmitted);
@@ -484,7 +488,8 @@
manager_.OnAckFrameStart(QuicPacketNumber(1), QuicTime::Delta::Infinite(),
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
- EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
SendDataPacket(3);
SendDataPacket(4);
@@ -497,14 +502,16 @@
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(4));
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
- EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
ExpectAck(4);
manager_.OnAckFrameStart(QuicPacketNumber(4), QuicTime::Delta::Infinite(),
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(5));
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
- EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
ExpectAckAndLoss(true, 5, 2);
if (manager_.session_decides_what_to_write()) {
@@ -518,7 +525,8 @@
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(6));
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
- EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
if (manager_.session_decides_what_to_write()) {
uint64_t unacked[] = {2};
@@ -554,7 +562,8 @@
manager_.OnAckFrameStart(QuicPacketNumber(1), QuicTime::Delta::Infinite(),
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
- EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
// Since 2 was marked for retransmit, when 1 is acked, 2 is kept for RTT.
uint64_t unacked[] = {2};
@@ -591,7 +600,8 @@
manager_.OnAckFrameStart(QuicPacketNumber(1), QuicTime::Delta::Infinite(),
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
- EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
if (manager_.session_decides_what_to_write()) {
// Frames in packets 2 and 3 are acked.
EXPECT_CALL(notifier_, IsFrameOutstanding(_))
@@ -619,7 +629,8 @@
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(5));
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
- EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
uint64_t unacked2[] = {2};
VerifyUnackedPackets(unacked2, QUIC_ARRAYSIZE(unacked2));
@@ -640,7 +651,8 @@
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(6));
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
- EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
if (manager_.session_decides_what_to_write()) {
uint64_t unacked[] = {2};
@@ -673,7 +685,8 @@
manager_.OnAckFrameStart(QuicPacketNumber(1), QuicTime::Delta::Infinite(),
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
- EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
}
SendDataPacket(3);
@@ -686,7 +699,8 @@
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(4), QuicPacketNumber(5));
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
- EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
RetransmitAndSendPacket(3, 5, LOSS_RETRANSMISSION);
}
@@ -701,7 +715,8 @@
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(5));
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
- EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
if (manager_.session_decides_what_to_write()) {
// Ack 3 will not cause 5 be considered as a spurious retransmission. Ack
// 5 will cause 5 be considered as a spurious retransmission as no new
@@ -713,7 +728,8 @@
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(6));
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
- EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
}
}
}
@@ -738,7 +754,8 @@
manager_.OnAckFrameStart(QuicPacketNumber(2),
QuicTime::Delta::FromMilliseconds(5), clock_.Now());
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(3));
- EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
EXPECT_EQ(QuicPacketNumber(1), manager_.largest_packet_peer_knows_is_acked());
SendAckPacket(3, 3);
@@ -749,7 +766,8 @@
manager_.OnAckFrameStart(QuicPacketNumber(3), QuicTime::Delta::Infinite(),
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(4));
- EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
EXPECT_EQ(QuicPacketNumber(3u),
manager_.largest_packet_peer_knows_is_acked());
}
@@ -763,7 +781,8 @@
manager_.OnAckFrameStart(QuicPacketNumber(1), QuicTime::Delta::Infinite(),
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
- EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
EXPECT_EQ(expected_rtt, manager_.GetRttStats()->latest_rtt());
}
@@ -779,7 +798,8 @@
manager_.OnAckFrameStart(QuicPacketNumber(1),
QuicTime::Delta::FromMilliseconds(11), clock_.Now());
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
- EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
EXPECT_EQ(expected_rtt, manager_.GetRttStats()->latest_rtt());
}
@@ -794,7 +814,8 @@
manager_.OnAckFrameStart(QuicPacketNumber(1), QuicTime::Delta::Infinite(),
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
- EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
EXPECT_EQ(expected_rtt, manager_.GetRttStats()->latest_rtt());
}
@@ -809,7 +830,8 @@
manager_.OnAckFrameStart(QuicPacketNumber(1), QuicTime::Delta::Zero(),
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
- EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
EXPECT_EQ(expected_rtt, manager_.GetRttStats()->latest_rtt());
}
@@ -859,7 +881,8 @@
manager_.OnAckFrameStart(QuicPacketNumber(3), QuicTime::Delta::Infinite(),
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(4));
- EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
EXPECT_TRUE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_));
@@ -880,7 +903,8 @@
manager_.OnAckFrameStart(QuicPacketNumber(5), QuicTime::Delta::Infinite(),
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(6));
- EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
EXPECT_FALSE(manager_.HasPendingRetransmissions());
EXPECT_FALSE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_));
@@ -988,7 +1012,8 @@
manager_.OnAckFrameStart(QuicPacketNumber(103), QuicTime::Delta::Infinite(),
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(103), QuicPacketNumber(104));
- EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
// All packets before 103 should be lost.
if (manager_.session_decides_what_to_write()) {
// Packet 104 is still in flight.
@@ -1054,7 +1079,8 @@
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(8), QuicPacketNumber(10));
manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(6));
- EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
EXPECT_FALSE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
}
@@ -1125,7 +1151,8 @@
manager_.OnAckFrameStart(QuicPacketNumber(9), QuicTime::Delta::Infinite(),
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(8), QuicPacketNumber(10));
- EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
if (manager_.session_decides_what_to_write()) {
EXPECT_CALL(notifier_, HasUnackedCryptoData())
.WillRepeatedly(Return(false));
@@ -1170,7 +1197,8 @@
manager_.OnAckFrameStart(QuicPacketNumber(2), QuicTime::Delta::Infinite(),
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(2), QuicPacketNumber(3));
- EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
EXPECT_FALSE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
uint64_t unacked[] = {3};
@@ -1290,7 +1318,8 @@
manager_.OnAckFrameStart(QuicPacketNumber(3), QuicTime::Delta::Infinite(),
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(4));
- EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
VerifyUnackedPackets(nullptr, 0);
VerifyRetransmittablePackets(nullptr, 0);
}
@@ -1354,7 +1383,8 @@
manager_.OnAckFrameStart(QuicPacketNumber(102), QuicTime::Delta::Zero(),
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(102), QuicPacketNumber(103));
- EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
}
TEST_P(QuicSentPacketManagerTest, RetransmissionTimeoutOnePacket) {
@@ -1466,7 +1496,8 @@
manager_.OnAckFrameStart(QuicPacketNumber(102), QuicTime::Delta::Zero(),
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(102), QuicPacketNumber(103));
- EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
}
TEST_P(QuicSentPacketManagerTest, TwoRetransmissionTimeoutsAckSecond) {
@@ -1514,7 +1545,8 @@
manager_.OnAckFrameStart(QuicPacketNumber(2), QuicTime::Delta::Zero(),
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(2), QuicPacketNumber(3));
- EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
// The original packet and newest should be outstanding.
EXPECT_EQ(2 * kDefaultLength,
@@ -1566,7 +1598,8 @@
manager_.OnAckFrameStart(QuicPacketNumber(3), QuicTime::Delta::Zero(),
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(4));
- EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
// The first two packets should still be outstanding.
EXPECT_EQ(2 * kDefaultLength,
@@ -1768,7 +1801,8 @@
manager_.OnAckFrameStart(QuicPacketNumber(2), QuicTime::Delta::Infinite(),
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(2), QuicPacketNumber(3));
- EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
EXPECT_FALSE(manager_.HasPendingRetransmissions());
EXPECT_EQ(5 * kDefaultLength,
QuicSentPacketManagerPeer::GetBytesInFlight(&manager_));
@@ -1903,7 +1937,8 @@
manager_.OnAckFrameStart(QuicPacketNumber(2), QuicTime::Delta::Infinite(),
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(2), QuicPacketNumber(3));
- EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
QuicTime timeout(clock_.Now() + QuicTime::Delta::FromMilliseconds(10));
EXPECT_CALL(*loss_algorithm, GetLossTimeout())
@@ -2405,7 +2440,8 @@
manager_.OnAckFrameStart(QuicPacketNumber(1), QuicTime::Delta::Infinite(),
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
- EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
}
TEST_P(QuicSentPacketManagerTest, OnAckRangeSlowPath) {
@@ -2426,7 +2462,8 @@
manager_.OnAckRange(QuicPacketNumber(5), QuicPacketNumber(7));
// Make sure empty range does not harm.
manager_.OnAckRange(QuicPacketNumber(4), QuicPacketNumber(4));
- EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
// Ack [4, 8), [9, 13), [14, 21).
uint64_t acked2[] = {4, 7, 9, 12, 14, 17, 18, 19, 20};
@@ -2436,7 +2473,8 @@
manager_.OnAckRange(QuicPacketNumber(14), QuicPacketNumber(21));
manager_.OnAckRange(QuicPacketNumber(9), QuicPacketNumber(13));
manager_.OnAckRange(QuicPacketNumber(4), QuicPacketNumber(8));
- EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
}
TEST_P(QuicSentPacketManagerTest, TolerateReneging) {
@@ -2458,7 +2496,8 @@
manager_.OnAckRange(QuicPacketNumber(15), QuicPacketNumber(17));
manager_.OnAckRange(QuicPacketNumber(10), QuicPacketNumber(12));
manager_.OnAckRange(QuicPacketNumber(5), QuicPacketNumber(7));
- EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
// Making sure reneged ACK does not harm. Ack [4, 8), [9, 13).
uint64_t acked2[] = {4, 7, 9, 12};
@@ -2467,7 +2506,8 @@
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(9), QuicPacketNumber(13));
manager_.OnAckRange(QuicPacketNumber(4), QuicPacketNumber(8));
- EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
EXPECT_EQ(QuicPacketNumber(16), manager_.GetLargestObserved());
}
@@ -2491,7 +2531,8 @@
manager_.OnAckFrameStart(QuicPacketNumber(1), QuicTime::Delta::Infinite(),
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
- EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
EXPECT_EQ(QuicPacketNumber(1),
manager_.GetLargestAckedPacket(ENCRYPTION_INITIAL));
EXPECT_FALSE(
@@ -2510,7 +2551,8 @@
manager_.OnAckFrameStart(QuicPacketNumber(2), QuicTime::Delta::Infinite(),
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(2), QuicPacketNumber(3));
- EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_HANDSHAKE));
EXPECT_EQ(QuicPacketNumber(2),
manager_.GetLargestAckedPacket(ENCRYPTION_HANDSHAKE));
EXPECT_FALSE(
@@ -2520,7 +2562,8 @@
manager_.OnAckFrameStart(QuicPacketNumber(3), QuicTime::Delta::Infinite(),
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(2), QuicPacketNumber(4));
- EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_HANDSHAKE));
EXPECT_EQ(QuicPacketNumber(3),
manager_.GetLargestAckedPacket(ENCRYPTION_HANDSHAKE));
EXPECT_FALSE(
@@ -2541,7 +2584,8 @@
manager_.OnAckFrameStart(QuicPacketNumber(5), QuicTime::Delta::Infinite(),
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(5), QuicPacketNumber(6));
- EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_FORWARD_SECURE));
EXPECT_EQ(QuicPacketNumber(3),
manager_.GetLargestAckedPacket(ENCRYPTION_HANDSHAKE));
EXPECT_EQ(QuicPacketNumber(5),
@@ -2567,7 +2611,8 @@
manager_.OnAckFrameStart(QuicPacketNumber(8), QuicTime::Delta::Infinite(),
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(4), QuicPacketNumber(9));
- EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now()));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_FORWARD_SECURE));
EXPECT_EQ(QuicPacketNumber(3),
manager_.GetLargestAckedPacket(ENCRYPTION_HANDSHAKE));
EXPECT_EQ(QuicPacketNumber(8),
@@ -2576,6 +2621,75 @@
manager_.GetLargestAckedPacket(ENCRYPTION_FORWARD_SECURE));
}
+TEST_P(QuicSentPacketManagerTest, PacketsGetAckedInWrongPacketNumberSpace) {
+ if (!GetQuicReloadableFlag(quic_use_uber_loss_algorithm)) {
+ return;
+ }
+ manager_.EnableMultiplePacketNumberSpacesSupport();
+ // Send packet 1.
+ SendDataPacket(1, ENCRYPTION_INITIAL);
+ // Send packets 2 and 3.
+ SendDataPacket(2, ENCRYPTION_HANDSHAKE);
+ SendDataPacket(3, ENCRYPTION_HANDSHAKE);
+
+ // ACK packets 2 and 3 in the wrong packet number space.
+ manager_.OnAckFrameStart(QuicPacketNumber(3), QuicTime::Delta::Infinite(),
+ clock_.Now());
+ manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(4));
+ EXPECT_EQ(PACKETS_ACKED_IN_WRONG_PACKET_NUMBER_SPACE,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+}
+
+TEST_P(QuicSentPacketManagerTest, PacketsGetAckedInWrongPacketNumberSpace2) {
+ if (!GetQuicReloadableFlag(quic_use_uber_loss_algorithm)) {
+ return;
+ }
+ manager_.EnableMultiplePacketNumberSpacesSupport();
+ // Send packet 1.
+ SendDataPacket(1, ENCRYPTION_INITIAL);
+ // Send packets 2 and 3.
+ SendDataPacket(2, ENCRYPTION_HANDSHAKE);
+ SendDataPacket(3, ENCRYPTION_HANDSHAKE);
+
+ // ACK packet 1 in the wrong packet number space.
+ manager_.OnAckFrameStart(QuicPacketNumber(3), QuicTime::Delta::Infinite(),
+ clock_.Now());
+ manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(4));
+ EXPECT_EQ(PACKETS_ACKED_IN_WRONG_PACKET_NUMBER_SPACE,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_HANDSHAKE));
+}
+
+TEST_P(QuicSentPacketManagerTest,
+ ToleratePacketsGetAckedInWrongPacketNumberSpace) {
+ if (!GetQuicReloadableFlag(quic_use_uber_loss_algorithm)) {
+ return;
+ }
+ manager_.EnableMultiplePacketNumberSpacesSupport();
+ // Send packet 1.
+ SendDataPacket(1, ENCRYPTION_INITIAL);
+ // Ack packet 1.
+ ExpectAck(1);
+ manager_.OnAckFrameStart(QuicPacketNumber(1), QuicTime::Delta::Infinite(),
+ clock_.Now());
+ manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+
+ // Send packets 2 and 3.
+ SendDataPacket(2, ENCRYPTION_HANDSHAKE);
+ SendDataPacket(3, ENCRYPTION_HANDSHAKE);
+
+ // Packet 1 gets acked in the wrong packet number space. Since packet 1 has
+ // been acked in the correct packet number space, tolerate it.
+ uint64_t acked[] = {2, 3};
+ ExpectAcksAndLosses(true, acked, QUIC_ARRAYSIZE(acked), nullptr, 0);
+ manager_.OnAckFrameStart(QuicPacketNumber(3), QuicTime::Delta::Infinite(),
+ clock_.Now());
+ manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(4));
+ EXPECT_EQ(PACKETS_NEWLY_ACKED,
+ manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_HANDSHAKE));
+}
+
} // namespace
} // namespace test
} // namespace quic
diff --git a/quic/core/quic_types.h b/quic/core/quic_types.h
index 19dac06..f90b0fa 100644
--- a/quic/core/quic_types.h
+++ b/quic/core/quic_types.h
@@ -587,6 +587,20 @@
enum AckMode { TCP_ACKING, ACK_DECIMATION, ACK_DECIMATION_WITH_REORDERING };
+// Used to return the result of processing a received ACK frame.
+enum AckResult {
+ PACKETS_NEWLY_ACKED,
+ NO_PACKETS_NEWLY_ACKED,
+ UNSENT_PACKETS_ACKED, // Peer acks unsent packets.
+ UNACKABLE_PACKETS_ACKED, // Peer acks packets that are not expected to be
+ // acked. For example, encryption is reestablished,
+ // and all sent encrypted packets cannot be
+ // decrypted by the peer. Version gets negotiated,
+ // and all sent packets in the different version
+ // cannot be processed by the peer.
+ PACKETS_ACKED_IN_WRONG_PACKET_NUMBER_SPACE,
+};
+
} // namespace quic
#endif // QUICHE_QUIC_CORE_QUIC_TYPES_H_
diff --git a/quic/core/quic_unacked_packet_map.cc b/quic/core/quic_unacked_packet_map.cc
index 5a9bd24..1a0b1af 100644
--- a/quic/core/quic_unacked_packet_map.cc
+++ b/quic/core/quic_unacked_packet_map.cc
@@ -229,11 +229,9 @@
}
void QuicUnackedPacketMap::MaybeUpdateLargestAckedOfPacketNumberSpace(
- EncryptionLevel encryption_level,
+ PacketNumberSpace packet_number_space,
QuicPacketNumber packet_number) {
DCHECK(use_uber_loss_algorithm_);
- const PacketNumberSpace packet_number_space =
- GetPacketNumberSpace(encryption_level);
largest_acked_packets_[packet_number_space].UpdateMax(packet_number);
}
diff --git a/quic/core/quic_unacked_packet_map.h b/quic/core/quic_unacked_packet_map.h
index 1d4f00c..1a37a1f 100644
--- a/quic/core/quic_unacked_packet_map.h
+++ b/quic/core/quic_unacked_packet_map.h
@@ -166,9 +166,9 @@
void IncreaseLargestAcked(QuicPacketNumber largest_acked);
// Called when |packet_number| gets acked. Maybe increase the largest acked of
- // corresponding packet number space of |encryption_level|.
+ // |packet_number_space|.
void MaybeUpdateLargestAckedOfPacketNumberSpace(
- EncryptionLevel encryption_level,
+ PacketNumberSpace packet_number_space,
QuicPacketNumber packet_number);
// Remove any packets no longer needed for retransmission, congestion, or
diff --git a/quic/core/quic_utils.cc b/quic/core/quic_utils.cc
index 56cfe87..413a244 100644
--- a/quic/core/quic_utils.cc
+++ b/quic/core/quic_utils.cc
@@ -209,6 +209,18 @@
}
// static
+const char* QuicUtils::AckResultToString(AckResult result) {
+ switch (result) {
+ RETURN_STRING_LITERAL(PACKETS_NEWLY_ACKED);
+ RETURN_STRING_LITERAL(NO_PACKETS_NEWLY_ACKED);
+ RETURN_STRING_LITERAL(UNSENT_PACKETS_ACKED);
+ RETURN_STRING_LITERAL(UNACKABLE_PACKETS_ACKED);
+ RETURN_STRING_LITERAL(PACKETS_ACKED_IN_WRONG_PACKET_NUMBER_SPACE);
+ }
+ return "INVALID_ACK_RESULT";
+}
+
+// static
AddressChangeType QuicUtils::DetermineAddressChangeType(
const QuicSocketAddress& old_address,
const QuicSocketAddress& new_address) {
diff --git a/quic/core/quic_utils.h b/quic/core/quic_utils.h
index 340f474..cacbc60 100644
--- a/quic/core/quic_utils.h
+++ b/quic/core/quic_utils.h
@@ -64,6 +64,9 @@
// Returns QuicLongHeaderType as a char*.
static const char* QuicLongHeaderTypetoString(QuicLongHeaderType type);
+ // Returns AckResult as a char*.
+ static const char* AckResultToString(AckResult result);
+
// Determines and returns change type of address change from |old_address| to
// |new_address|.
static AddressChangeType DetermineAddressChangeType(