summaryrefslogtreecommitdiffstats
path: root/net/quic
diff options
context:
space:
mode:
authorrtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-05-28 03:53:15 +0000
committerrtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-05-28 03:53:15 +0000
commitaa7e4ef1cd85a77bc3288e0eb67c24f71b9e994a (patch)
tree2b9c70c878b28df96a5b9861ec45bc3f469059bc /net/quic
parent6db100b2aaa4def86468d8de0214a716d92915d4 (diff)
downloadchromium_src-aa7e4ef1cd85a77bc3288e0eb67c24f71b9e994a.zip
chromium_src-aa7e4ef1cd85a77bc3288e0eb67c24f71b9e994a.tar.gz
chromium_src-aa7e4ef1cd85a77bc3288e0eb67c24f71b9e994a.tar.bz2
Land Recent QUIC Changes.
Changes StreamFramePacketOverhead to use offset in determining overhead. Stream overhead changes as the offset changes. Merge internal change: 67881361 https://codereview.chromium.org/304513006/ Fixes bugs in packet size computation in the creator and in the framer mostly related to truncated ack size computation and verification. Fixes a bug where sequence_number_length was incorrectly being allowed to change mid-packet, and actively updates lengths in packets at packet/FEC-group boundary. Adds tests to verify correct detection of ack truncation. Much yak hair was harvested, but no yaks were hurt in the making of this CL. Fixes bugs in packet-size computation in QuicPacketCreator and adds tests. Merge internal change: 67880898 https://codereview.chromium.org/300623009/ clang_tidy: remove redundant .get() calls on smart ptrs Merge internal change: 67852120 https://codereview.chromium.org/304623002/ Update naming of members per style guideline with clang_tidy. + slowStart_ was changed to slow_start_. Merge internal change: 67850333 https://codereview.chromium.org/300263003/ Added a helper function (SetIpInfoInCmsg) for WritePacket which fills in the cmsg with the supplied self address. This is part of "setting QoS on each quic sendmsg." internal CL. Merge internal change: 67783235 https://codereview.chromium.org/300693006/ QUIC: rename GetWriteblockedStreams to GetWriteBlockedStreams. Merge internal change: 67771815 https://codereview.chromium.org/302603007/ Change SendStreamId to take a stream ID argument in quic_session_test.cc I think this makes the OnCanWriteBundlesStreams correct - it now writes data with multiple stream IDs. Also cleanup: use Invoke instead of InvokeWithoutArgs for calls which have no args anyway... Merge internal change: 67763247 https://codereview.chromium.org/307453006/ Rename QUIC's TransmissionInfo pending to in_flight and the associated uses of pending in QuicUnackedPacketMap. Merge internal change: 67762946 https://codereview.chromium.org/302783003/ Add a packet bundler in the internal server so that headers and body go out in the same packet. Tested by checking a small request is 1 packet; negative test fails. Bundle headers with body in outgoing QUIC packets. Merge internal change: 67729594 https://codereview.chromium.org/301563006/ Add an IncreaseLargestObserved to QuicUnackedPacketMap to remove the rtt property from packets. Merge internal change: 67725797 https://codereview.chromium.org/306573002/ Open a new port before closing the original in QUIC's port migration EndToEndTest to ensure a new port is selected every time. Merge internal change: 67703074 https://codereview.chromium.org/297213009/ Simplify QuicSentPacketManager MarkPacketHandled to take an iterator instead of a sequence number and remove the case when it's called in RetransmitUnackedPackets. Merge internal change: 67652345 https://codereview.chromium.org/293383008/ R=rch@chromium.org Review URL: https://codereview.chromium.org/300683008 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@273146 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/quic')
-rw-r--r--net/quic/congestion_control/hybrid_slow_start_test.cc47
-rw-r--r--net/quic/congestion_control/tcp_loss_algorithm.cc4
-rw-r--r--net/quic/congestion_control/tcp_loss_algorithm_test.cc25
-rw-r--r--net/quic/congestion_control/time_loss_algorithm.cc2
-rw-r--r--net/quic/congestion_control/time_loss_algorithm_test.cc8
-rw-r--r--net/quic/quic_connection.cc13
-rw-r--r--net/quic/quic_connection_test.cc30
-rw-r--r--net/quic/quic_data_stream_test.cc2
-rw-r--r--net/quic/quic_default_packet_writer.h5
-rw-r--r--net/quic/quic_framer.cc59
-rw-r--r--net/quic/quic_framer.h8
-rw-r--r--net/quic/quic_framer_test.cc270
-rw-r--r--net/quic/quic_packet_creator.cc57
-rw-r--r--net/quic/quic_packet_creator.h8
-rw-r--r--net/quic/quic_packet_creator_test.cc163
-rw-r--r--net/quic/quic_protocol.cc6
-rw-r--r--net/quic/quic_protocol.h4
-rw-r--r--net/quic/quic_sent_packet_manager.cc148
-rw-r--r--net/quic/quic_sent_packet_manager.h8
-rw-r--r--net/quic/quic_sent_packet_manager_test.cc17
-rw-r--r--net/quic/quic_session_test.cc53
-rw-r--r--net/quic/quic_unacked_packet_map.cc99
-rw-r--r--net/quic/quic_unacked_packet_map.h64
-rw-r--r--net/quic/quic_unacked_packet_map_test.cc166
-rw-r--r--net/quic/reliable_quic_stream_test.cc25
-rw-r--r--net/quic/test_tools/quic_sent_packet_manager_peer.cc2
-rw-r--r--net/quic/test_tools/quic_session_peer.cc2
-rw-r--r--net/quic/test_tools/quic_session_peer.h2
-rw-r--r--net/quic/test_tools/quic_test_utils.cc15
-rw-r--r--net/quic/test_tools/quic_test_utils.h5
30 files changed, 964 insertions, 353 deletions
diff --git a/net/quic/congestion_control/hybrid_slow_start_test.cc b/net/quic/congestion_control/hybrid_slow_start_test.cc
index f07dd21..91c5d9f 100644
--- a/net/quic/congestion_control/hybrid_slow_start_test.cc
+++ b/net/quic/congestion_control/hybrid_slow_start_test.cc
@@ -18,36 +18,36 @@ class HybridSlowStartTest : public ::testing::Test {
rtt_(QuicTime::Delta::FromMilliseconds(60)) {
}
virtual void SetUp() {
- slowStart_.reset(new HybridSlowStart(&clock_));
+ slow_start_.reset(new HybridSlowStart(&clock_));
}
const QuicTime::Delta one_ms_;
const QuicTime::Delta rtt_;
MockClock clock_;
- scoped_ptr<HybridSlowStart> slowStart_;
+ scoped_ptr<HybridSlowStart> slow_start_;
};
TEST_F(HybridSlowStartTest, Simple) {
QuicPacketSequenceNumber sequence_number = 1;
QuicPacketSequenceNumber end_sequence_number = 3;
- slowStart_->StartReceiveRound(end_sequence_number);
+ slow_start_->StartReceiveRound(end_sequence_number);
- EXPECT_FALSE(slowStart_->IsEndOfRound(sequence_number++));
+ EXPECT_FALSE(slow_start_->IsEndOfRound(sequence_number++));
// Test duplicates.
- EXPECT_FALSE(slowStart_->IsEndOfRound(sequence_number));
+ EXPECT_FALSE(slow_start_->IsEndOfRound(sequence_number));
- EXPECT_FALSE(slowStart_->IsEndOfRound(sequence_number++));
- EXPECT_TRUE(slowStart_->IsEndOfRound(sequence_number++));
+ EXPECT_FALSE(slow_start_->IsEndOfRound(sequence_number++));
+ EXPECT_TRUE(slow_start_->IsEndOfRound(sequence_number++));
// Test without a new registered end_sequence_number;
- EXPECT_TRUE(slowStart_->IsEndOfRound(sequence_number++));
+ EXPECT_TRUE(slow_start_->IsEndOfRound(sequence_number++));
end_sequence_number = 20;
- slowStart_->StartReceiveRound(end_sequence_number);
+ slow_start_->StartReceiveRound(end_sequence_number);
while (sequence_number < end_sequence_number) {
- EXPECT_FALSE(slowStart_->IsEndOfRound(sequence_number++));
+ EXPECT_FALSE(slow_start_->IsEndOfRound(sequence_number++));
}
- EXPECT_TRUE(slowStart_->IsEndOfRound(sequence_number++));
+ EXPECT_TRUE(slow_start_->IsEndOfRound(sequence_number++));
}
// TODO(ianswett): Add tests which more realistically invoke the methods,
@@ -60,21 +60,22 @@ TEST_F(HybridSlowStartTest, AckTrain) {
QuicPacketSequenceNumber sequence_number = 2;
QuicPacketSequenceNumber end_sequence_number = 2;
for (int burst = 0; burst < kMaxLoopCount; ++burst) {
- slowStart_->StartReceiveRound(end_sequence_number);
+ slow_start_->StartReceiveRound(end_sequence_number);
do {
clock_.AdvanceTime(one_ms_);
- EXPECT_FALSE(slowStart_->ShouldExitSlowStart(rtt_, rtt_, 100));
- } while (!slowStart_->IsEndOfRound(sequence_number++));
+ EXPECT_FALSE(slow_start_->ShouldExitSlowStart(rtt_, rtt_, 100));
+ } while (!slow_start_->IsEndOfRound(sequence_number++));
end_sequence_number *= 2; // Exponential growth.
}
- slowStart_->StartReceiveRound(end_sequence_number);
+ slow_start_->StartReceiveRound(end_sequence_number);
- for (int n = 0; n < 29 && !slowStart_->IsEndOfRound(sequence_number++); ++n) {
+ for (int n = 0;
+ n < 29 && !slow_start_->IsEndOfRound(sequence_number++); ++n) {
clock_.AdvanceTime(one_ms_);
- EXPECT_FALSE(slowStart_->ShouldExitSlowStart(rtt_, rtt_, 100));
+ EXPECT_FALSE(slow_start_->ShouldExitSlowStart(rtt_, rtt_, 100));
}
clock_.AdvanceTime(one_ms_);
- EXPECT_TRUE(slowStart_->ShouldExitSlowStart(rtt_, rtt_, 100));
+ EXPECT_TRUE(slow_start_->ShouldExitSlowStart(rtt_, rtt_, 100));
}
TEST_F(HybridSlowStartTest, Delay) {
@@ -83,22 +84,22 @@ TEST_F(HybridSlowStartTest, Delay) {
const int kHybridStartMinSamples = 8; // Number of acks required to trigger.
QuicPacketSequenceNumber end_sequence_number = 1;
- slowStart_->StartReceiveRound(end_sequence_number++);
+ slow_start_->StartReceiveRound(end_sequence_number++);
// Will not trigger since our lowest RTT in our burst is the same as the long
// term RTT provided.
for (int n = 0; n < kHybridStartMinSamples; ++n) {
- EXPECT_FALSE(slowStart_->ShouldExitSlowStart(
+ EXPECT_FALSE(slow_start_->ShouldExitSlowStart(
rtt_.Add(QuicTime::Delta::FromMilliseconds(n)), rtt_, 100));
}
- slowStart_->StartReceiveRound(end_sequence_number++);
+ slow_start_->StartReceiveRound(end_sequence_number++);
for (int n = 1; n < kHybridStartMinSamples; ++n) {
- EXPECT_FALSE(slowStart_->ShouldExitSlowStart(
+ EXPECT_FALSE(slow_start_->ShouldExitSlowStart(
rtt_.Add(QuicTime::Delta::FromMilliseconds(n + 5)), rtt_, 100));
}
// Expect to trigger since all packets in this burst was above the long term
// RTT provided.
- EXPECT_TRUE(slowStart_->ShouldExitSlowStart(
+ EXPECT_TRUE(slow_start_->ShouldExitSlowStart(
rtt_.Add(QuicTime::Delta::FromMilliseconds(5)), rtt_, 100));
}
diff --git a/net/quic/congestion_control/tcp_loss_algorithm.cc b/net/quic/congestion_control/tcp_loss_algorithm.cc
index 70198d6..8dad3f1 100644
--- a/net/quic/congestion_control/tcp_loss_algorithm.cc
+++ b/net/quic/congestion_control/tcp_loss_algorithm.cc
@@ -40,7 +40,7 @@ SequenceNumberSet TCPLossAlgorithm::DetectLostPackets(
for (QuicUnackedPacketMap::const_iterator it = unacked_packets.begin();
it != unacked_packets.end() && it->first <= largest_observed; ++it) {
- if (!it->second.pending) {
+ if (!it->second.in_flight) {
continue;
}
@@ -52,7 +52,7 @@ SequenceNumberSet TCPLossAlgorithm::DetectLostPackets(
}
// Only early retransmit(RFC5827) when the last packet gets acked and
- // there are pending retransmittable packets.
+ // there are retransmittable packets in flight.
// This also implements a timer-protected variant of FACK.
if (it->second.retransmittable_frames &&
unacked_packets.largest_sent_packet() == largest_observed) {
diff --git a/net/quic/congestion_control/tcp_loss_algorithm_test.cc b/net/quic/congestion_control/tcp_loss_algorithm_test.cc
index 38736d4..eccda4a 100644
--- a/net/quic/congestion_control/tcp_loss_algorithm_test.cc
+++ b/net/quic/congestion_control/tcp_loss_algorithm_test.cc
@@ -56,15 +56,15 @@ TEST_F(TcpLossAlgorithmTest, NackRetransmit1Packet) {
SendDataPacket(i);
}
// No loss on one ack.
- unacked_packets_.SetNotPending(2);
+ unacked_packets_.RemoveFromInFlight(2);
unacked_packets_.NackPacket(1, 1);
VerifyLosses(2, NULL, 0);
// No loss on two acks.
- unacked_packets_.SetNotPending(3);
+ unacked_packets_.RemoveFromInFlight(3);
unacked_packets_.NackPacket(1, 2);
VerifyLosses(3, NULL, 0);
// Loss on three acks.
- unacked_packets_.SetNotPending(4);
+ unacked_packets_.RemoveFromInFlight(4);
unacked_packets_.NackPacket(1, 3);
QuicPacketSequenceNumber lost[] = { 1 };
VerifyLosses(4, lost, arraysize(lost));
@@ -82,9 +82,9 @@ TEST_F(TcpLossAlgorithmTest, NackRetransmit1PacketWith1StretchAck) {
// Nack the first packet 3 times in a single StretchAck.
unacked_packets_.NackPacket(1, 3);
- unacked_packets_.SetNotPending(2);
- unacked_packets_.SetNotPending(3);
- unacked_packets_.SetNotPending(4);
+ unacked_packets_.RemoveFromInFlight(2);
+ unacked_packets_.RemoveFromInFlight(3);
+ unacked_packets_.RemoveFromInFlight(4);
QuicPacketSequenceNumber lost[] = { 1 };
VerifyLosses(4, lost, arraysize(lost));
EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
@@ -102,7 +102,7 @@ TEST_F(TcpLossAlgorithmTest, NackRetransmit1PacketSingleAck) {
unacked_packets_.NackPacket(1, 3);
unacked_packets_.NackPacket(2, 2);
unacked_packets_.NackPacket(3, 1);
- unacked_packets_.SetNotPending(4);
+ unacked_packets_.RemoveFromInFlight(4);
QuicPacketSequenceNumber lost[] = { 1 };
VerifyLosses(4, lost, arraysize(lost));
EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
@@ -115,7 +115,7 @@ TEST_F(TcpLossAlgorithmTest, EarlyRetransmit1Packet) {
SendDataPacket(i);
}
// Early retransmit when the final packet gets acked and the first is nacked.
- unacked_packets_.SetNotPending(2);
+ unacked_packets_.RemoveFromInFlight(2);
unacked_packets_.NackPacket(1, 1);
VerifyLosses(2, NULL, 0);
EXPECT_EQ(clock_.Now().Add(rtt_stats_.SmoothedRtt().Multiply(1.25)),
@@ -139,7 +139,7 @@ TEST_F(TcpLossAlgorithmTest, EarlyRetransmitAllPackets) {
// Early retransmit when the final packet gets acked and 1.25 RTTs have
// elapsed since the packets were sent.
- unacked_packets_.SetNotPending(kNumSentPackets);
+ unacked_packets_.RemoveFromInFlight(kNumSentPackets);
// This simulates a single ack following multiple missing packets with FACK.
for (size_t i = 1; i < kNumSentPackets; ++i) {
unacked_packets_.NackPacket(i, kNumSentPackets - i);
@@ -168,10 +168,13 @@ TEST_F(TcpLossAlgorithmTest, DontEarlyRetransmitNeuteredPacket) {
for (size_t i = 1; i <= kNumSentPackets; ++i) {
SendDataPacket(i);
}
+ // Neuter packet 1.
+ unacked_packets_.RemoveRetransmittability(1);
+
// Early retransmit when the final packet gets acked and the first is nacked.
- unacked_packets_.SetNotPending(2);
+ unacked_packets_.IncreaseLargestObserved(2);
+ unacked_packets_.RemoveFromInFlight(2);
unacked_packets_.NackPacket(1, 1);
- unacked_packets_.RemoveRetransmittability(1, 1);
VerifyLosses(2, NULL, 0);
EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
}
diff --git a/net/quic/congestion_control/time_loss_algorithm.cc b/net/quic/congestion_control/time_loss_algorithm.cc
index 6cf1d81..d23dead 100644
--- a/net/quic/congestion_control/time_loss_algorithm.cc
+++ b/net/quic/congestion_control/time_loss_algorithm.cc
@@ -41,7 +41,7 @@ SequenceNumberSet TimeLossAlgorithm::DetectLostPackets(
for (QuicUnackedPacketMap::const_iterator it = unacked_packets.begin();
it != unacked_packets.end() && it->first <= largest_observed; ++it) {
- if (!it->second.pending) {
+ if (!it->second.in_flight) {
continue;
}
LOG_IF(DFATAL, it->second.nack_count == 0)
diff --git a/net/quic/congestion_control/time_loss_algorithm_test.cc b/net/quic/congestion_control/time_loss_algorithm_test.cc
index 42ca030..bd03e60 100644
--- a/net/quic/congestion_control/time_loss_algorithm_test.cc
+++ b/net/quic/congestion_control/time_loss_algorithm_test.cc
@@ -55,7 +55,7 @@ TEST_F(TimeLossAlgorithmTest, NoLossFor500Nacks) {
for (size_t i = 1; i <= kNumSentPackets; ++i) {
SendDataPacket(i);
}
- unacked_packets_.SetNotPending(2);
+ unacked_packets_.RemoveFromInFlight(2);
for (size_t i = 1; i < 500; ++i) {
unacked_packets_.NackPacket(1, i);
VerifyLosses(2, NULL, 0);
@@ -75,7 +75,7 @@ TEST_F(TimeLossAlgorithmTest, NoLossUntilTimeout) {
EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
// The packet should not be lost until 1.25 RTTs pass.
unacked_packets_.NackPacket(1, 1);
- unacked_packets_.SetNotPending(2);
+ unacked_packets_.RemoveFromInFlight(2);
VerifyLosses(2, NULL, 0);
// Expect the timer to be set to 0.25 RTT's in the future.
EXPECT_EQ(rtt_stats_.SmoothedRtt().Multiply(0.25),
@@ -98,7 +98,7 @@ TEST_F(TimeLossAlgorithmTest, NoLossWithoutNack) {
// Expect the timer to not be set.
EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
// The packet should not be lost without a nack.
- unacked_packets_.SetNotPending(1);
+ unacked_packets_.RemoveFromInFlight(1);
VerifyLosses(1, NULL, 0);
// The timer should still not be set.
EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
@@ -123,7 +123,7 @@ TEST_F(TimeLossAlgorithmTest, MultipleLossesAtOnce) {
for (size_t i = 1; i < kNumSentPackets; ++i) {
unacked_packets_.NackPacket(i, 1);
}
- unacked_packets_.SetNotPending(10);
+ unacked_packets_.RemoveFromInFlight(10);
VerifyLosses(10, NULL, 0);
// Expect the timer to be set to 0.25 RTT's in the future.
EXPECT_EQ(rtt_stats_.SmoothedRtt().Multiply(0.25),
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc
index e5fb0f8..8162c3c 100644
--- a/net/quic/quic_connection.cc
+++ b/net/quic/quic_connection.cc
@@ -1466,8 +1466,8 @@ bool QuicConnection::ShouldDiscardPacket(
if (retransmittable == HAS_RETRANSMITTABLE_DATA &&
!sent_packet_manager_.HasRetransmittableFrames(sequence_number)) {
- LOG(DFATAL) << ENDPOINT << "Dropping unacked packet: " << sequence_number
- << " This should have been removed when it was Neutered.";
+ DVLOG(1) << ENDPOINT << "Dropping unacked packet: " << sequence_number
+ << " A previous transmission was acked while write blocked.";
return true;
}
@@ -1944,7 +1944,11 @@ QuicConnection::ScopedPacketBundler::ScopedPacketBundler(
QuicConnection* connection,
AckBundling send_ack)
: connection_(connection),
- already_in_batch_mode_(connection->packet_generator_.InBatchMode()) {
+ already_in_batch_mode_(connection != NULL &&
+ connection->packet_generator_.InBatchMode()) {
+ if (connection_ == NULL) {
+ return;
+ }
// Move generator into batch mode. If caller wants us to include an ack,
// check the delayed-ack timer to see if there's ack info to be sent.
if (!already_in_batch_mode_) {
@@ -1962,6 +1966,9 @@ QuicConnection::ScopedPacketBundler::ScopedPacketBundler(
}
QuicConnection::ScopedPacketBundler::~ScopedPacketBundler() {
+ if (connection_ == NULL) {
+ return;
+ }
// If we changed the generator's batch state, restore original batch state.
if (!already_in_batch_mode_) {
DVLOG(1) << "Leaving Batch Mode.";
diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc
index 2c0fecc..603680f 100644
--- a/net/quic/quic_connection_test.cc
+++ b/net/quic/quic_connection_test.cc
@@ -1433,8 +1433,12 @@ TEST_P(QuicConnectionTest, BasicSending) {
TEST_P(QuicConnectionTest, FECSending) {
// All packets carry version info till version is negotiated.
size_t payload_length;
- connection_.options()->max_packet_length =
- GetPacketLengthForOneStream(
+ // GetPacketLengthForOneStream() assumes a stream offset of 0 in determining
+ // packet length. The size of the offset field in a stream frame is 0 for
+ // offset 0, and 2 for non-zero offsets up through 16K. Increase
+ // max_packet_length by 2 so that subsequent packets containing subsequent
+ // stream frames with non-zero offets will fit within the packet length.
+ connection_.options()->max_packet_length = 2 + GetPacketLengthForOneStream(
connection_.version(), kIncludeVersion, PACKET_1BYTE_SEQUENCE_NUMBER,
IN_FEC_GROUP, &payload_length);
// And send FEC every two packets.
@@ -1443,8 +1447,8 @@ TEST_P(QuicConnectionTest, FECSending) {
// Send 4 data packets and 2 FEC packets.
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(6);
- // The first stream frame will consume 2 fewer bytes than the other three.
- const string payload(payload_length * 4 - 6, 'a');
+ // The first stream frame will have 2 fewer overhead bytes than the other 3.
+ const string payload(payload_length * 4 + 2, 'a');
connection_.SendStreamDataWithString(1, payload, 0, !kFin, NULL);
// Expect the FEC group to be closed after SendStreamDataWithString.
EXPECT_FALSE(creator_.ShouldSendFec(true));
@@ -1958,9 +1962,9 @@ TEST_P(QuicConnectionTest, RetransmitWriteBlockedAckedOriginalThenSent) {
ProcessAckPacket(&ack);
connection_.OnPacketSent(WriteResult(WRITE_STATUS_OK, 0));
- // The retransmission alarm should not be set because there are
- // no unacked packets.
- EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
+ // There is now a pending packet, but with no retransmittable frames.
+ EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
+ EXPECT_FALSE(connection_.sent_packet_manager().HasRetransmittableFrames(2));
}
TEST_P(QuicConnectionTest, AlarmsWhenWriteBlocked) {
@@ -2885,15 +2889,19 @@ TEST_P(QuicConnectionTest, TestQueueLimitsOnSendStreamData) {
TEST_P(QuicConnectionTest, LoopThroughSendingPackets) {
// All packets carry version info till version is negotiated.
size_t payload_length;
- connection_.options()->max_packet_length =
- GetPacketLengthForOneStream(
+ // GetPacketLengthForOneStream() assumes a stream offset of 0 in determining
+ // packet length. The size of the offset field in a stream frame is 0 for
+ // offset 0, and 2 for non-zero offsets up through 16K. Increase
+ // max_packet_length by 2 so that subsequent packets containing subsequent
+ // stream frames with non-zero offets will fit within the packet length.
+ connection_.options()->max_packet_length = 2 + GetPacketLengthForOneStream(
connection_.version(), kIncludeVersion, PACKET_1BYTE_SEQUENCE_NUMBER,
NOT_IN_FEC_GROUP, &payload_length);
// Queue the first packet.
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(7);
- // The first stream frame will consume 2 fewer bytes than the other six.
- const string payload(payload_length * 7 - 12, 'a');
+ // The first stream frame will have 2 fewer overhead bytes than the other six.
+ const string payload(payload_length * 7 + 2, 'a');
EXPECT_EQ(payload.size(),
connection_.SendStreamDataWithString(1, payload, 0,
!kFin, NULL).bytes_consumed);
diff --git a/net/quic/quic_data_stream_test.cc b/net/quic/quic_data_stream_test.cc
index 7740337..6799131 100644
--- a/net/quic/quic_data_stream_test.cc
+++ b/net/quic/quic_data_stream_test.cc
@@ -100,7 +100,7 @@ class QuicDataStreamTest : public ::testing::TestWithParam<QuicVersion> {
stream2_.reset(new TestStream(kClientDataStreamId2, session_.get(),
stream_should_process_data));
write_blocked_list_ =
- QuicSessionPeer::GetWriteblockedStreams(session_.get());
+ QuicSessionPeer::GetWriteBlockedStreams(session_.get());
}
protected:
diff --git a/net/quic/quic_default_packet_writer.h b/net/quic/quic_default_packet_writer.h
index 2c03b62..66b6a0f 100644
--- a/net/quic/quic_default_packet_writer.h
+++ b/net/quic/quic_default_packet_writer.h
@@ -39,6 +39,11 @@ class NET_EXPORT_PRIVATE QuicDefaultPacketWriter : public QuicPacketWriter {
connection_ = connection;
}
+ protected:
+ void set_write_blocked(bool is_blocked) {
+ write_blocked_ = is_blocked;
+ }
+
private:
base::WeakPtrFactory<QuicDefaultPacketWriter> weak_factory_;
DatagramClientSocket* socket_;
diff --git a/net/quic/quic_framer.cc b/net/quic/quic_framer.cc
index 09cd43d..8ff2ee7 100644
--- a/net/quic/quic_framer.cc
+++ b/net/quic/quic_framer.cc
@@ -198,9 +198,12 @@ size_t QuicFramer::GetMinAckFrameSize(
QuicVersion version,
QuicSequenceNumberLength sequence_number_length,
QuicSequenceNumberLength largest_observed_length) {
- return kQuicFrameTypeSize + kQuicEntropyHashSize +
- sequence_number_length + kQuicEntropyHashSize +
+ size_t len = kQuicFrameTypeSize + kQuicEntropyHashSize +
largest_observed_length + kQuicDeltaTimeLargestObservedSize;
+ if (version <= QUIC_VERSION_15) {
+ len += sequence_number_length + kQuicEntropyHashSize;
+ }
+ return len;
}
// static
@@ -298,21 +301,25 @@ size_t QuicFramer::GetSerializedFrameLength(
size_t frame_len =
ComputeFrameLength(frame, last_frame, is_in_fec_group,
sequence_number_length);
- if (frame_len > free_bytes) {
- // Only truncate the first frame in a packet, so if subsequent ones go
- // over, stop including more frames.
- if (!first_frame) {
- return 0;
- }
- if (CanTruncate(quic_version_, frame, free_bytes)) {
- // Truncate the frame so the packet will not exceed kMaxPacketSize.
- // Note that we may not use every byte of the writer in this case.
- DVLOG(1) << "Truncating large frame";
- return free_bytes;
- } else if (!FLAGS_quic_allow_oversized_packets_for_test) {
- return 0;
- }
+ if (frame_len <= free_bytes) {
+ // Frame fits within packet. Note that acks may be truncated.
+ return frame_len;
}
+ // Only truncate the first frame in a packet, so if subsequent ones go
+ // over, stop including more frames.
+ if (!first_frame) {
+ return 0;
+ }
+ if (CanTruncate(quic_version_, frame, free_bytes)) {
+ // Truncate the frame so the packet will not exceed kMaxPacketSize.
+ // Note that we may not use every byte of the writer in this case.
+ DVLOG(1) << "Truncating large frame, free bytes: " << free_bytes;
+ return free_bytes;
+ }
+ if (!FLAGS_quic_allow_oversized_packets_for_test) {
+ return 0;
+ }
+ LOG(DFATAL) << "Packet size too small to fit frame.";
return frame_len;
}
@@ -1818,11 +1825,11 @@ size_t QuicFramer::GetAckFrameSize(
sequence_number_length,
largest_observed_length);
if (!ack_info.nack_ranges.empty()) {
- ack_size += kNumberOfMissingPacketsSize + kNumberOfRevivedPacketsSize;
- ack_size += ack_info.nack_ranges.size() *
+ ack_size += kNumberOfNackRangesSize + kNumberOfRevivedPacketsSize;
+ ack_size += min(ack_info.nack_ranges.size(), kMaxNackRanges) *
(missing_sequence_number_length + PACKET_1BYTE_SEQUENCE_NUMBER);
- ack_size +=
- ack.received_info.revived_packets.size() * largest_observed_length;
+ ack_size += min(ack.received_info.revived_packets.size(),
+ kMaxRevivedPackets) * largest_observed_length;
}
return ack_size;
}
@@ -2028,18 +2035,17 @@ bool QuicFramer::AppendAckFrameAndTypeByte(
GetMinSequenceNumberLength(ack_info.max_delta);
// Determine whether we need to truncate ranges.
size_t available_range_bytes = writer->capacity() - writer->length() -
+ kNumberOfRevivedPacketsSize - kNumberOfNackRangesSize -
GetMinAckFrameSize(quic_version_,
header.public_header.sequence_number_length,
- largest_observed_length) - kNumberOfRevivedPacketsSize;
+ largest_observed_length);
size_t max_num_ranges = available_range_bytes /
(missing_sequence_number_length + PACKET_1BYTE_SEQUENCE_NUMBER);
- max_num_ranges =
- min(static_cast<size_t>(numeric_limits<uint8>::max()), max_num_ranges);
+ max_num_ranges = min(kMaxNackRanges, max_num_ranges);
bool truncated = ack_info.nack_ranges.size() > max_num_ranges;
DVLOG_IF(1, truncated) << "Truncating ack from "
<< ack_info.nack_ranges.size() << " ranges to "
<< max_num_ranges;
-
// Write out the type byte by setting the low order bits and doing shifts
// to make room for the next bit flags to be set.
// Whether there are any nacks.
@@ -2141,9 +2147,8 @@ bool QuicFramer::AppendAckFrameAndTypeByte(
// Append revived packets.
// If not all the revived packets fit, only mention the ones that do.
- uint8 num_revived_packets =
- min(received_info.revived_packets.size(),
- static_cast<size_t>(numeric_limits<uint8>::max()));
+ uint8 num_revived_packets = min(received_info.revived_packets.size(),
+ kMaxRevivedPackets);
num_revived_packets = min(
static_cast<size_t>(num_revived_packets),
(writer->capacity() - writer->length()) / largest_observed_length);
diff --git a/net/quic/quic_framer.h b/net/quic/quic_framer.h
index 34bba98..a7e8a08 100644
--- a/net/quic/quic_framer.h
+++ b/net/quic/quic_framer.h
@@ -46,9 +46,15 @@ const size_t kQuicEntropyHashSize = 1;
// sequence number in ack frames.
const size_t kQuicDeltaTimeLargestObservedSize = 2;
// Size in bytes reserved for the number of missing packets in ack frames.
-const size_t kNumberOfMissingPacketsSize = 1;
+const size_t kNumberOfNackRangesSize = 1;
+// Maximum number of missing packet ranges that can fit within an ack frame.
+const size_t kMaxNackRanges =
+ (1 << (kNumberOfNackRangesSize * 8)) - 1;
// Size in bytes reserved for the number of revived packets in ack frames.
const size_t kNumberOfRevivedPacketsSize = 1;
+// Maximum number of revived packets that can fit within an ack frame.
+const size_t kMaxRevivedPackets =
+ (1 << (kNumberOfRevivedPacketsSize * 8)) - 1;
// This class receives callbacks from the framer when packets
// are processed.
diff --git a/net/quic/quic_framer_test.cc b/net/quic/quic_framer_test.cc
index e445008..5dd3e35 100644
--- a/net/quic/quic_framer_test.cc
+++ b/net/quic/quic_framer_test.cc
@@ -1489,8 +1489,8 @@ TEST_P(QuicFramerTest, StreamFrameWithVersion) {
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
- EXPECT_TRUE(visitor_.header_.get()->public_header.version_flag);
- EXPECT_EQ(GetParam(), visitor_.header_.get()->public_header.versions[0]);
+ EXPECT_TRUE(visitor_.header_->public_header.version_flag);
+ EXPECT_EQ(GetParam(), visitor_.header_->public_header.versions[0]);
EXPECT_TRUE(CheckDecryption(encrypted, kIncludeVersion));
ASSERT_EQ(1u, visitor_.stream_frames_.size());
@@ -1750,7 +1750,7 @@ TEST_P(QuicFramerTest, AckFrame15) {
const size_t kNumMissingPacketOffset = kMissingDeltaTimeOffset +
kQuicDeltaTimeLargestObservedSize;
const size_t kMissingPacketsOffset = kNumMissingPacketOffset +
- kNumberOfMissingPacketsSize;
+ kNumberOfNackRangesSize;
const size_t kMissingPacketsRange = kMissingPacketsOffset +
PACKET_1BYTE_SEQUENCE_NUMBER;
const size_t kRevivedPacketsLength = kMissingPacketsRange +
@@ -1849,7 +1849,7 @@ TEST_P(QuicFramerTest, AckFrame) {
const size_t kNumMissingPacketOffset = kMissingDeltaTimeOffset +
kQuicDeltaTimeLargestObservedSize;
const size_t kMissingPacketsOffset = kNumMissingPacketOffset +
- kNumberOfMissingPacketsSize;
+ kNumberOfNackRangesSize;
const size_t kMissingPacketsRange = kMissingPacketsOffset +
PACKET_1BYTE_SEQUENCE_NUMBER;
const size_t kRevivedPacketsLength = kMissingPacketsRange +
@@ -1947,7 +1947,7 @@ TEST_P(QuicFramerTest, AckFrameRevivedPackets) {
const size_t kNumMissingPacketOffset = kMissingDeltaTimeOffset +
kQuicDeltaTimeLargestObservedSize;
const size_t kMissingPacketsOffset = kNumMissingPacketOffset +
- kNumberOfMissingPacketsSize;
+ kNumberOfNackRangesSize;
const size_t kMissingPacketsRange = kMissingPacketsOffset +
PACKET_1BYTE_SEQUENCE_NUMBER;
const size_t kRevivedPacketsLength = kMissingPacketsRange +
@@ -2061,7 +2061,7 @@ TEST_P(QuicFramerTest, AckFrameRevivedPackets15) {
const size_t kNumMissingPacketOffset = kMissingDeltaTimeOffset +
kQuicDeltaTimeLargestObservedSize;
const size_t kMissingPacketsOffset = kNumMissingPacketOffset +
- kNumberOfMissingPacketsSize;
+ kNumberOfNackRangesSize;
const size_t kMissingPacketsRange = kMissingPacketsOffset +
PACKET_1BYTE_SEQUENCE_NUMBER;
const size_t kRevivedPacketsLength = kMissingPacketsRange +
@@ -3722,6 +3722,193 @@ TEST_P(QuicFramerTest, BuildAckFramePacket15) {
AsChars(packet), arraysize(packet));
}
+// TODO(jri): Add test for tuncated packets in which the original ack frame had
+// revived packets. (In both the large and small packet cases below).
+TEST_P(QuicFramerTest, BuildTruncatedAckFrameLargePacket) {
+ if (version_ <= QUIC_VERSION_15) {
+ return;
+ }
+ QuicPacketHeader header;
+ header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210);
+ header.public_header.reset_flag = false;
+ header.public_header.version_flag = false;
+ header.fec_flag = false;
+ header.entropy_flag = true;
+ header.packet_sequence_number = GG_UINT64_C(0x770123456789AA8);
+ header.fec_group = 0;
+
+ QuicAckFrame ack_frame;
+ // This entropy hash is different from what shows up in the packet below,
+ // since entropy is recomputed by the framer on ack truncation (by
+ // TestEntropyCalculator for this test.)
+ ack_frame.received_info.entropy_hash = 0x43;
+ ack_frame.received_info.largest_observed = 2 * 300;
+ ack_frame.received_info.delta_time_largest_observed = QuicTime::Delta::Zero();
+ for (size_t i = 1; i < 2 * 300; i += 2) {
+ ack_frame.received_info.missing_packets.insert(i);
+ }
+
+ QuicFrames frames;
+ frames.push_back(QuicFrame(&ack_frame));
+
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x3C,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet sequence number
+ 0xA8, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags (entropy)
+ 0x01,
+
+ // frame type (ack frame)
+ // (has nacks, is truncated, 2 byte largest observed, 1 byte delta)
+ 0x74,
+ // entropy hash of all received packets, set to 1 by TestEntropyCalculator
+ // since ack is truncated.
+ 0x01,
+ // 2-byte largest observed packet sequence number.
+ // Expected to be 510 (0x1FE), since only 255 nack ranges can fit.
+ 0xFE, 0x01,
+ // Zero delta time.
+ 0x0, 0x0,
+ // num missing packet ranges (limited to 255 by size of this field).
+ 0xFF,
+ // {missing packet delta, further missing packets in range}
+ // 6 nack ranges x 42 + 3 nack ranges
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+
+ // 0 revived packets.
+ 0x00,
+ };
+
+ scoped_ptr<QuicPacket> data(
+ framer_.BuildDataPacket(header, frames, kMaxPacketSize).packet);
+ ASSERT_TRUE(data != NULL);
+
+ test::CompareCharArraysWithHexError("constructed packet",
+ data->data(), data->length(),
+ AsChars(packet), arraysize(packet));
+}
+
+
+TEST_P(QuicFramerTest, BuildTruncatedAckFrameSmallPacket) {
+ if (version_ <= QUIC_VERSION_15) {
+ return;
+ }
+ QuicPacketHeader header;
+ header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210);
+ header.public_header.reset_flag = false;
+ header.public_header.version_flag = false;
+ header.fec_flag = false;
+ header.entropy_flag = true;
+ header.packet_sequence_number = GG_UINT64_C(0x770123456789AA8);
+ header.fec_group = 0;
+
+ QuicAckFrame ack_frame;
+ // This entropy hash is different from what shows up in the packet below,
+ // since entropy is recomputed by the framer on ack truncation (by
+ // TestEntropyCalculator for this test.)
+ ack_frame.received_info.entropy_hash = 0x43;
+ ack_frame.received_info.largest_observed = 2 * 300;
+ ack_frame.received_info.delta_time_largest_observed = QuicTime::Delta::Zero();
+ for (size_t i = 1; i < 2 * 300; i += 2) {
+ ack_frame.received_info.missing_packets.insert(i);
+ }
+
+ QuicFrames frames;
+ frames.push_back(QuicFrame(&ack_frame));
+
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x3C,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet sequence number
+ 0xA8, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags (entropy)
+ 0x01,
+
+ // frame type (ack frame)
+ // (has nacks, is truncated, 2 byte largest observed, 1 byte delta)
+ 0x74,
+ // entropy hash of all received packets, set to 1 by TestEntropyCalculator
+ // since ack is truncated.
+ 0x01,
+ // 2-byte largest observed packet sequence number.
+ // Expected to be 12 (0x0C), since only 6 nack ranges can fit.
+ 0x0C, 0x00,
+ // Zero delta time.
+ 0x0, 0x0,
+ // num missing packet ranges (limited to 6 by packet size of 37).
+ 0x06,
+ // {missing packet delta, further missing packets in range}
+ // 6 nack ranges
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ // 0 revived packets.
+ 0x00,
+ };
+
+ scoped_ptr<QuicPacket> data(
+ framer_.BuildDataPacket(header, frames, 37u).packet);
+ ASSERT_TRUE(data != NULL);
+ // Expect 1 byte unused since at least 2 bytes are needed to fit more nacks.
+ EXPECT_EQ(36u, data->length());
+ test::CompareCharArraysWithHexError("constructed packet",
+ data->data(), data->length(),
+ AsChars(packet), arraysize(packet));
+}
+
TEST_P(QuicFramerTest, BuildCongestionFeedbackFramePacketTCP) {
QuicPacketHeader header;
header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210);
@@ -4470,7 +4657,7 @@ TEST_P(QuicFramerTest, EncryptPacketWithVersionFlag) {
EXPECT_TRUE(CheckEncryption(sequence_number, raw.get()));
}
-TEST_P(QuicFramerTest, Truncation) {
+TEST_P(QuicFramerTest, AckTruncationLargePacket) {
if (framer_.version() <= QUIC_VERSION_15) {
return;
}
@@ -4483,31 +4670,25 @@ TEST_P(QuicFramerTest, Truncation) {
header.packet_sequence_number = GG_UINT64_C(0x123456789ABC);
header.fec_group = 0;
- QuicAckFrame ack_frame;
- ack_frame.received_info.largest_observed = 601;
- for (uint64 i = 1; i < ack_frame.received_info.largest_observed; i += 2) {
- ack_frame.received_info.missing_packets.insert(i);
- }
-
- // Create a packet with just the ack
+ // Create a packet with just the ack.
+ QuicAckFrame ack_frame = MakeAckFrameWithNackRanges(300, 0u);
QuicFrame frame;
frame.type = ACK_FRAME;
frame.ack_frame = &ack_frame;
QuicFrames frames;
frames.push_back(frame);
+ // Build an ack packet with truncation due to limit in number of nack ranges.
scoped_ptr<QuicPacket> raw_ack_packet(
- framer_.BuildUnsizedDataPacket(header, frames).packet);
+ framer_.BuildDataPacket(header, frames, kMaxPacketSize).packet);
ASSERT_TRUE(raw_ack_packet != NULL);
-
scoped_ptr<QuicEncryptedPacket> ack_packet(
framer_.EncryptPacket(ENCRYPTION_NONE, header.packet_sequence_number,
*raw_ack_packet));
-
- // Now make sure we can turn our ack packet back into an ack frame
+ // Now make sure we can turn our ack packet back into an ack frame.
ASSERT_TRUE(framer_.ProcessPacket(*ack_packet));
ASSERT_EQ(1u, visitor_.ack_frames_.size());
- const QuicAckFrame& processed_ack_frame = *visitor_.ack_frames_[0];
+ QuicAckFrame& processed_ack_frame = *visitor_.ack_frames_[0];
EXPECT_TRUE(processed_ack_frame.received_info.is_truncated);
EXPECT_EQ(510u, processed_ack_frame.received_info.largest_observed);
ASSERT_EQ(255u, processed_ack_frame.received_info.missing_packets.size());
@@ -4519,6 +4700,49 @@ TEST_P(QuicFramerTest, Truncation) {
EXPECT_EQ(509u, *last_missing_iter);
}
+TEST_P(QuicFramerTest, AckTruncationSmallPacket) {
+ if (framer_.version() <= QUIC_VERSION_15) {
+ return;
+ }
+ QuicPacketHeader header;
+ header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210);
+ header.public_header.reset_flag = false;
+ header.public_header.version_flag = false;
+ header.fec_flag = false;
+ header.entropy_flag = false;
+ header.packet_sequence_number = GG_UINT64_C(0x123456789ABC);
+ header.fec_group = 0;
+
+ // Create a packet with just the ack.
+ QuicAckFrame ack_frame = MakeAckFrameWithNackRanges(300, 0u);
+ QuicFrame frame;
+ frame.type = ACK_FRAME;
+ frame.ack_frame = &ack_frame;
+ QuicFrames frames;
+ frames.push_back(frame);
+
+ // Build an ack packet with truncation due to limit in number of nack ranges.
+ scoped_ptr<QuicPacket> raw_ack_packet(
+ framer_.BuildDataPacket(header, frames, 500).packet);
+ ASSERT_TRUE(raw_ack_packet != NULL);
+ scoped_ptr<QuicEncryptedPacket> ack_packet(
+ framer_.EncryptPacket(ENCRYPTION_NONE, header.packet_sequence_number,
+ *raw_ack_packet));
+ // Now make sure we can turn our ack packet back into an ack frame.
+ ASSERT_TRUE(framer_.ProcessPacket(*ack_packet));
+ ASSERT_EQ(1u, visitor_.ack_frames_.size());
+ QuicAckFrame& processed_ack_frame = *visitor_.ack_frames_[0];
+ EXPECT_TRUE(processed_ack_frame.received_info.is_truncated);
+ EXPECT_EQ(476u, processed_ack_frame.received_info.largest_observed);
+ ASSERT_EQ(238u, processed_ack_frame.received_info.missing_packets.size());
+ SequenceNumberSet::const_iterator missing_iter =
+ processed_ack_frame.received_info.missing_packets.begin();
+ EXPECT_EQ(1u, *missing_iter);
+ SequenceNumberSet::const_reverse_iterator last_missing_iter =
+ processed_ack_frame.received_info.missing_packets.rbegin();
+ EXPECT_EQ(475u, *last_missing_iter);
+}
+
TEST_P(QuicFramerTest, Truncation15) {
if (framer_.version() > QUIC_VERSION_15) {
return;
@@ -4539,7 +4763,7 @@ TEST_P(QuicFramerTest, Truncation15) {
ack_frame.received_info.missing_packets.insert(i);
}
- // Create a packet with just the ack
+ // Create a packet with just the ack.
QuicFrame frame;
frame.type = ACK_FRAME;
frame.ack_frame = &ack_frame;
@@ -4554,7 +4778,7 @@ TEST_P(QuicFramerTest, Truncation15) {
framer_.EncryptPacket(ENCRYPTION_NONE, header.packet_sequence_number,
*raw_ack_packet));
- // Now make sure we can turn our ack packet back into an ack frame
+ // Now make sure we can turn our ack packet back into an ack frame.
ASSERT_TRUE(framer_.ProcessPacket(*ack_packet));
ASSERT_EQ(1u, visitor_.ack_frames_.size());
const QuicAckFrame& processed_ack_frame = *visitor_.ack_frames_[0];
@@ -4588,7 +4812,7 @@ TEST_P(QuicFramerTest, CleanTruncation) {
ack_frame.received_info.missing_packets.insert(i);
}
- // Create a packet with just the ack
+ // Create a packet with just the ack.
QuicFrame frame;
frame.type = ACK_FRAME;
frame.ack_frame = &ack_frame;
@@ -4603,7 +4827,7 @@ TEST_P(QuicFramerTest, CleanTruncation) {
framer_.EncryptPacket(ENCRYPTION_NONE, header.packet_sequence_number,
*raw_ack_packet));
- // Now make sure we can turn our ack packet back into an ack frame
+ // Now make sure we can turn our ack packet back into an ack frame.
ASSERT_TRUE(framer_.ProcessPacket(*ack_packet));
// Test for clean truncation of the ack by comparing the length of the
diff --git a/net/quic/quic_packet_creator.cc b/net/quic/quic_packet_creator.cc
index e567a05..4b64ae5 100644
--- a/net/quic/quic_packet_creator.cc
+++ b/net/quic/quic_packet_creator.cc
@@ -137,14 +137,27 @@ void QuicPacketCreator::set_max_packets_per_fec_group(
options_.max_packets_per_fec_group = max_packets_per_fec_group;
}
-InFecGroup QuicPacketCreator::MaybeStartFec() {
- if (should_fec_protect_ && fec_group_.get() == NULL) {
- DCHECK(queued_frames_.empty());
- // Set the fec group number to the sequence number of the next packet.
- fec_group_number_ = sequence_number() + 1;
- fec_group_.reset(new QuicFecGroup());
+InFecGroup QuicPacketCreator::MaybeUpdateLengthsAndStartFec() {
+ if (fec_group_.get() != NULL) {
+ // Don't update any lengths when an FEC group is open, to ensure same
+ // packet header size in all packets within a group.
+ return IN_FEC_GROUP;
+ }
+ if (!queued_frames_.empty()) {
+ // Don't change creator state if there are frames queued.
+ return fec_group_.get() == NULL ? NOT_IN_FEC_GROUP : IN_FEC_GROUP;
+ }
+ // TODO(jri): Add max_packet_length and send_connection_id_length here too.
+ sequence_number_length_ = options_.send_sequence_number_length;
+
+ if (!should_fec_protect_) {
+ return NOT_IN_FEC_GROUP;
}
- return fec_group_.get() == NULL ? NOT_IN_FEC_GROUP : IN_FEC_GROUP;
+ // Start a new FEC group since protection is on. Set the fec group number to
+ // the sequence number of the next packet.
+ fec_group_number_ = sequence_number() + 1;
+ fec_group_.reset(new QuicFecGroup());
+ return IN_FEC_GROUP;
}
// Stops serializing version of the protocol in packets sent after this call.
@@ -192,11 +205,13 @@ size_t QuicPacketCreator::StreamFramePacketOverhead(
QuicConnectionIdLength connection_id_length,
bool include_version,
QuicSequenceNumberLength sequence_number_length,
+ QuicStreamOffset offset,
InFecGroup is_in_fec_group) {
return GetPacketHeaderSize(connection_id_length, include_version,
sequence_number_length, is_in_fec_group) +
// Assumes this is a stream with a single lone packet.
- QuicFramer::GetMinStreamFrameSize(version, 1u, 0u, true, is_in_fec_group);
+ QuicFramer::GetMinStreamFrameSize(version, 1u, offset, true,
+ is_in_fec_group);
}
size_t QuicPacketCreator::CreateStreamFrame(QuicStreamId id,
@@ -207,9 +222,9 @@ size_t QuicPacketCreator::CreateStreamFrame(QuicStreamId id,
DCHECK_GT(options_.max_packet_length,
StreamFramePacketOverhead(
framer_->version(), PACKET_8BYTE_CONNECTION_ID, kIncludeVersion,
- PACKET_6BYTE_SEQUENCE_NUMBER, IN_FEC_GROUP));
+ PACKET_6BYTE_SEQUENCE_NUMBER, offset, IN_FEC_GROUP));
- InFecGroup is_in_fec_group = MaybeStartFec();
+ InFecGroup is_in_fec_group = MaybeUpdateLengthsAndStartFec();
LOG_IF(DFATAL, !HasRoomForStreamFrame(id, offset))
<< "No room for Stream frame, BytesFree: " << BytesFree()
@@ -354,22 +369,21 @@ SerializedPacket QuicPacketCreator::SerializePacket() {
size_t max_plaintext_size =
framer_->GetMaxPlaintextSize(options_.max_packet_length);
DCHECK_GE(max_plaintext_size, packet_size_);
- // ACK and CONNECTION_CLOSE Frames will be truncated only if they're
- // the first frame in the packet. If truncation is to occur, then
- // GetSerializedFrameLength will have returned all bytes free.
- bool possibly_truncated =
- packet_size_ != max_plaintext_size ||
- queued_frames_.size() != 1 ||
- (queued_frames_.back().type == ACK_FRAME ||
- queued_frames_.back().type == CONNECTION_CLOSE_FRAME);
+ // ACK Frames will be truncated only if they're the only frame in the packet,
+ // and if packet_size_ was set to max_plaintext_size. If truncation occurred,
+ // then GetSerializedFrameLength will have returned all bytes free.
+ bool possibly_truncated = packet_size_ == max_plaintext_size &&
+ queued_frames_.size() == 1 &&
+ queued_frames_.back().type == ACK_FRAME;
SerializedPacket serialized =
framer_->BuildDataPacket(header, queued_frames_, packet_size_);
LOG_IF(DFATAL, !serialized.packet)
<< "Failed to serialize " << queued_frames_.size() << " frames.";
// Because of possible truncation, we can't be confident that our
// packet size calculation worked correctly.
- if (!possibly_truncated)
+ if (!possibly_truncated) {
DCHECK_EQ(packet_size_, serialized.packet->length());
+ }
packet_size_ = 0;
queued_frames_.clear();
@@ -450,10 +464,11 @@ bool QuicPacketCreator::ShouldRetransmit(const QuicFrame& frame) {
bool QuicPacketCreator::AddFrame(const QuicFrame& frame,
bool save_retransmittable_frames) {
DVLOG(1) << "Adding frame: " << frame;
- InFecGroup is_in_fec_group = MaybeStartFec();
+ InFecGroup is_in_fec_group = MaybeUpdateLengthsAndStartFec();
+
size_t frame_len = framer_->GetSerializedFrameLength(
frame, BytesFree(), queued_frames_.empty(), true, is_in_fec_group,
- options()->send_sequence_number_length);
+ sequence_number_length_);
if (frame_len == 0) {
return false;
}
diff --git a/net/quic/quic_packet_creator.h b/net/quic/quic_packet_creator.h
index 5eadff4..36ab5df 100644
--- a/net/quic/quic_packet_creator.h
+++ b/net/quic/quic_packet_creator.h
@@ -93,6 +93,7 @@ class NET_EXPORT_PRIVATE QuicPacketCreator : public QuicFecBuilderInterface {
QuicConnectionIdLength connection_id_length,
bool include_version,
QuicSequenceNumberLength sequence_number_length,
+ QuicStreamOffset offset,
InFecGroup is_in_fec_group);
bool HasRoomForStreamFrame(QuicStreamId id, QuicStreamOffset offset) const;
@@ -221,9 +222,10 @@ class NET_EXPORT_PRIVATE QuicPacketCreator : public QuicFecBuilderInterface {
static bool ShouldRetransmit(const QuicFrame& frame);
- // Starts a new FEC group with the next serialized packet, if FEC is enabled
- // and there is not already an FEC group open.
- InFecGroup MaybeStartFec();
+ // Updates sequence number length on a packet or FEC group boundary.
+ // Also starts an FEC group if FEC protection is on and there is not already
+ // an FEC group open.
+ InFecGroup MaybeUpdateLengthsAndStartFec();
void FillPacketHeader(QuicFecGroupNumber fec_group,
bool fec_flag,
diff --git a/net/quic/quic_packet_creator_test.cc b/net/quic/quic_packet_creator_test.cc
index 3e3b228..57bf2f4 100644
--- a/net/quic/quic_packet_creator_test.cc
+++ b/net/quic/quic_packet_creator_test.cc
@@ -70,6 +70,7 @@ class QuicPacketCreatorTest : public ::testing::TestWithParam<TestParams> {
data_("foo"),
creator_(connection_id_, &client_framer_, &mock_random_, false) {
client_framer_.set_visitor(&framer_visitor_);
+ client_framer_.set_received_entropy_calculator(&entropy_calculator_);
server_framer_.set_visitor(&framer_visitor_);
}
~QuicPacketCreatorTest() {
@@ -131,6 +132,7 @@ class QuicPacketCreatorTest : public ::testing::TestWithParam<TestParams> {
string data_;
MockRandom mock_random_;
QuicPacketCreator creator_;
+ MockEntropyCalculator entropy_calculator_;
};
// Run all packet creator tests with all supported versions of QUIC, and with
@@ -253,6 +255,86 @@ TEST_P(QuicPacketCreatorTest, SerializeChangingSequenceNumberLength) {
delete serialized.packet;
}
+TEST_P(QuicPacketCreatorTest, ChangeSequenceNumberLengthMidPacket) {
+ if (GetParam().version <= QUIC_VERSION_15) {
+ return;
+ }
+ // Changing the sequence number length with queued frames in the creator
+ // should hold the change until after any currently queued frames are
+ // serialized.
+
+ // Packet 1.
+ // Queue a frame in the creator.
+ EXPECT_FALSE(creator_.HasPendingFrames());
+ QuicFrame ack_frame = QuicFrame(new QuicAckFrame(MakeAckFrame(0u, 0u)));
+ creator_.AddSavedFrame(ack_frame);
+
+ // Now change sequence number length.
+ creator_.options()->send_sequence_number_length =
+ PACKET_4BYTE_SEQUENCE_NUMBER;
+
+ // Add a STOP_WAITING frame since it contains a packet sequence number,
+ // whose length should be 1.
+ QuicStopWaitingFrame stop_waiting_frame;
+ EXPECT_TRUE(creator_.AddSavedFrame(QuicFrame(&stop_waiting_frame)));
+ EXPECT_TRUE(creator_.HasPendingFrames());
+
+ // Ensure the packet is successfully created.
+ SerializedPacket serialized = creator_.SerializePacket();
+ ASSERT_TRUE(serialized.packet);
+ EXPECT_EQ(PACKET_1BYTE_SEQUENCE_NUMBER, serialized.sequence_number_length);
+
+ // Verify that header in transmitted packet has 1 byte sequence length.
+ QuicPacketHeader header;
+ {
+ InSequence s;
+ EXPECT_CALL(framer_visitor_, OnPacket());
+ EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_));
+ EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_));
+ EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_));
+ EXPECT_CALL(framer_visitor_, OnPacketHeader(_)).WillOnce(
+ DoAll(SaveArg<0>(&header), Return(true)));
+ EXPECT_CALL(framer_visitor_, OnAckFrame(_));
+ EXPECT_CALL(framer_visitor_, OnStopWaitingFrame(_));
+ EXPECT_CALL(framer_visitor_, OnPacketComplete());
+ }
+ ProcessPacket(serialized.packet);
+ EXPECT_EQ(PACKET_1BYTE_SEQUENCE_NUMBER,
+ header.public_header.sequence_number_length);
+ delete serialized.packet;
+
+ // Packet 2.
+ EXPECT_FALSE(creator_.HasPendingFrames());
+ // Generate Packet 2 with one frame -- sequence number length should now
+ // change to 4 bytes.
+ EXPECT_TRUE(creator_.AddSavedFrame(QuicFrame(&stop_waiting_frame)));
+ EXPECT_TRUE(creator_.HasPendingFrames());
+
+ // Ensure the packet is successfully created.
+ serialized = creator_.SerializePacket();
+ ASSERT_TRUE(serialized.packet);
+ EXPECT_EQ(PACKET_4BYTE_SEQUENCE_NUMBER, serialized.sequence_number_length);
+
+ // Verify that header in transmitted packet has 4 byte sequence length.
+ {
+ InSequence s;
+ EXPECT_CALL(framer_visitor_, OnPacket());
+ EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_));
+ EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_));
+ EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_));
+ EXPECT_CALL(framer_visitor_, OnPacketHeader(_)).WillOnce(
+ DoAll(SaveArg<0>(&header), Return(true)));
+ EXPECT_CALL(framer_visitor_, OnStopWaitingFrame(_));
+ EXPECT_CALL(framer_visitor_, OnPacketComplete());
+ }
+ ProcessPacket(serialized.packet);
+ EXPECT_EQ(PACKET_4BYTE_SEQUENCE_NUMBER,
+ header.public_header.sequence_number_length);
+
+ delete serialized.packet;
+ delete ack_frame.ack_frame;
+}
+
TEST_P(QuicPacketCreatorTest, SerializeWithFECChangingSequenceNumberLength) {
// Test goal is to test the following sequence (P1 => generate Packet 1):
// P1 <change seq num length> P2 FEC,
@@ -653,7 +735,7 @@ TEST_P(QuicPacketCreatorTest, SerializeVersionNegotiationPacket) {
EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_));
EXPECT_CALL(framer_visitor_, OnVersionNegotiationPacket(_));
}
- client_framer_.ProcessPacket(*encrypted.get());
+ client_framer_.ProcessPacket(*encrypted);
}
TEST_P(QuicPacketCreatorTest, UpdatePacketSequenceNumberLengthLeastAwaiting) {
@@ -825,6 +907,85 @@ TEST_P(QuicPacketCreatorTest, AddFrameAndSerialize) {
creator_.BytesFree());
}
+TEST_P(QuicPacketCreatorTest, SerializeTruncatedAckFrameWithLargePacketSize) {
+ if (!GetParam().version_serialization) {
+ creator_.StopSendingVersion();
+ }
+ creator_.options()->max_packet_length = kMaxPacketSize;
+ const size_t max_plaintext_size =
+ client_framer_.GetMaxPlaintextSize(creator_.options()->max_packet_length);
+
+ // Serialized length of ack frame with 2000 nack ranges should be limited by
+ // the number of nack ranges that can be fit in an ack frame.
+ QuicAckFrame ack_frame = MakeAckFrameWithNackRanges(2000u, 0u);
+ size_t frame_len = client_framer_.GetSerializedFrameLength(
+ QuicFrame(&ack_frame), creator_.BytesFree(), true, true,
+ NOT_IN_FEC_GROUP, PACKET_1BYTE_SEQUENCE_NUMBER);
+ EXPECT_GT(creator_.BytesFree(), frame_len);
+ EXPECT_GT(max_plaintext_size, creator_.PacketSize());
+
+ // Add ack frame to creator.
+ EXPECT_TRUE(creator_.AddSavedFrame(QuicFrame(&ack_frame)));
+ EXPECT_TRUE(creator_.HasPendingFrames());
+ EXPECT_GT(max_plaintext_size, creator_.PacketSize());
+ EXPECT_LT(0u, creator_.BytesFree());
+
+ // Make sure that an additional stream frame can be added to the packet.
+ QuicFrame stream_frame;
+ size_t consumed = creator_.CreateStreamFrame(
+ 2u, MakeIOVector("test"), 0u, false, &stream_frame);
+ EXPECT_EQ(4u, consumed);
+ ASSERT_TRUE(stream_frame.stream_frame);
+ EXPECT_TRUE(creator_.AddSavedFrame(stream_frame));
+ EXPECT_TRUE(creator_.HasPendingFrames());
+
+ // Ensure the packet is successfully created, and the packet size estimate
+ // matches the serialized packet length.
+ EXPECT_CALL(entropy_calculator_,
+ EntropyHash(_)).WillOnce(testing::Return(0));
+ size_t est_packet_size = creator_.PacketSize();
+ SerializedPacket serialized = creator_.SerializePacket();
+ ASSERT_TRUE(serialized.packet);
+ EXPECT_EQ(est_packet_size, serialized.packet->length());
+ delete serialized.retransmittable_frames;
+ delete serialized.packet;
+}
+
+TEST_P(QuicPacketCreatorTest, SerializeTruncatedAckFrameWithSmallPacketSize) {
+ if (!GetParam().version_serialization) {
+ creator_.StopSendingVersion();
+ }
+ creator_.options()->max_packet_length = 500u;
+ const size_t max_plaintext_size =
+ client_framer_.GetMaxPlaintextSize(creator_.options()->max_packet_length);
+ EXPECT_EQ(max_plaintext_size - creator_.PacketSize(), creator_.BytesFree());
+
+ // Serialized length of ack frame with 2000 nack ranges should be limited by
+ // the packet size.
+ QuicAckFrame ack_frame = MakeAckFrameWithNackRanges(2000u, 0u);
+ size_t frame_len = client_framer_.GetSerializedFrameLength(
+ QuicFrame(&ack_frame), creator_.BytesFree(), true, true,
+ NOT_IN_FEC_GROUP, PACKET_1BYTE_SEQUENCE_NUMBER);
+ EXPECT_EQ(creator_.BytesFree(), frame_len);
+
+ // Add ack frame to creator.
+ EXPECT_TRUE(creator_.AddSavedFrame(QuicFrame(&ack_frame)));
+ EXPECT_TRUE(creator_.HasPendingFrames());
+ EXPECT_EQ(max_plaintext_size, creator_.PacketSize());
+ EXPECT_EQ(0u, creator_.BytesFree());
+
+ // Ensure the packet is successfully created, and the packet size estimate
+ // may not match the serialized packet length.
+ EXPECT_CALL(entropy_calculator_,
+ EntropyHash(_)).WillOnce(Return(0));
+ size_t est_packet_size = creator_.PacketSize();
+ SerializedPacket serialized = creator_.SerializePacket();
+ ASSERT_TRUE(serialized.packet);
+ EXPECT_GE(est_packet_size, serialized.packet->length());
+ delete serialized.packet;
+}
+
+
TEST_P(QuicPacketCreatorTest, EntropyFlag) {
frames_.push_back(QuicFrame(new QuicStreamFrame(0u, false, 0u, IOVector())));
diff --git a/net/quic/quic_protocol.cc b/net/quic/quic_protocol.cc
index 0f92e45..df3bfa5 100644
--- a/net/quic/quic_protocol.cc
+++ b/net/quic/quic_protocol.cc
@@ -747,7 +747,7 @@ TransmissionInfo::TransmissionInfo()
bytes_sent(0),
nack_count(0),
all_transmissions(NULL),
- pending(false) { }
+ in_flight(false) { }
TransmissionInfo::TransmissionInfo(
RetransmittableFrames* retransmittable_frames,
@@ -759,7 +759,7 @@ TransmissionInfo::TransmissionInfo(
bytes_sent(0),
nack_count(0),
all_transmissions(new SequenceNumberSet),
- pending(false) {
+ in_flight(false) {
all_transmissions->insert(sequence_number);
}
@@ -774,7 +774,7 @@ TransmissionInfo::TransmissionInfo(
bytes_sent(0),
nack_count(0),
all_transmissions(all_transmissions),
- pending(false) {
+ in_flight(false) {
all_transmissions->insert(sequence_number);
}
diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h
index 93236bb..b833b9f 100644
--- a/net/quic/quic_protocol.h
+++ b/net/quic/quic_protocol.h
@@ -1037,8 +1037,8 @@ struct NET_EXPORT_PRIVATE TransmissionInfo {
// Stores the sequence numbers of all transmissions of this packet.
// Can never be null.
SequenceNumberSet* all_transmissions;
- // Pending packets have not been abandoned or lost.
- bool pending;
+ // In flight packets have not been abandoned or lost.
+ bool in_flight;
};
// A struct for functions which consume data payloads and fins.
diff --git a/net/quic/quic_sent_packet_manager.cc b/net/quic/quic_sent_packet_manager.cc
index eefb320..eaf66bd 100644
--- a/net/quic/quic_sent_packet_manager.cc
+++ b/net/quic/quic_sent_packet_manager.cc
@@ -126,8 +126,11 @@ void QuicSentPacketManager::OnIncomingAck(
// We rely on delta_time_largest_observed to compute an RTT estimate, so
// we only update rtt when the largest observed gets acked.
- largest_observed_ = received_info.largest_observed;
bool largest_observed_acked = MaybeUpdateRTT(received_info, ack_receive_time);
+ if (largest_observed_ < received_info.largest_observed) {
+ largest_observed_ = received_info.largest_observed;
+ unacked_packets_.IncreaseLargestObserved(largest_observed_);
+ }
HandleAckForSentPackets(received_info);
InvokeLossDetection(ack_receive_time);
MaybeInvokeCongestionEvent(largest_observed_acked, bytes_in_flight);
@@ -175,36 +178,28 @@ void QuicSentPacketManager::HandleAckForSentPackets(
}
if (IsAwaitingPacket(received_info, sequence_number)) {
- // Remove any rtt only packets less than or equal to the largest observed,
- // since they will not produce an RTT measurement.
- if (QuicUnackedPacketMap::IsForRttOnly(it->second)) {
- ++it;
- unacked_packets_.RemoveRttOnlyPacket(sequence_number);
- } else {
- // Consider it multiple nacks when there is a gap between the missing
- // packet and the largest observed, since the purpose of a nack
- // threshold is to tolerate re-ordering. This handles both StretchAcks
- // and Forward Acks.
- // The nack count only increases when the largest observed increases.
- size_t min_nacks = received_info.largest_observed - sequence_number;
- // Truncated acks can nack the largest observed, so use a min of 1.
- if (min_nacks == 0) {
- min_nacks = 1;
- }
- unacked_packets_.NackPacket(sequence_number, min_nacks);
- ++it;
+ // Consider it multiple nacks when there is a gap between the missing
+ // packet and the largest observed, since the purpose of a nack
+ // threshold is to tolerate re-ordering. This handles both StretchAcks
+ // and Forward Acks.
+ // The nack count only increases when the largest observed increases.
+ size_t min_nacks = received_info.largest_observed - sequence_number;
+ // Truncated acks can nack the largest observed, so use a min of 1.
+ if (min_nacks == 0) {
+ min_nacks = 1;
}
+ unacked_packets_.NackPacket(sequence_number, min_nacks);
+ ++it;
continue;
}
-
// Packet was acked, so remove it from our unacked packet list.
DVLOG(1) << ENDPOINT << "Got an ack for packet " << sequence_number;
// If data is associated with the most recent transmission of this
// packet, then inform the caller.
- if (it->second.pending) {
+ if (it->second.in_flight) {
packets_acked_[sequence_number] = it->second;
}
- it = MarkPacketHandled(sequence_number, delta_largest_observed);
+ it = MarkPacketHandled(it, delta_largest_observed);
}
// Discard any retransmittable frames associated with revived packets.
@@ -222,45 +217,36 @@ bool QuicSentPacketManager::HasRetransmittableFrames(
void QuicSentPacketManager::RetransmitUnackedPackets(
RetransmissionType retransmission_type) {
- QuicUnackedPacketMap::const_iterator unacked_it = unacked_packets_.begin();
- while (unacked_it != unacked_packets_.end()) {
- const RetransmittableFrames* frames =
- unacked_it->second.retransmittable_frames;
- // Only mark it as handled if it can't be retransmitted and there are no
- // pending retransmissions which would be cleared.
- if (frames == NULL && unacked_it->second.all_transmissions->size() == 1 &&
- retransmission_type == ALL_PACKETS) {
- unacked_it = MarkPacketHandled(unacked_it->first,
- QuicTime::Delta::Zero());
- continue;
- }
- // If it had no other transmissions, we handle it above. If it has
- // other transmissions, one of them must have retransmittable frames,
- // so that gets resolved the same way as other retransmissions.
+ QuicUnackedPacketMap::const_iterator it = unacked_packets_.begin();
+ while (it != unacked_packets_.end()) {
+ const RetransmittableFrames* frames = it->second.retransmittable_frames;
// TODO(ianswett): Consider adding a new retransmission type which removes
// all these old packets from unacked and retransmits them as new sequence
// numbers with no connection to the previous ones.
if (frames != NULL && (retransmission_type == ALL_PACKETS ||
frames->encryption_level() == ENCRYPTION_INITIAL)) {
- MarkForRetransmission(unacked_it->first, ALL_UNACKED_RETRANSMISSION);
+ MarkForRetransmission(it->first, ALL_UNACKED_RETRANSMISSION);
}
- ++unacked_it;
+ ++it;
}
}
void QuicSentPacketManager::NeuterUnencryptedPackets() {
- for (QuicUnackedPacketMap::const_iterator it = unacked_packets_.begin();
- it != unacked_packets_.end(); ++it) {
- const RetransmittableFrames* frames =
- it->second.retransmittable_frames;
+ QuicUnackedPacketMap::const_iterator it = unacked_packets_.begin();
+ while (it != unacked_packets_.end()) {
+ const RetransmittableFrames* frames = it->second.retransmittable_frames;
+ QuicPacketSequenceNumber sequence_number = it->first;
+ ++it;
if (frames != NULL && frames->encryption_level() == ENCRYPTION_NONE) {
// Once you're forward secure, no unencrypted packets will be sent, crypto
// or otherwise. Unencrypted packets are neutered and abandoned, to ensure
// they are not retransmitted or considered lost from a congestion control
// perspective.
- pending_retransmissions_.erase(it->first);
- unacked_packets_.RemoveRetransmittability(it->first, largest_observed_);
- unacked_packets_.SetNotPending(it->first);
+ pending_retransmissions_.erase(sequence_number);
+ unacked_packets_.RemoveFromInFlight(sequence_number);
+ // RemoveRetransmittibility is safe because only the newest sequence
+ // number can have frames.
+ unacked_packets_.RemoveRetransmittability(sequence_number);
}
}
}
@@ -272,7 +258,7 @@ void QuicSentPacketManager::MarkForRetransmission(
unacked_packets_.GetTransmissionInfo(sequence_number);
LOG_IF(DFATAL, transmission_info.retransmittable_frames == NULL);
if (transmission_type != TLP_RETRANSMISSION) {
- unacked_packets_.SetNotPending(sequence_number);
+ unacked_packets_.RemoveFromInFlight(sequence_number);
}
// TODO(ianswett): Currently the RTO can fire while there are pending NACK
// retransmissions for the same data, which is not ideal.
@@ -339,18 +325,16 @@ void QuicSentPacketManager::MarkPacketRevived(
newest_transmission, delta_largest_observed);
}
- unacked_packets_.RemoveRetransmittability(sequence_number, largest_observed_);
+ unacked_packets_.RemoveRetransmittability(sequence_number);
}
QuicUnackedPacketMap::const_iterator QuicSentPacketManager::MarkPacketHandled(
- QuicPacketSequenceNumber sequence_number,
+ QuicUnackedPacketMap::const_iterator it,
QuicTime::Delta delta_largest_observed) {
- if (!unacked_packets_.IsUnacked(sequence_number)) {
- LOG(DFATAL) << "Packet is not unacked: " << sequence_number;
- return unacked_packets_.end();
- }
- const TransmissionInfo& transmission_info =
- unacked_packets_.GetTransmissionInfo(sequence_number);
+ LOG_IF(DFATAL, it == unacked_packets_.end())
+ << "MarkPacketHandled must be passed a valid iterator entry.";
+ const QuicPacketSequenceNumber sequence_number = it->first;
+ const TransmissionInfo& transmission_info = it->second;
QuicPacketSequenceNumber newest_transmission =
*transmission_info.all_transmissions->rbegin();
@@ -377,10 +361,10 @@ QuicUnackedPacketMap::const_iterator QuicSentPacketManager::MarkPacketHandled(
// only handle NULL encrypted packets in a special way.
if (HasCryptoHandshake(
unacked_packets_.GetTransmissionInfo(newest_transmission))) {
- unacked_packets_.SetNotPending(newest_transmission);
+ unacked_packets_.RemoveFromInFlight(newest_transmission);
}
- unacked_packets_.SetNotPending(sequence_number);
- unacked_packets_.RemoveRetransmittability(sequence_number, largest_observed_);
+ unacked_packets_.RemoveFromInFlight(sequence_number);
+ unacked_packets_.RemoveRetransmittability(sequence_number);
QuicUnackedPacketMap::const_iterator next_unacked = unacked_packets_.begin();
while (next_unacked != unacked_packets_.end() &&
@@ -426,21 +410,21 @@ bool QuicSentPacketManager::OnPacketSent(
rtt_stats_.SampleNewRecentMinRtt(kNumMinRttSamplesAfterQuiescence);
}
- // Only track packets as pending that the send algorithm wants us to track.
- const bool pending =
+ // Only track packets as in flight that the send algorithm wants us to track.
+ const bool in_flight =
send_algorithm_->OnPacketSent(sent_time,
unacked_packets_.bytes_in_flight(),
sequence_number,
bytes,
has_retransmittable_data);
- unacked_packets_.SetSent(sequence_number, sent_time, bytes, pending);
+ unacked_packets_.SetSent(sequence_number, sent_time, bytes, in_flight);
// Reset the retransmission timer anytime a pending packet is sent.
- return pending;
+ return in_flight;
}
void QuicSentPacketManager::OnRetransmissionTimeout() {
- DCHECK(unacked_packets_.HasPendingPackets());
+ DCHECK(unacked_packets_.HasInFlightPackets());
// Handshake retransmission, timer based loss detection, TLP, and RTO are
// implemented with a single alarm. The handshake alarm is set when the
// handshake has not completed, the loss alarm is set when the loss detection
@@ -482,8 +466,8 @@ void QuicSentPacketManager::RetransmitCryptoPackets() {
it != unacked_packets_.end(); ++it) {
QuicPacketSequenceNumber sequence_number = it->first;
const RetransmittableFrames* frames = it->second.retransmittable_frames;
- // Only retransmit frames which are pending, and therefore have been sent.
- if (!it->second.pending || frames == NULL ||
+ // Only retransmit frames which are in flight, and therefore have been sent.
+ if (!it->second.in_flight || frames == NULL ||
frames->HasCryptoHandshake() != IS_HANDSHAKE) {
continue;
}
@@ -500,8 +484,8 @@ void QuicSentPacketManager::RetransmitOldestPacket() {
it != unacked_packets_.end(); ++it) {
QuicPacketSequenceNumber sequence_number = it->first;
const RetransmittableFrames* frames = it->second.retransmittable_frames;
- // Only retransmit frames which are pending, and therefore have been sent.
- if (!it->second.pending || frames == NULL) {
+ // Only retransmit frames which are in flight, and therefore have been sent.
+ if (!it->second.in_flight || frames == NULL) {
continue;
}
DCHECK_NE(IS_HANDSHAKE, frames->HasCryptoHandshake());
@@ -524,13 +508,16 @@ void QuicSentPacketManager::RetransmitAllPackets() {
// immediately and the remaining packets will be queued.
// Abandon any non-retransmittable packets that are sufficiently old.
bool packets_retransmitted = false;
- for (QuicUnackedPacketMap::const_iterator it = unacked_packets_.begin();
- it != unacked_packets_.end(); ++it) {
- if (it->second.retransmittable_frames != NULL) {
+ QuicUnackedPacketMap::const_iterator it = unacked_packets_.begin();
+ while (it != unacked_packets_.end()) {
+ const RetransmittableFrames* frames = it->second.retransmittable_frames;
+ QuicPacketSequenceNumber sequence_number = it->first;
+ ++it;
+ if (frames != NULL) {
packets_retransmitted = true;
- MarkForRetransmission(it->first, RTO_RETRANSMISSION);
+ MarkForRetransmission(sequence_number, RTO_RETRANSMISSION);
} else {
- unacked_packets_.SetNotPending(it->first);
+ unacked_packets_.RemoveFromInFlight(sequence_number);
}
}
@@ -542,7 +529,7 @@ void QuicSentPacketManager::RetransmitAllPackets() {
QuicSentPacketManager::RetransmissionTimeoutMode
QuicSentPacketManager::GetRetransmissionMode() const {
- DCHECK(unacked_packets_.HasPendingPackets());
+ DCHECK(unacked_packets_.HasInFlightPackets());
if (unacked_packets_.HasPendingCryptoPackets()) {
return HANDSHAKE_MODE;
}
@@ -589,10 +576,7 @@ void QuicSentPacketManager::InvokeLossDetection(QuicTime time) {
// unacked_packets_. This is either the current transmission of
// a packet whose previous transmission has been acked, a packet that has
// been TLP retransmitted, or an FEC packet.
- unacked_packets_.SetNotPending(sequence_number);
- if (QuicUnackedPacketMap::IsForRttOnly(transmission_info)) {
- unacked_packets_.RemoveRttOnlyPacket(sequence_number);
- }
+ unacked_packets_.RemoveFromInFlight(sequence_number);
}
}
}
@@ -649,8 +633,8 @@ const QuicTime::Delta QuicSentPacketManager::DelayedAckTime() const {
}
const QuicTime QuicSentPacketManager::GetRetransmissionTime() const {
- // Don't set the timer if there are no pending packets.
- if (!unacked_packets_.HasPendingPackets()) {
+ // Don't set the timer if there are no packets in flight.
+ if (!unacked_packets_.HasInFlightPackets()) {
return QuicTime::Zero();
}
switch (GetRetransmissionMode()) {
@@ -668,9 +652,9 @@ const QuicTime QuicSentPacketManager::GetRetransmissionTime() const {
return QuicTime::Max(clock_->ApproximateNow(), tlp_time);
}
case RTO_MODE: {
- // The RTO is based on the first pending packet.
+ // The RTO is based on the first outstanding packet.
const QuicTime sent_time =
- unacked_packets_.GetFirstPendingPacketSentTime();
+ unacked_packets_.GetFirstInFlightPacketSentTime();
QuicTime rto_timeout = sent_time.Add(GetRetransmissionDelay());
// Always wait at least 1.5 * RTT from now.
QuicTime min_timeout = clock_->ApproximateNow().Add(
@@ -695,7 +679,7 @@ const QuicTime::Delta QuicSentPacketManager::GetCryptoRetransmissionDelay()
const QuicTime::Delta QuicSentPacketManager::GetTailLossProbeDelay() const {
QuicTime::Delta srtt = rtt_stats_.SmoothedRtt();
- if (!unacked_packets_.HasMultiplePendingPackets()) {
+ if (!unacked_packets_.HasMultipleInFlightPackets()) {
return QuicTime::Delta::Max(
srtt.Multiply(1.5).Add(DelayedAckTime()), srtt.Multiply(2));
}
diff --git a/net/quic/quic_sent_packet_manager.h b/net/quic/quic_sent_packet_manager.h
index 0c6c407..d65e361 100644
--- a/net/quic/quic_sent_packet_manager.h
+++ b/net/quic/quic_sent_packet_manager.h
@@ -227,11 +227,11 @@ class NET_EXPORT_PRIVATE QuicSentPacketManager {
void MarkPacketRevived(QuicPacketSequenceNumber sequence_number,
QuicTime::Delta delta_largest_observed);
- // Marks |sequence_number| as being fully handled, either due to receipt
- // by the peer, or having been discarded as indecipherable. Returns an
- // iterator to the next remaining unacked packet.
+ // Removes the retransmittability and pending properties from the packet at
+ // |it| due to receipt by the peer. Returns an iterator to the next remaining
+ // unacked packet.
QuicUnackedPacketMap::const_iterator MarkPacketHandled(
- QuicPacketSequenceNumber sequence_number,
+ QuicUnackedPacketMap::const_iterator it,
QuicTime::Delta delta_largest_observed);
// Request that |sequence_number| be retransmitted after the other pending
diff --git a/net/quic/quic_sent_packet_manager_test.cc b/net/quic/quic_sent_packet_manager_test.cc
index 838da40..b3c1fdc 100644
--- a/net/quic/quic_sent_packet_manager_test.cc
+++ b/net/quic/quic_sent_packet_manager_test.cc
@@ -321,8 +321,9 @@ TEST_F(QuicSentPacketManagerTest, RetransmitThenAckPrevious) {
received_info.largest_observed = 1;
manager_.OnIncomingAck(received_info, clock_.ApproximateNow());
- // No packets should be unacked.
- VerifyUnackedPackets(NULL, 0);
+ // 2 should be unacked, since it may provide an RTT measurement.
+ QuicPacketSequenceNumber unacked[] = { 2 };
+ VerifyUnackedPackets(unacked, arraysize(unacked));
EXPECT_FALSE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_));
VerifyRetransmittablePackets(NULL, 0);
@@ -415,8 +416,9 @@ TEST_F(QuicSentPacketManagerTest, RetransmitTwiceThenAckPreviousBeforeSend) {
ExpectUpdatedRtt(1);
manager_.OnIncomingAck(received_info, clock_.ApproximateNow());
- // Since 2 was marked for retransmit, when 1 is acked, 2 is discarded.
- VerifyUnackedPackets(NULL, 0);
+ // Since 2 was marked for retransmit, when 1 is acked, 2 is kept for RTT.
+ QuicPacketSequenceNumber unacked[] = { 2 };
+ VerifyUnackedPackets(unacked, arraysize(unacked));
EXPECT_FALSE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_));
VerifyRetransmittablePackets(NULL, 0);
@@ -917,8 +919,8 @@ TEST_F(QuicSentPacketManagerTest, CryptoHandshakeSpuriousRetransmission) {
manager_.OnRetransmissionTimeout();
RetransmitNextPacket(3);
- // Now ack the first crypto packet, and ensure the second gets abandoned and
- // removed from unacked_packets.
+ // Now ack the second crypto packet, and ensure the first gets removed, but
+ // the third does not.
ExpectUpdatedRtt(2);
ReceivedPacketInfo received_info;
received_info.largest_observed = 2;
@@ -926,7 +928,8 @@ TEST_F(QuicSentPacketManagerTest, CryptoHandshakeSpuriousRetransmission) {
manager_.OnIncomingAck(received_info, clock_.ApproximateNow());
EXPECT_FALSE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
- VerifyUnackedPackets(NULL, 0);
+ QuicPacketSequenceNumber unacked[] = { 3 };
+ VerifyUnackedPackets(unacked, arraysize(unacked));
}
TEST_F(QuicSentPacketManagerTest, CryptoHandshakeTimeoutUnsentDataPacket) {
diff --git a/net/quic/quic_session_test.cc b/net/quic/quic_session_test.cc
index 34025de..92c3cab 100644
--- a/net/quic/quic_session_test.cc
+++ b/net/quic/quic_session_test.cc
@@ -24,13 +24,15 @@
#include "net/spdy/spdy_framer.h"
#include "net/test/gtest_util.h"
#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gmock_mutant.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::hash_map;
using std::set;
using std::vector;
+using testing::CreateFunctor;
using testing::InSequence;
-using testing::InvokeWithoutArgs;
+using testing::Invoke;
using testing::Return;
using testing::StrictMock;
using testing::_;
@@ -162,8 +164,8 @@ class TestSession : public QuicSession {
writev_consumes_all_data_ = val;
}
- QuicConsumedData SendStreamData() {
- return WritevData(5, IOVector(), 0, true, NULL);
+ QuicConsumedData SendStreamData(QuicStreamId id) {
+ return WritevData(id, IOVector(), 0, true, NULL);
}
private:
@@ -354,9 +356,9 @@ TEST_P(QuicSessionTest, OnCanWrite) {
InSequence s;
StreamBlocker stream2_blocker(&session_, stream2->id());
- EXPECT_CALL(*stream2, OnCanWrite()).WillOnce(
- // Reregister, to test the loop limit.
- InvokeWithoutArgs(&stream2_blocker, &StreamBlocker::MarkWriteBlocked));
+ // Reregister, to test the loop limit.
+ EXPECT_CALL(*stream2, OnCanWrite())
+ .WillOnce(Invoke(&stream2_blocker, &StreamBlocker::MarkWriteBlocked));
EXPECT_CALL(*stream6, OnCanWrite());
EXPECT_CALL(*stream4, OnCanWrite());
session_.OnCanWrite();
@@ -376,23 +378,28 @@ TEST_P(QuicSessionTest, OnCanWriteBundlesStreams) {
session_.MarkWriteBlocked(stream6->id(), kSomeMiddlePriority);
session_.MarkWriteBlocked(stream4->id(), kSomeMiddlePriority);
-
EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _, _)).WillRepeatedly(
Return(QuicTime::Delta::Zero()));
- EXPECT_CALL(*send_algorithm, GetCongestionWindow()).WillOnce(
- Return(kMaxPacketSize * 10));
- EXPECT_CALL(*stream2, OnCanWrite()).WillOnce(IgnoreResult(
- InvokeWithoutArgs(&session_, &TestSession::SendStreamData)));
- EXPECT_CALL(*stream6, OnCanWrite()).WillOnce(IgnoreResult(
- InvokeWithoutArgs(&session_, &TestSession::SendStreamData)));
- EXPECT_CALL(*stream4, OnCanWrite()).WillOnce(IgnoreResult(
- InvokeWithoutArgs(&session_, &TestSession::SendStreamData)));
+ EXPECT_CALL(*send_algorithm, GetCongestionWindow())
+ .WillOnce(Return(kMaxPacketSize * 10));
+ EXPECT_CALL(*stream2, OnCanWrite())
+ .WillOnce(IgnoreResult(Invoke(CreateFunctor(
+ &session_, &TestSession::SendStreamData, stream2->id()))));
+ EXPECT_CALL(*stream4, OnCanWrite())
+ .WillOnce(IgnoreResult(Invoke(CreateFunctor(
+ &session_, &TestSession::SendStreamData, stream4->id()))));
+ EXPECT_CALL(*stream6, OnCanWrite())
+ .WillOnce(IgnoreResult(Invoke(CreateFunctor(
+ &session_, &TestSession::SendStreamData, stream6->id()))));
+
+ // Expect that we only send one packet, the writes from different streams
+ // should be bundled together.
MockPacketWriter* writer =
static_cast<MockPacketWriter*>(
QuicConnectionPeer::GetWriter(session_.connection()));
EXPECT_CALL(*writer, WritePacket(_, _, _, _)).WillOnce(
Return(WriteResult(WRITE_STATUS_OK, 0)));
- EXPECT_CALL(*send_algorithm, OnPacketSent(_, _, _, _, _));
+ EXPECT_CALL(*send_algorithm, OnPacketSent(_, _, _, _, _)).Times(1);
session_.OnCanWrite();
EXPECT_FALSE(session_.WillingAndAbleToWrite());
}
@@ -475,14 +482,12 @@ TEST_P(QuicSessionTest, BufferedHandshake) {
EXPECT_CALL(*crypto_stream, OnCanWrite());
// Re-register all other streams, to show they weren't able to proceed.
- EXPECT_CALL(*stream2, OnCanWrite()).WillOnce(
- InvokeWithoutArgs(&stream2_blocker, &StreamBlocker::MarkWriteBlocked));
-
- EXPECT_CALL(*stream3, OnCanWrite()).WillOnce(
- InvokeWithoutArgs(&stream3_blocker, &StreamBlocker::MarkWriteBlocked));
-
- EXPECT_CALL(*stream4, OnCanWrite()).WillOnce(
- InvokeWithoutArgs(&stream4_blocker, &StreamBlocker::MarkWriteBlocked));
+ EXPECT_CALL(*stream2, OnCanWrite())
+ .WillOnce(Invoke(&stream2_blocker, &StreamBlocker::MarkWriteBlocked));
+ EXPECT_CALL(*stream3, OnCanWrite())
+ .WillOnce(Invoke(&stream3_blocker, &StreamBlocker::MarkWriteBlocked));
+ EXPECT_CALL(*stream4, OnCanWrite())
+ .WillOnce(Invoke(&stream4_blocker, &StreamBlocker::MarkWriteBlocked));
session_.OnCanWrite();
EXPECT_TRUE(session_.WillingAndAbleToWrite());
diff --git a/net/quic/quic_unacked_packet_map.cc b/net/quic/quic_unacked_packet_map.cc
index 053b445b..b230485 100644
--- a/net/quic/quic_unacked_packet_map.cc
+++ b/net/quic/quic_unacked_packet_map.cc
@@ -15,6 +15,7 @@ namespace net {
QuicUnackedPacketMap::QuicUnackedPacketMap()
: largest_sent_packet_(0),
+ largest_observed_(0),
bytes_in_flight_(0),
pending_crypto_packet_count_(0) {
}
@@ -83,10 +84,10 @@ void QuicUnackedPacketMap::ClearPreviousRetransmissions(size_t num_to_clear) {
UnackedPacketMap::iterator it = unacked_packets_.begin();
while (it != unacked_packets_.end() && num_to_clear > 0) {
QuicPacketSequenceNumber sequence_number = it->first;
- // If this is a pending packet, or has retransmittable data, then there is
+ // If this packet is in flight, or has retransmittable data, then there is
// no point in clearing out any further packets, because they would not
// affect the high water mark.
- if (it->second.pending || it->second.retransmittable_frames != NULL) {
+ if (it->second.in_flight || it->second.retransmittable_frames != NULL) {
break;
}
@@ -123,16 +124,15 @@ void QuicUnackedPacketMap::NackPacket(QuicPacketSequenceNumber sequence_number,
}
void QuicUnackedPacketMap::RemoveRetransmittability(
- QuicPacketSequenceNumber sequence_number,
- QuicPacketSequenceNumber largest_observed) {
+ QuicPacketSequenceNumber sequence_number) {
UnackedPacketMap::iterator it = unacked_packets_.find(sequence_number);
if (it == unacked_packets_.end()) {
- LOG(DFATAL) << "packet is not unacked: " << sequence_number;
+ DVLOG(1) << "packet is not in unacked_packets: " << sequence_number;
return;
}
SequenceNumberSet* all_transmissions = it->second.all_transmissions;
// TODO(ianswett): Consider optimizing this for lone packets.
- // TODO(ianswett): Consider adding a check to ensure there are retranmittable
+ // TODO(ianswett): Consider adding a check to ensure there are retransmittable
// frames associated with this packet.
for (SequenceNumberSet::reverse_iterator it = all_transmissions->rbegin();
it != all_transmissions->rend(); ++it) {
@@ -143,7 +143,7 @@ void QuicUnackedPacketMap::RemoveRetransmittability(
continue;
}
MaybeRemoveRetransmittableFrames(transmission_info);
- if (sequence_number <= largest_observed && !transmission_info->pending) {
+ if (*it <= largest_observed_ && !transmission_info->in_flight) {
unacked_packets_.erase(*it);
} else {
transmission_info->all_transmissions = new SequenceNumberSet();
@@ -166,27 +166,29 @@ void QuicUnackedPacketMap::MaybeRemoveRetransmittableFrames(
}
}
-void QuicUnackedPacketMap::RemoveRttOnlyPacket(
- QuicPacketSequenceNumber sequence_number) {
- UnackedPacketMap::iterator it = unacked_packets_.find(sequence_number);
- if (it == unacked_packets_.end()) {
- LOG(DFATAL) << "packet is not unacked: " << sequence_number;
- return;
+void QuicUnackedPacketMap::IncreaseLargestObserved(
+ QuicPacketSequenceNumber largest_observed) {
+ DCHECK_LT(largest_observed_, largest_observed);
+ largest_observed_ = largest_observed;
+ UnackedPacketMap::iterator it = unacked_packets_.begin();
+ while (it != unacked_packets_.end() && it->first <= largest_observed_) {
+ if (!IsPacketUseless(it)) {
+ ++it;
+ continue;
+ }
+ delete it->second.all_transmissions;
+ QuicPacketSequenceNumber sequence_number = it->first;
+ ++it;
+ unacked_packets_.erase(sequence_number);
}
- TransmissionInfo* transmission_info = &it->second;
- DCHECK(!transmission_info->pending);
- DCHECK(transmission_info->retransmittable_frames == NULL);
- DCHECK_EQ(1u, transmission_info->all_transmissions->size());
- delete transmission_info->all_transmissions;
- unacked_packets_.erase(it);
}
-// static
-bool QuicUnackedPacketMap::IsForRttOnly(
- const TransmissionInfo& transmission_info) {
- return !transmission_info.pending &&
- transmission_info.retransmittable_frames == NULL &&
- transmission_info.all_transmissions->size() == 1;
+bool QuicUnackedPacketMap::IsPacketUseless(
+ UnackedPacketMap::const_iterator it) const {
+ return it->first <= largest_observed_ &&
+ !it->second.in_flight &&
+ it->second.retransmittable_frames == NULL &&
+ it->second.all_transmissions->size() == 1;
}
bool QuicUnackedPacketMap::IsUnacked(
@@ -194,18 +196,22 @@ bool QuicUnackedPacketMap::IsUnacked(
return ContainsKey(unacked_packets_, sequence_number);
}
-void QuicUnackedPacketMap::SetNotPending(
+void QuicUnackedPacketMap::RemoveFromInFlight(
QuicPacketSequenceNumber sequence_number) {
UnackedPacketMap::iterator it = unacked_packets_.find(sequence_number);
if (it == unacked_packets_.end()) {
- LOG(DFATAL) << "SetNotPending called for packet that is not unacked: "
+ LOG(DFATAL) << "RemoveFromFlight called for packet that is not unacked: "
<< sequence_number;
return;
}
- if (it->second.pending) {
+ if (it->second.in_flight) {
LOG_IF(DFATAL, bytes_in_flight_ < it->second.bytes_sent);
bytes_in_flight_ -= it->second.bytes_sent;
- it->second.pending = false;
+ it->second.in_flight = false;
+ }
+ if (IsPacketUseless(it)) {
+ delete it->second.all_transmissions;
+ unacked_packets_.erase(it);
}
}
@@ -213,7 +219,7 @@ bool QuicUnackedPacketMap::HasUnackedPackets() const {
return !unacked_packets_.empty();
}
-bool QuicUnackedPacketMap::HasPendingPackets() const {
+bool QuicUnackedPacketMap::HasInFlightPackets() const {
return bytes_in_flight_ > 0;
}
@@ -225,25 +231,24 @@ const TransmissionInfo& QuicUnackedPacketMap::GetTransmissionInfo(
QuicTime QuicUnackedPacketMap::GetLastPacketSentTime() const {
UnackedPacketMap::const_reverse_iterator it = unacked_packets_.rbegin();
while (it != unacked_packets_.rend()) {
- if (it->second.pending) {
+ if (it->second.in_flight) {
LOG_IF(DFATAL, it->second.sent_time == QuicTime::Zero())
- << "Sent time can never be zero for a pending packet.";
+ << "Sent time can never be zero for a packet in flight.";
return it->second.sent_time;
}
++it;
}
- LOG(DFATAL) << "Unable to find sent time. "
- << "This method is only intended when there are pending packets.";
+ LOG(DFATAL) << "GetLastPacketSentTime requires in flight packets.";
return QuicTime::Zero();
}
-QuicTime QuicUnackedPacketMap::GetFirstPendingPacketSentTime() const {
+QuicTime QuicUnackedPacketMap::GetFirstInFlightPacketSentTime() const {
UnackedPacketMap::const_iterator it = unacked_packets_.begin();
- while (it != unacked_packets_.end() && !it->second.pending) {
+ while (it != unacked_packets_.end() && !it->second.in_flight) {
++it;
}
if (it == unacked_packets_.end()) {
- LOG(DFATAL) << "No pending packets";
+ LOG(DFATAL) << "GetFirstInFlightPacketSentTime requires in flight packets.";
return QuicTime::Zero();
}
return it->second.sent_time;
@@ -253,14 +258,14 @@ size_t QuicUnackedPacketMap::GetNumUnackedPackets() const {
return unacked_packets_.size();
}
-bool QuicUnackedPacketMap::HasMultiplePendingPackets() const {
- size_t num_pending = 0;
+bool QuicUnackedPacketMap::HasMultipleInFlightPackets() const {
+ size_t num_in_flight = 0;
for (UnackedPacketMap::const_reverse_iterator it = unacked_packets_.rbegin();
it != unacked_packets_.rend(); ++it) {
- if (it->second.pending) {
- ++num_pending;
+ if (it->second.in_flight) {
+ ++num_in_flight;
}
- if (num_pending > 1) {
+ if (num_in_flight > 1) {
return true;
}
}
@@ -274,7 +279,7 @@ bool QuicUnackedPacketMap::HasPendingCryptoPackets() const {
bool QuicUnackedPacketMap::HasUnackedRetransmittableFrames() const {
for (UnackedPacketMap::const_reverse_iterator it =
unacked_packets_.rbegin(); it != unacked_packets_.rend(); ++it) {
- if (it->second.pending && it->second.retransmittable_frames) {
+ if (it->second.in_flight && it->second.retransmittable_frames) {
return true;
}
}
@@ -294,7 +299,7 @@ QuicUnackedPacketMap::GetLeastUnackedSentPacket() const {
void QuicUnackedPacketMap::SetSent(QuicPacketSequenceNumber sequence_number,
QuicTime sent_time,
QuicByteCount bytes_sent,
- bool set_pending) {
+ bool set_in_flight) {
DCHECK_LT(0u, sequence_number);
UnackedPacketMap::iterator it = unacked_packets_.find(sequence_number);
if (it == unacked_packets_.end()) {
@@ -302,14 +307,14 @@ void QuicUnackedPacketMap::SetSent(QuicPacketSequenceNumber sequence_number,
<< sequence_number;
return;
}
- DCHECK(!it->second.pending);
+ DCHECK(!it->second.in_flight);
largest_sent_packet_ = max(sequence_number, largest_sent_packet_);
it->second.sent_time = sent_time;
- if (set_pending) {
+ if (set_in_flight) {
bytes_in_flight_ += bytes_sent;
it->second.bytes_sent = bytes_sent;
- it->second.pending = true;
+ it->second.in_flight = true;
}
}
diff --git a/net/quic/quic_unacked_packet_map.h b/net/quic/quic_unacked_packet_map.h
index 610639c..0263422 100644
--- a/net/quic/quic_unacked_packet_map.h
+++ b/net/quic/quic_unacked_packet_map.h
@@ -10,15 +10,16 @@
namespace net {
-// Class which tracks unacked packets, including those packets which are
-// currently pending, and the relationship between packets which
-// contain the same data (via retransmissions)
+// Class which tracks unacked packets for three purposes:
+// 1) Track retransmittable data, including multiple transmissions of frames.
+// 2) Track packets and bytes in flight for congestion control.
+// 3) Track sent time of packets to provide RTT measurements from acks.
class NET_EXPORT_PRIVATE QuicUnackedPacketMap {
public:
QuicUnackedPacketMap();
~QuicUnackedPacketMap();
- // Adds |serialized_packet| to the map. Does not mark it pending.
+ // Adds |serialized_packet| to the map. Does not mark it in flight.
void AddPacket(const SerializedPacket& serialized_packet);
// Called when a packet is retransmitted with a new sequence number.
@@ -35,8 +36,8 @@ class NET_EXPORT_PRIVATE QuicUnackedPacketMap {
void NackPacket(QuicPacketSequenceNumber sequence_number,
size_t min_nacks);
- // Marks |sequence_number| as no longer pending.
- void SetNotPending(QuicPacketSequenceNumber sequence_number);
+ // Marks |sequence_number| as no longer in flight.
+ void RemoveFromInFlight(QuicPacketSequenceNumber sequence_number);
// Returns true if the unacked packet |sequence_number| has retransmittable
// frames. This will return false if the packet has been acked, if a
@@ -57,7 +58,7 @@ class NET_EXPORT_PRIVATE QuicUnackedPacketMap {
return largest_sent_packet_;
}
- // Returns the sum of the bytes in all pending packets.
+ // Returns the sum of bytes from all packets in flight.
QuicByteCount bytes_in_flight() const {
return bytes_in_flight_;
}
@@ -67,13 +68,13 @@ class NET_EXPORT_PRIVATE QuicUnackedPacketMap {
QuicPacketSequenceNumber GetLeastUnackedSentPacket() const;
// Sets a packet as sent with the sent time |sent_time|. Marks the packet
- // as pending and tracks the |bytes_sent| if |set_pending| is true.
- // Packets marked as pending are expected to be marked as missing when they
+ // as in flight if |set_in_flight| is true.
+ // Packets marked as in flight are expected to be marked as missing when they
// don't arrive, indicating the need for retransmission.
void SetSent(QuicPacketSequenceNumber sequence_number,
QuicTime sent_time,
QuicByteCount bytes_sent,
- bool set_pending);
+ bool set_in_flight);
// Clears up to |num_to_clear| previous transmissions in order to make room
// in the ack frame for new acks.
@@ -87,8 +88,8 @@ class NET_EXPORT_PRIVATE QuicUnackedPacketMap {
const_iterator begin() const { return unacked_packets_.begin(); }
const_iterator end() const { return unacked_packets_.end(); }
- // Returns true if there are unacked packets that are pending.
- bool HasPendingPackets() const;
+ // Returns true if there are unacked packets that are in flight.
+ bool HasInFlightPackets() const;
// Returns the TransmissionInfo associated with |sequence_number|, which
// must be unacked.
@@ -98,42 +99,35 @@ class NET_EXPORT_PRIVATE QuicUnackedPacketMap {
// Returns the time that the last unacked packet was sent.
QuicTime GetLastPacketSentTime() const;
- // Returns the time that the first pending packet was sent.
- QuicTime GetFirstPendingPacketSentTime() const;
+ // Returns the time that the first in flight packet was sent.
+ QuicTime GetFirstInFlightPacketSentTime() const;
// Returns the number of unacked packets.
size_t GetNumUnackedPackets() const;
- // Returns true if there are multiple packet pending.
- bool HasMultiplePendingPackets() const;
+ // Returns true if there are multiple packets in flight.
+ bool HasMultipleInFlightPackets() const;
// Returns true if there are any pending crypto packets.
bool HasPendingCryptoPackets() const;
// Removes any retransmittable frames from this transmission or an associated
- // transmission. It removes any nnon-pending transmissions less than or
- // equal to |largest_observed|, and disconnects any other packets from other
- // transmissions.
- // TODO(ianswett): Remove largest_observed_ once the map tracks whether a
- // transmission is useful for RTT purposes internally.
- void RemoveRetransmittability(QuicPacketSequenceNumber sequence_number,
- QuicPacketSequenceNumber largest_observed_);
-
- // Removes an entry from the unacked packet map which is not pending, has
- // no retransmittable frames, and no associated transmissions.
- // TODO(ianswett): Remove or make this method private once the map tracks
- // the three reasons for tracking a packet correctly.
- void RemoveRttOnlyPacket(QuicPacketSequenceNumber sequence_number);
-
- // Returns true if the packet's only purpose is to measure RTT. It must not
- // be pending, have retransmittable frames, or be linked to transmissions
- // with retransmittable frames.
- static bool IsForRttOnly(const TransmissionInfo& transmission_info);
+ // transmission. It removes now useless transmissions, and disconnects any
+ // other packets from other transmissions.
+ void RemoveRetransmittability(QuicPacketSequenceNumber sequence_number);
+
+ // Increases the largest observed. Any packets less or equal to
+ // |largest_acked_packet| are discarded if they are only for the RTT purposes.
+ void IncreaseLargestObserved(QuicPacketSequenceNumber largest_observed);
private:
void MaybeRemoveRetransmittableFrames(TransmissionInfo* transmission_info);
+ // Returns true if the packet no longer has a purpose in the map.
+ bool IsPacketUseless(UnackedPacketMap::const_iterator it) const;
+
QuicPacketSequenceNumber largest_sent_packet_;
+ QuicPacketSequenceNumber largest_observed_;
// Newly serialized retransmittable and fec packets are added to this map,
// which contains owning pointers to any contained frames. If a packet is
@@ -146,7 +140,7 @@ class NET_EXPORT_PRIVATE QuicUnackedPacketMap {
UnackedPacketMap unacked_packets_;
size_t bytes_in_flight_;
- // Number of outstanding crypto handshake packets.
+ // Number of retransmittable crypto handshake packets.
size_t pending_crypto_packet_count_;
DISALLOW_COPY_AND_ASSIGN(QuicUnackedPacketMap);
diff --git a/net/quic/quic_unacked_packet_map_test.cc b/net/quic/quic_unacked_packet_map_test.cc
new file mode 100644
index 0000000..0ff0cf0
--- /dev/null
+++ b/net/quic/quic_unacked_packet_map_test.cc
@@ -0,0 +1,166 @@
+// Copyright 2014 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 "net/quic/quic_unacked_packet_map.h"
+
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace test {
+namespace {
+
+// Default packet length.
+const uint32 kDefaultAckLength = 50;
+const uint32 kDefaultLength = 1000;
+
+class QuicUnackedPacketMapTest : public ::testing::Test {
+ protected:
+ QuicUnackedPacketMapTest()
+ : now_(QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(1000))) {
+ }
+
+ SerializedPacket CreateRetransmittablePacket(
+ QuicPacketSequenceNumber sequence_number) {
+ return SerializedPacket(sequence_number, PACKET_1BYTE_SEQUENCE_NUMBER, NULL,
+ 0, new RetransmittableFrames());
+ }
+
+ SerializedPacket CreateNonRetransmittablePacket(
+ QuicPacketSequenceNumber sequence_number) {
+ return SerializedPacket(
+ sequence_number, PACKET_1BYTE_SEQUENCE_NUMBER, NULL, 0, NULL);
+ }
+
+ void VerifyPendingPackets(QuicPacketSequenceNumber* packets,
+ size_t num_packets) {
+ if (num_packets == 0) {
+ EXPECT_FALSE(unacked_packets_.HasInFlightPackets());
+ EXPECT_FALSE(unacked_packets_.HasMultipleInFlightPackets());
+ return;
+ }
+ if (num_packets == 1) {
+ EXPECT_TRUE(unacked_packets_.HasInFlightPackets());
+ EXPECT_FALSE(unacked_packets_.HasMultipleInFlightPackets());
+ }
+ for (size_t i = 0; i < num_packets; ++i) {
+ ASSERT_TRUE(unacked_packets_.IsUnacked(packets[i]));
+ EXPECT_TRUE(unacked_packets_.GetTransmissionInfo(packets[i]).in_flight);
+ }
+ }
+
+ void VerifyUnackedPackets(QuicPacketSequenceNumber* packets,
+ size_t num_packets) {
+ if (num_packets == 0) {
+ EXPECT_FALSE(unacked_packets_.HasUnackedPackets());
+ EXPECT_FALSE(unacked_packets_.HasUnackedRetransmittableFrames());
+ return;
+ }
+ EXPECT_TRUE(unacked_packets_.HasUnackedPackets());
+ for (size_t i = 0; i < num_packets; ++i) {
+ EXPECT_TRUE(unacked_packets_.IsUnacked(packets[i])) << packets[i];
+ }
+ }
+
+ void VerifyRetransmittablePackets(QuicPacketSequenceNumber* packets,
+ size_t num_packets) {
+ size_t num_retransmittable_packets = 0;
+ for (QuicUnackedPacketMap::const_iterator it = unacked_packets_.begin();
+ it != unacked_packets_.end(); ++it) {
+ if (it->second.retransmittable_frames != NULL) {
+ ++num_retransmittable_packets;
+ }
+ }
+ EXPECT_EQ(num_packets, num_retransmittable_packets);
+ for (size_t i = 0; i < num_packets; ++i) {
+ EXPECT_TRUE(unacked_packets_.HasRetransmittableFrames(packets[i]))
+ << " packets[" << i << "]:" << packets[i];
+ }
+ }
+
+ QuicUnackedPacketMap unacked_packets_;
+ QuicTime now_;
+};
+
+TEST_F(QuicUnackedPacketMapTest, RttOnly) {
+ // Acks are only tracked for RTT measurement purposes.
+ unacked_packets_.AddPacket(CreateNonRetransmittablePacket(1));
+ unacked_packets_.SetSent(1, now_, kDefaultAckLength, false);
+
+ QuicPacketSequenceNumber unacked[] = { 1 };
+ VerifyUnackedPackets(unacked, arraysize(unacked));
+ VerifyPendingPackets(NULL, 0);
+ VerifyRetransmittablePackets(NULL, 0);
+
+ unacked_packets_.IncreaseLargestObserved(1);
+ VerifyUnackedPackets(NULL, 0);
+ VerifyPendingPackets(NULL, 0);
+ VerifyRetransmittablePackets(NULL, 0);
+}
+
+TEST_F(QuicUnackedPacketMapTest, RetransmittableInflightAndRtt) {
+ // Simulate a retransmittable packet being sent and acked.
+ unacked_packets_.AddPacket(CreateRetransmittablePacket(1));
+ unacked_packets_.SetSent(1, now_, kDefaultLength, true);
+
+ QuicPacketSequenceNumber unacked[] = { 1 };
+ VerifyUnackedPackets(unacked, arraysize(unacked));
+ VerifyPendingPackets(unacked, arraysize(unacked));
+ VerifyRetransmittablePackets(unacked, arraysize(unacked));
+
+ unacked_packets_.RemoveRetransmittability(1);
+ VerifyUnackedPackets(unacked, arraysize(unacked));
+ VerifyPendingPackets(unacked, arraysize(unacked));
+ VerifyRetransmittablePackets(NULL, 0);
+
+ unacked_packets_.IncreaseLargestObserved(1);
+ VerifyUnackedPackets(unacked, arraysize(unacked));
+ VerifyPendingPackets(unacked, arraysize(unacked));
+ VerifyRetransmittablePackets(NULL, 0);
+
+ unacked_packets_.RemoveFromInFlight(1);
+ VerifyUnackedPackets(NULL, 0);
+ VerifyPendingPackets(NULL, 0);
+ VerifyRetransmittablePackets(NULL, 0);
+}
+
+TEST_F(QuicUnackedPacketMapTest, RetransmittedPacket) {
+ // Simulate a retransmittable packet being sent, retransmitted, and the first
+ // transmission being acked.
+ unacked_packets_.AddPacket(CreateRetransmittablePacket(1));
+ unacked_packets_.SetSent(1, now_, kDefaultLength, true);
+ unacked_packets_.OnRetransmittedPacket(1, 2);
+ unacked_packets_.SetSent(2, now_, kDefaultLength, true);
+
+ QuicPacketSequenceNumber unacked[] = { 1, 2 };
+ VerifyUnackedPackets(unacked, arraysize(unacked));
+ VerifyPendingPackets(unacked, arraysize(unacked));
+ QuicPacketSequenceNumber retransmittable[] = { 2 };
+ VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable));
+
+ unacked_packets_.RemoveRetransmittability(1);
+ VerifyUnackedPackets(unacked, arraysize(unacked));
+ VerifyPendingPackets(unacked, arraysize(unacked));
+ VerifyRetransmittablePackets(NULL, 0);
+
+ unacked_packets_.IncreaseLargestObserved(2);
+ VerifyUnackedPackets(unacked, arraysize(unacked));
+ VerifyPendingPackets(unacked, arraysize(unacked));
+ VerifyRetransmittablePackets(NULL, 0);
+
+ unacked_packets_.RemoveFromInFlight(2);
+ QuicPacketSequenceNumber unacked2[] = { 1 };
+ VerifyUnackedPackets(unacked, arraysize(unacked2));
+ VerifyPendingPackets(unacked, arraysize(unacked2));
+ VerifyRetransmittablePackets(NULL, 0);
+
+ unacked_packets_.RemoveFromInFlight(1);
+ VerifyUnackedPackets(NULL, 0);
+ VerifyPendingPackets(NULL, 0);
+ VerifyRetransmittablePackets(NULL, 0);
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/net/quic/reliable_quic_stream_test.cc b/net/quic/reliable_quic_stream_test.cc
index 935554f..9e212ce 100644
--- a/net/quic/reliable_quic_stream_test.cc
+++ b/net/quic/reliable_quic_stream_test.cc
@@ -121,7 +121,7 @@ class ReliableQuicStreamTest : public ::testing::TestWithParam<bool> {
stream_.reset(new TestStream(kHeadersStreamId, session_.get(),
stream_should_process_data));
write_blocked_list_ =
- QuicSessionPeer::GetWriteblockedStreams(session_.get());
+ QuicSessionPeer::GetWriteBlockedStreams(session_.get());
}
bool fin_sent() { return ReliableQuicStreamPeer::FinSent(stream_.get()); }
@@ -153,7 +153,8 @@ TEST_F(ReliableQuicStreamTest, WriteAllData) {
connection_->options()->max_packet_length =
1 + QuicPacketCreator::StreamFramePacketOverhead(
connection_->version(), PACKET_8BYTE_CONNECTION_ID,
- !kIncludeVersion, PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP);
+ !kIncludeVersion, PACKET_6BYTE_SEQUENCE_NUMBER, 0u,
+ NOT_IN_FEC_GROUP);
EXPECT_CALL(*session_, WritevData(kHeadersStreamId, _, _, _, _))
.WillOnce(Return(QuicConsumedData(kDataLen, true)));
stream_->WriteOrBufferData(kData1, false, NULL);
@@ -211,7 +212,7 @@ TEST_F(ReliableQuicStreamTest, WriteOrBufferData) {
connection_->options()->max_packet_length =
1 + QuicPacketCreator::StreamFramePacketOverhead(
connection_->version(), PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion,
- PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP);
+ PACKET_6BYTE_SEQUENCE_NUMBER, 0u, NOT_IN_FEC_GROUP);
EXPECT_CALL(*session_, WritevData(_, _, _, _, _)).WillOnce(
Return(QuicConsumedData(kDataLen - 1, false)));
stream_->WriteOrBufferData(kData1, false, NULL);
@@ -325,16 +326,16 @@ TEST_F(ReliableQuicStreamTest, StreamFlowControlMultipleWindowUpdates) {
// want to make sure we latch the largest offset we see.
// Initially should be default.
- EXPECT_EQ(initial_flow_control_window_bytes_,
- QuicFlowControllerPeer::SendWindowOffset(
- stream_.get()->flow_controller()));
+ EXPECT_EQ(
+ initial_flow_control_window_bytes_,
+ QuicFlowControllerPeer::SendWindowOffset(stream_->flow_controller()));
// Check a single WINDOW_UPDATE results in correct offset.
QuicWindowUpdateFrame window_update_1(stream_->id(), 1234);
stream_->OnWindowUpdateFrame(window_update_1);
- EXPECT_EQ(window_update_1.byte_offset,
- QuicFlowControllerPeer::SendWindowOffset(
- stream_.get()->flow_controller()));
+ EXPECT_EQ(
+ window_update_1.byte_offset,
+ QuicFlowControllerPeer::SendWindowOffset(stream_->flow_controller()));
// Now send a few more WINDOW_UPDATES and make sure that only the largest is
// remembered.
@@ -344,9 +345,9 @@ TEST_F(ReliableQuicStreamTest, StreamFlowControlMultipleWindowUpdates) {
stream_->OnWindowUpdateFrame(window_update_2);
stream_->OnWindowUpdateFrame(window_update_3);
stream_->OnWindowUpdateFrame(window_update_4);
- EXPECT_EQ(window_update_3.byte_offset,
- QuicFlowControllerPeer::SendWindowOffset(
- stream_.get()->flow_controller()));
+ EXPECT_EQ(
+ window_update_3.byte_offset,
+ QuicFlowControllerPeer::SendWindowOffset(stream_->flow_controller()));
}
TEST_F(ReliableQuicStreamTest, StreamFlowControlShouldNotBlockInLessThanQ017) {
diff --git a/net/quic/test_tools/quic_sent_packet_manager_peer.cc b/net/quic/test_tools/quic_sent_packet_manager_peer.cc
index db1a26d..786e63c 100644
--- a/net/quic/test_tools/quic_sent_packet_manager_peer.cc
+++ b/net/quic/test_tools/quic_sent_packet_manager_peer.cc
@@ -62,7 +62,7 @@ size_t QuicSentPacketManagerPeer::GetPendingRetransmissionCount(
// static
bool QuicSentPacketManagerPeer::HasPendingPackets(
const QuicSentPacketManager* sent_packet_manager) {
- return sent_packet_manager->unacked_packets_.HasPendingPackets();
+ return sent_packet_manager->unacked_packets_.HasInFlightPackets();
}
// static
diff --git a/net/quic/test_tools/quic_session_peer.cc b/net/quic/test_tools/quic_session_peer.cc
index a46b6fe..39663fb 100644
--- a/net/quic/test_tools/quic_session_peer.cc
+++ b/net/quic/test_tools/quic_session_peer.cc
@@ -33,7 +33,7 @@ void QuicSessionPeer::SetHeadersStream(QuicSession* session,
}
// static
-QuicWriteBlockedList* QuicSessionPeer::GetWriteblockedStreams(
+QuicWriteBlockedList* QuicSessionPeer::GetWriteBlockedStreams(
QuicSession* session) {
return &session->write_blocked_streams_;
}
diff --git a/net/quic/test_tools/quic_session_peer.h b/net/quic/test_tools/quic_session_peer.h
index ef9fef7..77b376c 100644
--- a/net/quic/test_tools/quic_session_peer.h
+++ b/net/quic/test_tools/quic_session_peer.h
@@ -23,7 +23,7 @@ class QuicSessionPeer {
static QuicHeadersStream* GetHeadersStream(QuicSession* session);
static void SetHeadersStream(QuicSession* session,
QuicHeadersStream* headers_stream);
- static QuicWriteBlockedList* GetWriteblockedStreams(QuicSession* session);
+ static QuicWriteBlockedList* GetWriteBlockedStreams(QuicSession* session);
static QuicDataStream* GetIncomingDataStream(QuicSession* session,
QuicStreamId stream_id);
diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc
index f14dd73..1f7759d 100644
--- a/net/quic/test_tools/quic_test_utils.cc
+++ b/net/quic/test_tools/quic_test_utils.cc
@@ -52,6 +52,17 @@ QuicAckFrame MakeAckFrame(QuicPacketSequenceNumber largest_observed,
return ack;
}
+QuicAckFrame MakeAckFrameWithNackRanges(
+ size_t num_nack_ranges, QuicPacketSequenceNumber least_unacked) {
+ QuicAckFrame ack = MakeAckFrame(2 * num_nack_ranges + least_unacked,
+ least_unacked);
+ // Add enough missing packets to get num_nack_ranges nack ranges.
+ for (QuicPacketSequenceNumber i = 1; i < 2 * num_nack_ranges; i += 2) {
+ ack.received_info.missing_packets.insert(least_unacked + i);
+ }
+ return ack;
+}
+
MockFramerVisitor::MockFramerVisitor() {
// By default, we want to accept packets.
ON_CALL(*this, OnProtocolVersionMismatch(_))
@@ -510,7 +521,7 @@ size_t GetPacketLengthForOneStream(
NullEncrypter().GetCiphertextSize(*payload_length) +
QuicPacketCreator::StreamFramePacketOverhead(
version, PACKET_8BYTE_CONNECTION_ID, include_version,
- sequence_number_length, is_in_fec_group);
+ sequence_number_length, 0u, is_in_fec_group);
const size_t ack_length = NullEncrypter().GetCiphertextSize(
QuicFramer::GetMinAckFrameSize(
version, sequence_number_length, PACKET_1BYTE_SEQUENCE_NUMBER)) +
@@ -523,7 +534,7 @@ size_t GetPacketLengthForOneStream(
return NullEncrypter().GetCiphertextSize(*payload_length) +
QuicPacketCreator::StreamFramePacketOverhead(
version, PACKET_8BYTE_CONNECTION_ID, include_version,
- sequence_number_length, is_in_fec_group);
+ sequence_number_length, 0u, is_in_fec_group);
}
TestEntropyCalculator::TestEntropyCalculator() { }
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h
index 3bf2bf3..8bf069b 100644
--- a/net/quic/test_tools/quic_test_utils.h
+++ b/net/quic/test_tools/quic_test_utils.h
@@ -88,6 +88,11 @@ QuicVersionVector SupportedVersions(QuicVersion version);
QuicAckFrame MakeAckFrame(QuicPacketSequenceNumber largest_observed,
QuicPacketSequenceNumber least_unacked);
+// Testing convenience method to construct a QuicAckFrame with |num_nack_ranges|
+// nack ranges of width 1 packet, starting from |least_unacked|.
+QuicAckFrame MakeAckFrameWithNackRanges(size_t num_nack_ranges,
+ QuicPacketSequenceNumber least_unacked);
+
template<typename SaveType>
class ValueRestore {
public: