summaryrefslogtreecommitdiffstats
path: root/net/quic
diff options
context:
space:
mode:
authorrtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-05-22 11:13:05 +0000
committerrtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-05-22 11:13:05 +0000
commit66ae596f10dfc801b79c5d756c0e99792af1807f (patch)
tree5b224ff7568761c1217b5075ec27c9efab9c783f /net/quic
parent411f8aef7e6db2fadec7205a220f24ec8b914486 (diff)
downloadchromium_src-66ae596f10dfc801b79c5d756c0e99792af1807f.zip
chromium_src-66ae596f10dfc801b79c5d756c0e99792af1807f.tar.gz
chromium_src-66ae596f10dfc801b79c5d756c0e99792af1807f.tar.bz2
Land Recent QUIC Changes.
A number of tests define data stream IDs: this CL puts these definitions in one place in quic_test_utils.h Merge internal change: 67627075 https://codereview.chromium.org/296853003/ Replace NeuterPacket and RemovePacket with RemoveRetransmittibility, which removes the retransmittibility property from a packet and it's associated transmissions. Merge internal change: 67615222 https://codereview.chromium.org/286933010/ Cleanup changes to fix the using:: order. Merge internal change: 67541632,, 67612445 https://codereview.chromium.org/297773002/ Remove QuicSentPacketManager's DiscardUnackedPacket method now that it's not necessary. Merge internal change: 67542370 https://codereview.chromium.org/290333005/ Garbage collect QUIC entropy map as gaps are filled. Not flag protected. Merge internal change: 67521743 https://codereview.chromium.org/296053006/ Extract entropy tracking from QuicReceivedPacketManager into its own class in preparation for garbage collecting unneeded entropy history. Extract QUIC entropy tracking into a separate class, no behavior change. Merge internal change: 67273904 https://codereview.chromium.org/294143004/ Remove check for an impossible condition. StopWaiting frames with least_unacked > packet sequence number are illegal. Largest observed is guaranteed to be >= the StopWaiting packet sequence number. Remove impossible condition from an if. Merge internal change: 67268376 https://codereview.chromium.org/292983009/ R=rch@chromium.org Review URL: https://codereview.chromium.org/297513005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@272158 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/quic')
-rw-r--r--net/quic/congestion_control/tcp_loss_algorithm_test.cc2
-rw-r--r--net/quic/quic_connection.cc28
-rw-r--r--net/quic/quic_connection_test.cc60
-rw-r--r--net/quic/quic_data_stream_test.cc76
-rw-r--r--net/quic/quic_headers_stream_test.cc6
-rw-r--r--net/quic/quic_http_stream_test.cc2
-rw-r--r--net/quic/quic_network_transaction_unittest.cc47
-rw-r--r--net/quic/quic_packet_creator_test.cc21
-rw-r--r--net/quic/quic_received_packet_manager.cc189
-rw-r--r--net/quic/quic_received_packet_manager.h97
-rw-r--r--net/quic/quic_received_packet_manager_test.cc187
-rw-r--r--net/quic/quic_sent_packet_manager.cc91
-rw-r--r--net/quic/quic_sent_packet_manager.h6
-rw-r--r--net/quic/quic_sent_packet_manager_test.cc17
-rw-r--r--net/quic/quic_session_test.cc13
-rw-r--r--net/quic/quic_stream_factory_test.cc4
-rw-r--r--net/quic/quic_unacked_packet_map.cc68
-rw-r--r--net/quic/quic_unacked_packet_map.h22
-rw-r--r--net/quic/quic_write_blocked_list_test.cc3
-rw-r--r--net/quic/reliable_quic_stream_test.cc112
-rw-r--r--net/quic/test_tools/quic_received_packet_manager_peer.cc6
-rw-r--r--net/quic/test_tools/quic_received_packet_manager_peer.h2
-rw-r--r--net/quic/test_tools/quic_test_utils.h6
23 files changed, 642 insertions, 423 deletions
diff --git a/net/quic/congestion_control/tcp_loss_algorithm_test.cc b/net/quic/congestion_control/tcp_loss_algorithm_test.cc
index 657ab2b..53806b4 100644
--- a/net/quic/congestion_control/tcp_loss_algorithm_test.cc
+++ b/net/quic/congestion_control/tcp_loss_algorithm_test.cc
@@ -171,7 +171,7 @@ TEST_F(TcpLossAlgorithmTest, DontEarlyRetransmitNeuteredPacket) {
// Early retransmit when the final packet gets acked and the first is nacked.
unacked_packets_.SetNotPending(2);
unacked_packets_.NackPacket(1, 1);
- unacked_packets_.NeuterPacket(1);
+ unacked_packets_.RemoveRetransmittibility(1, 1);
VerifyLosses(2, NULL, 0);
EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
}
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc
index 523ce6e..851ccd6 100644
--- a/net/quic/quic_connection.cc
+++ b/net/quic/quic_connection.cc
@@ -1443,16 +1443,6 @@ bool QuicConnection::ShouldDiscardPacket(
return true;
}
- if (encryption_level_ == ENCRYPTION_FORWARD_SECURE &&
- level == ENCRYPTION_NONE) {
- // Drop packets that are NULL encrypted since the peer won't accept them
- // anymore.
- DVLOG(1) << ENDPOINT << "Dropping packet: " << sequence_number
- << " since the packet is NULL encrypted.";
- sent_packet_manager_.DiscardUnackedPacket(sequence_number);
- return true;
- }
-
// If the packet has been discarded before sending, don't send it.
// This occurs if a packet gets serialized, queued, then discarded.
if (!sent_packet_manager_.IsUnacked(sequence_number)) {
@@ -1461,11 +1451,23 @@ bool QuicConnection::ShouldDiscardPacket(
return true;
}
+ if (encryption_level_ == ENCRYPTION_FORWARD_SECURE &&
+ level == ENCRYPTION_NONE) {
+ // Drop packets that are NULL encrypted since the peer won't accept them
+ // anymore.
+ DVLOG(1) << ENDPOINT << "Dropping NULL encrypted packet: "
+ << sequence_number << " since the connection is forward secure.";
+ LOG_IF(DFATAL,
+ sent_packet_manager_.HasRetransmittableFrames(sequence_number))
+ << "Once forward secure, all NULL encrypted packets should be "
+ << "neutered.";
+ return true;
+ }
+
if (retransmittable == HAS_RETRANSMITTABLE_DATA &&
!sent_packet_manager_.HasRetransmittableFrames(sequence_number)) {
- DVLOG(1) << ENDPOINT << "Dropping packet: " << sequence_number
- << " since a previous transmission has been acked.";
- sent_packet_manager_.DiscardUnackedPacket(sequence_number);
+ LOG(DFATAL) << ENDPOINT << "Dropping unacked packet: " << sequence_number
+ << " This should have been removed when it was Neutered.";
return true;
}
diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc
index 48cb2db..5e2da31 100644
--- a/net/quic/quic_connection_test.cc
+++ b/net/quic/quic_connection_test.cc
@@ -59,11 +59,6 @@ const QuicPacketEntropyHash kTestEntropyHash = 76;
const int kDefaultRetransmissionTimeMs = 500;
const int kMinRetransmissionTimeMs = 200;
-// Used by TestConnection::SendStreamData3.
-const QuicStreamId kStreamId3 = 3;
-// Used by TestConnection::SendStreamData5.
-const QuicStreamId kStreamId5 = 5;
-
class TestReceiveAlgorithm : public ReceiveAlgorithmInterface {
public:
explicit TestReceiveAlgorithm(QuicCongestionFeedbackFrame* feedback)
@@ -473,11 +468,13 @@ class TestConnection : public QuicConnection {
}
QuicConsumedData SendStreamData3() {
- return SendStreamDataWithString(kStreamId3, "food", 0, !kFin, NULL);
+ return SendStreamDataWithString(kClientDataStreamId1, "food", 0, !kFin,
+ NULL);
}
QuicConsumedData SendStreamData5() {
- return SendStreamDataWithString(kStreamId5, "food2", 0, !kFin, NULL);
+ return SendStreamDataWithString(kClientDataStreamId2, "food2", 0,
+ !kFin, NULL);
}
// Ensures the connection can write stream data before writing.
@@ -1587,8 +1584,8 @@ TEST_P(QuicConnectionTest, FramePacking) {
}
EXPECT_FALSE(writer_->ack_frames().empty());
EXPECT_EQ(2u, writer_->stream_frames().size());
- EXPECT_EQ(kStreamId3, writer_->stream_frames()[0].stream_id);
- EXPECT_EQ(kStreamId5, writer_->stream_frames()[1].stream_id);
+ EXPECT_EQ(kClientDataStreamId1, writer_->stream_frames()[0].stream_id);
+ EXPECT_EQ(kClientDataStreamId2, writer_->stream_frames()[1].stream_id);
}
TEST_P(QuicConnectionTest, FramePackingNonCryptoThenCrypto) {
@@ -1640,7 +1637,7 @@ TEST_P(QuicConnectionTest, FramePackingCryptoThenNonCrypto) {
// Parse the last packet and ensure it's the stream frame from stream 3.
EXPECT_EQ(1u, writer_->frame_count());
EXPECT_EQ(1u, writer_->stream_frames().size());
- EXPECT_EQ(kStreamId3, writer_->stream_frames()[0].stream_id);
+ EXPECT_EQ(kClientDataStreamId1, writer_->stream_frames()[0].stream_id);
}
TEST_P(QuicConnectionTest, FramePackingFEC) {
@@ -1706,8 +1703,8 @@ TEST_P(QuicConnectionTest, FramePackingAckResponse) {
}
EXPECT_FALSE(writer_->ack_frames().empty());
ASSERT_EQ(2u, writer_->stream_frames().size());
- EXPECT_EQ(kStreamId3, writer_->stream_frames()[0].stream_id);
- EXPECT_EQ(kStreamId5, writer_->stream_frames()[1].stream_id);
+ EXPECT_EQ(kClientDataStreamId1, writer_->stream_frames()[0].stream_id);
+ EXPECT_EQ(kClientDataStreamId2, writer_->stream_frames()[1].stream_id);
}
TEST_P(QuicConnectionTest, FramePackingSendv) {
@@ -1794,8 +1791,8 @@ TEST_P(QuicConnectionTest, OnCanWrite) {
// two different streams.
EXPECT_EQ(2u, writer_->frame_count());
EXPECT_EQ(2u, writer_->stream_frames().size());
- EXPECT_EQ(kStreamId3, writer_->stream_frames()[0].stream_id);
- EXPECT_EQ(kStreamId5, writer_->stream_frames()[1].stream_id);
+ EXPECT_EQ(kClientDataStreamId1, writer_->stream_frames()[0].stream_id);
+ EXPECT_EQ(kClientDataStreamId2, writer_->stream_frames()[1].stream_id);
}
TEST_P(QuicConnectionTest, RetransmitOnNack) {
@@ -2323,21 +2320,24 @@ TEST_P(QuicConnectionTest,
QuicPacketSequenceNumber sequence_number;
SendStreamDataToPeer(3, "foo", 0, !kFin, &sequence_number);
+ // Simulate the retransmission alarm firing and the socket blocking.
+ BlockOnNextWrite();
+ EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true));
+ clock_.AdvanceTime(DefaultRetransmissionTime());
+ connection_.GetRetransmissionAlarm()->Fire();
+
+ // Go forward secure.
connection_.SetEncrypter(ENCRYPTION_FORWARD_SECURE,
new TaggingEncrypter(0x02));
connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+ connection_.NeuterUnencryptedPackets();
- EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true));
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
-
- QuicTime default_retransmission_time = clock_.ApproximateNow().Add(
- DefaultRetransmissionTime());
-
- EXPECT_EQ(default_retransmission_time,
+ EXPECT_EQ(QuicTime::Zero(),
connection_.GetRetransmissionAlarm()->deadline());
- // Simulate the retransmission alarm firing.
- clock_.AdvanceTime(DefaultRetransmissionTime());
- connection_.GetRetransmissionAlarm()->Fire();
+ // Unblock the socket and ensure that no packets are sent.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ writer_->SetWritable();
+ connection_.OnCanWrite();
}
TEST_P(QuicConnectionTest, RetransmitPacketsWithInitialEncryption) {
@@ -2997,7 +2997,8 @@ TEST_P(QuicConnectionTest, NoAckOnOldNacks) {
TEST_P(QuicConnectionTest, SendDelayedAckOnOutgoingPacket) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
ProcessPacket(1);
- connection_.SendStreamDataWithString(kStreamId3, "foo", 0, !kFin, NULL);
+ connection_.SendStreamDataWithString(kClientDataStreamId1, "foo", 0,
+ !kFin, NULL);
// Check that ack is bundled with outgoing data and that delayed ack
// alarm is reset.
if (version() > QUIC_VERSION_15) {
@@ -3022,8 +3023,10 @@ TEST_P(QuicConnectionTest, SendDelayedAckOnOutgoingCryptoPacket) {
TEST_P(QuicConnectionTest, BundleAckWithDataOnIncomingAck) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- connection_.SendStreamDataWithString(kStreamId3, "foo", 0, !kFin, NULL);
- connection_.SendStreamDataWithString(kStreamId3, "foo", 3, !kFin, NULL);
+ connection_.SendStreamDataWithString(kClientDataStreamId1, "foo", 0,
+ !kFin, NULL);
+ connection_.SendStreamDataWithString(kClientDataStreamId1, "foo", 3,
+ !kFin, NULL);
// Ack the second packet, which will retransmit the first packet.
QuicAckFrame ack = InitAckFrame(2, 0);
NackPacket(1, &ack);
@@ -3247,7 +3250,7 @@ TEST_P(QuicConnectionTest, EntropyCalculationForTruncatedAck) {
QuicPacketEntropyHash entropy[51];
entropy[0] = 0;
for (int i = 1; i < 51; ++i) {
- bool should_send = i % 10 != 0;
+ bool should_send = i % 10 != 1;
bool entropy_flag = (i & (i - 1)) != 0;
if (!should_send) {
entropy[i] = entropy[i - 1];
@@ -3260,7 +3263,6 @@ TEST_P(QuicConnectionTest, EntropyCalculationForTruncatedAck) {
}
ProcessDataPacket(i, 1, entropy_flag);
}
- // Till 50 since 50th packet is not sent.
for (int i = 1; i < 50; ++i) {
EXPECT_EQ(entropy[i], QuicConnectionPeer::ReceivedEntropyHash(
&connection_, i));
diff --git a/net/quic/quic_data_stream_test.cc b/net/quic/quic_data_stream_test.cc
index 164e7e4..a899853 100644
--- a/net/quic/quic_data_stream_test.cc
+++ b/net/quic/quic_data_stream_test.cc
@@ -30,9 +30,6 @@ namespace net {
namespace test {
namespace {
-// First non-reserved client stream ID.
-const QuicStreamId kStreamId = 5;
-
const bool kIsServer = true;
const bool kShouldProcessData = true;
@@ -98,10 +95,10 @@ class QuicDataStreamTest : public ::testing::TestWithParam<QuicVersion> {
connection_ = new testing::StrictMock<MockConnection>(
kIsServer, SupportedVersions(GetParam()));
session_.reset(new testing::StrictMock<MockSession>(connection_));
- stream_.reset(new TestStream(kStreamId, session_.get(),
- stream_should_process_data));
- stream2_.reset(new TestStream(kStreamId + 2, session_.get(),
+ stream_.reset(new TestStream(kClientDataStreamId1, session_.get(),
stream_should_process_data));
+ stream2_.reset(new TestStream(kClientDataStreamId2, session_.get(),
+ stream_should_process_data));
write_blocked_list_ =
QuicSessionPeer::GetWriteblockedStreams(session_.get());
}
@@ -140,7 +137,7 @@ TEST_P(QuicDataStreamTest, ProcessHeadersAndBody) {
stream_->OnStreamHeaders(headers);
EXPECT_EQ(headers, stream_->data());
stream_->OnStreamHeadersComplete(false, headers.size());
- QuicStreamFrame frame(kStreamId, false, 0, MakeIOVector(body));
+ QuicStreamFrame frame(kClientDataStreamId1, false, 0, MakeIOVector(body));
stream_->OnStreamFrame(frame);
EXPECT_EQ(headers + body, stream_->data());
@@ -165,7 +162,8 @@ TEST_P(QuicDataStreamTest, ProcessHeadersAndBodyFragments) {
size_t remaining_data = body.size() - offset;
StringPiece fragment(body.data() + offset,
min(fragment_size, remaining_data));
- QuicStreamFrame frame(kStreamId, false, offset, MakeIOVector(fragment));
+ QuicStreamFrame frame(kClientDataStreamId1, false, offset,
+ MakeIOVector(fragment));
stream_->OnStreamFrame(frame);
}
ASSERT_EQ(headers + body,
@@ -188,13 +186,14 @@ TEST_P(QuicDataStreamTest, ProcessHeadersAndBodyFragmentsSplit) {
stream_->OnStreamHeadersComplete(false, headers.size());
StringPiece fragment1(body.data(), split_point);
- QuicStreamFrame frame1(kStreamId, false, 0, MakeIOVector(fragment1));
+ QuicStreamFrame frame1(kClientDataStreamId1, false, 0,
+ MakeIOVector(fragment1));
stream_->OnStreamFrame(frame1);
StringPiece fragment2(body.data() + split_point,
body.size() - split_point);
- QuicStreamFrame frame2(
- kStreamId, false, split_point, MakeIOVector(fragment2));
+ QuicStreamFrame frame2(kClientDataStreamId1, false, split_point,
+ MakeIOVector(fragment2));
stream_->OnStreamFrame(frame2);
ASSERT_EQ(headers + body,
@@ -211,7 +210,7 @@ TEST_P(QuicDataStreamTest, ProcessHeadersAndBodyReadv) {
stream_->OnStreamHeaders(headers);
EXPECT_EQ(headers, stream_->data());
stream_->OnStreamHeadersComplete(false, headers.size());
- QuicStreamFrame frame(kStreamId, false, 0, MakeIOVector(body));
+ QuicStreamFrame frame(kClientDataStreamId1, false, 0, MakeIOVector(body));
stream_->OnStreamFrame(frame);
char buffer[2048];
@@ -237,10 +236,9 @@ TEST_P(QuicDataStreamTest, ProcessHeadersAndBodyIncrementalReadv) {
stream_->OnStreamHeaders(headers);
EXPECT_EQ(headers, stream_->data());
stream_->OnStreamHeadersComplete(false, headers.size());
- QuicStreamFrame frame(kStreamId, false, 0, MakeIOVector(body));
+ QuicStreamFrame frame(kClientDataStreamId1, false, 0, MakeIOVector(body));
stream_->OnStreamFrame(frame);
-
char buffer[1];
struct iovec vec;
vec.iov_base = buffer;
@@ -262,10 +260,9 @@ TEST_P(QuicDataStreamTest, ProcessHeadersUsingReadvWithMultipleIovecs) {
stream_->OnStreamHeaders(headers);
EXPECT_EQ(headers, stream_->data());
stream_->OnStreamHeadersComplete(false, headers.size());
- QuicStreamFrame frame(kStreamId, false, 0, MakeIOVector(body));
+ QuicStreamFrame frame(kClientDataStreamId1, false, 0, MakeIOVector(body));
stream_->OnStreamFrame(frame);
-
char buffer1[1];
char buffer2[1];
struct iovec vec[2];
@@ -305,9 +302,9 @@ TEST_P(QuicDataStreamTest, StreamFlowControlBlocked) {
const uint64 kOverflow = 15;
GenerateBody(&body, kWindow + kOverflow);
- EXPECT_CALL(*connection_, SendBlocked(kStreamId));
- EXPECT_CALL(*session_, WritevData(kStreamId, _, _, _, _)).WillOnce(
- Return(QuicConsumedData(kWindow, true)));
+ EXPECT_CALL(*connection_, SendBlocked(kClientDataStreamId1));
+ EXPECT_CALL(*session_, WritevData(kClientDataStreamId1, _, _, _, _))
+ .WillOnce(Return(QuicConsumedData(kWindow, true)));
stream_->WriteOrBufferData(body, false, NULL);
// Should have sent as much as possible, resulting in no send window left.
@@ -352,7 +349,7 @@ TEST_P(QuicDataStreamTest, StreamFlowControlNoWindowUpdateIfNotConsumed) {
EXPECT_EQ(headers, stream_->data());
stream_->OnStreamHeadersComplete(false, headers.size());
- QuicStreamFrame frame1(kStreamId, false, 0, MakeIOVector(body));
+ QuicStreamFrame frame1(kClientDataStreamId1, false, 0, MakeIOVector(body));
stream_->OnStreamFrame(frame1);
EXPECT_EQ(kWindow - (kWindow / 3), QuicFlowControllerPeer::ReceiveWindowSize(
stream_->flow_controller()));
@@ -360,7 +357,8 @@ TEST_P(QuicDataStreamTest, StreamFlowControlNoWindowUpdateIfNotConsumed) {
// Now receive another frame which results in the receive window being over
// half full. This should all be buffered, decreasing the receive window but
// not sending WINDOW_UPDATE.
- QuicStreamFrame frame2(kStreamId, false, kWindow / 3, MakeIOVector(body));
+ QuicStreamFrame frame2(kClientDataStreamId1, false, kWindow / 3,
+ MakeIOVector(body));
stream_->OnStreamFrame(frame2);
EXPECT_EQ(
kWindow - (2 * kWindow / 3),
@@ -395,7 +393,7 @@ TEST_P(QuicDataStreamTest, StreamFlowControlWindowUpdate) {
EXPECT_EQ(headers, stream_->data());
stream_->OnStreamHeadersComplete(false, headers.size());
- QuicStreamFrame frame1(kStreamId, false, 0, MakeIOVector(body));
+ QuicStreamFrame frame1(kClientDataStreamId1, false, 0, MakeIOVector(body));
stream_->OnStreamFrame(frame1);
EXPECT_EQ(kWindow - (kWindow / 3), QuicFlowControllerPeer::ReceiveWindowSize(
stream_->flow_controller()));
@@ -404,12 +402,13 @@ TEST_P(QuicDataStreamTest, StreamFlowControlWindowUpdate) {
// half full. This will trigger the stream to increase its receive window
// offset and send a WINDOW_UPDATE. The result will be again an available
// window of kWindow bytes.
- QuicStreamFrame frame2(kStreamId, false, kWindow / 3, MakeIOVector(body));
- EXPECT_CALL(
- *connection_,
- SendWindowUpdate(kStreamId, QuicFlowControllerPeer::ReceiveWindowOffset(
- stream_->flow_controller()) +
- 2 * kWindow / 3));
+ QuicStreamFrame frame2(kClientDataStreamId1, false, kWindow / 3,
+ MakeIOVector(body));
+ EXPECT_CALL(*connection_,
+ SendWindowUpdate(kClientDataStreamId1,
+ QuicFlowControllerPeer::ReceiveWindowOffset(
+ stream_->flow_controller()) +
+ 2 * kWindow / 3));
stream_->OnStreamFrame(frame2);
EXPECT_EQ(kWindow, QuicFlowControllerPeer::ReceiveWindowSize(
stream_->flow_controller()));
@@ -453,21 +452,22 @@ TEST_P(QuicDataStreamTest, ConnectionFlowControlWindowUpdate) {
// WINDOW_UPDATE for either stream, nor for the connection.
string body;
GenerateBody(&body, kWindow / 4);
- QuicStreamFrame frame1(kStreamId, false, 0, MakeIOVector(body));
+ QuicStreamFrame frame1(kClientDataStreamId1, false, 0, MakeIOVector(body));
stream_->OnStreamFrame(frame1);
- QuicStreamFrame frame2(kStreamId + 2, false, 0, MakeIOVector(body));
+ QuicStreamFrame frame2(kClientDataStreamId2, false, 0, MakeIOVector(body));
stream2_->OnStreamFrame(frame2);
// Now receive a further single byte on one stream - again this does not
// trigger a stream WINDOW_UPDATE, but now the connection flow control window
// is over half full and thus a connection WINDOW_UPDATE is sent.
- EXPECT_CALL(*connection_, SendWindowUpdate(kStreamId, _)).Times(0);
- EXPECT_CALL(*connection_, SendWindowUpdate(kStreamId + 2, _)).Times(0);
+ EXPECT_CALL(*connection_, SendWindowUpdate(kClientDataStreamId1, _)).Times(0);
+ EXPECT_CALL(*connection_, SendWindowUpdate(kClientDataStreamId2, _)).Times(0);
EXPECT_CALL(*connection_,
SendWindowUpdate(0, QuicFlowControllerPeer::ReceiveWindowOffset(
session_->flow_controller()) +
1 + kWindow / 2));
- QuicStreamFrame frame3(kStreamId, false, (kWindow / 4), MakeIOVector("a"));
+ QuicStreamFrame frame3(kClientDataStreamId1, false, (kWindow / 4),
+ MakeIOVector("a"));
stream_->OnStreamFrame(frame3);
}
@@ -496,7 +496,7 @@ TEST_P(QuicDataStreamTest, StreamFlowControlViolation) {
// Receive data to overflow the window, violating flow control.
string body;
GenerateBody(&body, kWindow + 1);
- QuicStreamFrame frame(kStreamId, false, 0, MakeIOVector(body));
+ QuicStreamFrame frame(kClientDataStreamId1, false, 0, MakeIOVector(body));
EXPECT_CALL(*connection_, SendConnectionClose(QUIC_FLOW_CONTROL_ERROR));
stream_->OnStreamFrame(frame);
}
@@ -532,7 +532,7 @@ TEST_P(QuicDataStreamTest, ConnectionFlowControlViolation) {
string body;
GenerateBody(&body, kConnectionWindow + 1);
EXPECT_LT(body.size(), kStreamWindow);
- QuicStreamFrame frame(kStreamId, false, 0, MakeIOVector(body));
+ QuicStreamFrame frame(kClientDataStreamId1, false, 0, MakeIOVector(body));
EXPECT_CALL(*connection_, SendConnectionClose(QUIC_FLOW_CONTROL_ERROR));
stream_->OnStreamFrame(frame);
@@ -557,9 +557,9 @@ TEST_P(QuicDataStreamTest, StreamFlowControlFinNotBlocked) {
string body = "";
bool fin = true;
- EXPECT_CALL(*connection_, SendBlocked(kStreamId)).Times(0);
- EXPECT_CALL(*session_, WritevData(kStreamId, _, _, _, _)).WillOnce(
- Return(QuicConsumedData(0, fin)));
+ EXPECT_CALL(*connection_, SendBlocked(kClientDataStreamId1)).Times(0);
+ EXPECT_CALL(*session_, WritevData(kClientDataStreamId1, _, _, _, _))
+ .WillOnce(Return(QuicConsumedData(0, fin)));
stream_->WriteOrBufferData(body, fin, NULL);
}
diff --git a/net/quic/quic_headers_stream_test.cc b/net/quic/quic_headers_stream_test.cc
index 4022073..8ce730a 100644
--- a/net/quic/quic_headers_stream_test.cc
+++ b/net/quic/quic_headers_stream_test.cc
@@ -194,7 +194,8 @@ TEST_P(QuicHeadersStreamTest, EffectivePriority) {
}
TEST_P(QuicHeadersStreamTest, WriteHeaders) {
- for (QuicStreamId stream_id = 5; stream_id < 9; stream_id +=2) {
+ for (QuicStreamId stream_id = kClientDataStreamId1;
+ stream_id < kClientDataStreamId3; stream_id += 2) {
for (int count = 0; count < 2; ++count) {
bool fin = (count == 0);
if (is_server()) {
@@ -209,7 +210,8 @@ TEST_P(QuicHeadersStreamTest, WriteHeaders) {
}
TEST_P(QuicHeadersStreamTest, ProcessRawData) {
- for (QuicStreamId stream_id = 5; stream_id < 9; stream_id +=2) {
+ for (QuicStreamId stream_id = kClientDataStreamId1;
+ stream_id < kClientDataStreamId3; stream_id += 2) {
for (int count = 0; count < 2; ++count) {
bool fin = (count == 0);
for (QuicPriority priority = 0; priority < 7; ++priority) {
diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc
index 206c00d..d413b66 100644
--- a/net/quic/quic_http_stream_test.cc
+++ b/net/quic/quic_http_stream_test.cc
@@ -129,7 +129,7 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<QuicVersion> {
use_closing_stream_(false),
read_buffer_(new IOBufferWithSize(4096)),
connection_id_(2),
- stream_id_(5),
+ stream_id_(kClientDataStreamId1),
maker_(GetParam(), connection_id_),
random_generator_(0) {
IPAddressNumber ip;
diff --git a/net/quic/quic_network_transaction_unittest.cc b/net/quic/quic_network_transaction_unittest.cc
index 3ffa159..c5994a1 100644
--- a/net/quic/quic_network_transaction_unittest.cc
+++ b/net/quic/quic_network_transaction_unittest.cc
@@ -54,9 +54,6 @@ static const char kQuicAlternateProtocolHttpHeader[] =
static const char kQuicAlternateProtocolHttpsHeader[] =
"Alternate-Protocol: 443:quic\r\n\r\n";
-// Used by the QuicNetworkTransactionTest unit tests.
-const net::QuicStreamId kStreamId5 = 5;
-
} // namespace
namespace net {
@@ -324,13 +321,13 @@ TEST_P(QuicNetworkTransactionTest, ForceQuic) {
MockQuicData mock_quic_data;
mock_quic_data.AddWrite(
- ConstructRequestHeadersPacket(1, kStreamId5, true, true,
+ ConstructRequestHeadersPacket(1, kClientDataStreamId1, true, true,
GetRequestHeaders("GET", "http", "/")));
mock_quic_data.AddRead(
- ConstructResponseHeadersPacket(1, kStreamId5, false, false,
+ ConstructResponseHeadersPacket(1, kClientDataStreamId1, false, false,
GetResponseHeaders("200 OK")));
mock_quic_data.AddRead(
- ConstructDataPacket(2, kStreamId5, false, true, 0, "hello!"));
+ ConstructDataPacket(2, kClientDataStreamId1, false, true, 0, "hello!"));
mock_quic_data.AddWrite(ConstructAckPacket(2, 1));
mock_quic_data.AddRead(SYNCHRONOUS, 0); // EOF
@@ -386,13 +383,13 @@ TEST_P(QuicNetworkTransactionTest, QuicProxy) {
MockQuicData mock_quic_data;
mock_quic_data.AddWrite(
- ConstructRequestHeadersPacket(1, kStreamId5, true, true,
+ ConstructRequestHeadersPacket(1, kClientDataStreamId1, true, true,
GetRequestHeaders("GET", "http", "/")));
mock_quic_data.AddRead(
- ConstructResponseHeadersPacket(1, kStreamId5, false, false,
+ ConstructResponseHeadersPacket(1, kClientDataStreamId1, false, false,
GetResponseHeaders("200 OK")));
mock_quic_data.AddRead(
- ConstructDataPacket(2, kStreamId5, false, true, 0, "hello!"));
+ ConstructDataPacket(2, kClientDataStreamId1, false, true, 0, "hello!"));
mock_quic_data.AddWrite(ConstructAckPacket(2, 1));
mock_quic_data.AddRead(SYNCHRONOUS, 0); // EOF
@@ -464,13 +461,13 @@ TEST_P(QuicNetworkTransactionTest, UseAlternateProtocolForQuic) {
MockQuicData mock_quic_data;
mock_quic_data.AddWrite(
- ConstructRequestHeadersPacket(1, kStreamId5, true, true,
+ ConstructRequestHeadersPacket(1, kClientDataStreamId1, true, true,
GetRequestHeaders("GET", "http", "/")));
mock_quic_data.AddRead(
- ConstructResponseHeadersPacket(1, kStreamId5, false, false,
+ ConstructResponseHeadersPacket(1, kClientDataStreamId1, false, false,
GetResponseHeaders("200 OK")));
mock_quic_data.AddRead(
- ConstructDataPacket(2, kStreamId5, false, true, 0, "hello!"));
+ ConstructDataPacket(2, kClientDataStreamId1, false, true, 0, "hello!"));
mock_quic_data.AddWrite(ConstructAckPacket(2, 1));
mock_quic_data.AddRead(SYNCHRONOUS, 0); // EOF
@@ -506,13 +503,13 @@ TEST_P(QuicNetworkTransactionTest, UseAlternateProtocolForQuicForHttps) {
MockQuicData mock_quic_data;
mock_quic_data.AddWrite(
- ConstructRequestHeadersPacket(1, kStreamId5, true, true,
+ ConstructRequestHeadersPacket(1, kClientDataStreamId1, true, true,
GetRequestHeaders("GET", "http", "/")));
mock_quic_data.AddRead(
- ConstructResponseHeadersPacket(1, kStreamId5, false, false,
+ ConstructResponseHeadersPacket(1, kClientDataStreamId1, false, false,
GetResponseHeaders("200 OK")));
mock_quic_data.AddRead(
- ConstructDataPacket(2, kStreamId5, false, true, 0, "hello!"));
+ ConstructDataPacket(2, kClientDataStreamId1, false, true, 0, "hello!"));
mock_quic_data.AddWrite(ConstructAckPacket(2, 1));
mock_quic_data.AddRead(SYNCHRONOUS, 0); // EOF
@@ -592,13 +589,13 @@ TEST_P(QuicNetworkTransactionTest, ZeroRTTWithHttpRace) {
MockQuicData mock_quic_data;
mock_quic_data.AddWrite(
- ConstructRequestHeadersPacket(1, kStreamId5, true, true,
+ ConstructRequestHeadersPacket(1, kClientDataStreamId1, true, true,
GetRequestHeaders("GET", "http", "/")));
mock_quic_data.AddRead(
- ConstructResponseHeadersPacket(1, kStreamId5, false, false,
+ ConstructResponseHeadersPacket(1, kClientDataStreamId1, false, false,
GetResponseHeaders("200 OK")));
mock_quic_data.AddRead(
- ConstructDataPacket(2, kStreamId5, false, true, 0, "hello!"));
+ ConstructDataPacket(2, kClientDataStreamId1, false, true, 0, "hello!"));
mock_quic_data.AddWrite(ConstructAckPacket(2, 1));
mock_quic_data.AddRead(SYNCHRONOUS, 0); // EOF
@@ -618,13 +615,13 @@ TEST_P(QuicNetworkTransactionTest, ZeroRTTWithNoHttpRace) {
MockQuicData mock_quic_data;
mock_quic_data.AddWrite(
- ConstructRequestHeadersPacket(1, kStreamId5, true, true,
+ ConstructRequestHeadersPacket(1, kClientDataStreamId1, true, true,
GetRequestHeaders("GET", "http", "/")));
mock_quic_data.AddRead(
- ConstructResponseHeadersPacket(1, kStreamId5, false, false,
+ ConstructResponseHeadersPacket(1, kClientDataStreamId1, false, false,
GetResponseHeaders("200 OK")));
mock_quic_data.AddRead(
- ConstructDataPacket(2, kStreamId5, false, true, 0, "hello!"));
+ ConstructDataPacket(2, kClientDataStreamId1, false, true, 0, "hello!"));
mock_quic_data.AddWrite(ConstructAckPacket(2, 1));
mock_quic_data.AddRead(SYNCHRONOUS, 0); // EOF
mock_quic_data.AddDelayedSocketDataToFactory(&socket_factory_, 1);
@@ -695,13 +692,13 @@ TEST_P(QuicNetworkTransactionTest, ZeroRTTWithConfirmationRequired) {
MockQuicData mock_quic_data;
mock_quic_data.AddWrite(
- ConstructRequestHeadersPacket(1, kStreamId5, true, true,
+ ConstructRequestHeadersPacket(1, kClientDataStreamId1, true, true,
GetRequestHeaders("GET", "http", "/")));
mock_quic_data.AddRead(
- ConstructResponseHeadersPacket(1, kStreamId5, false, false,
+ ConstructResponseHeadersPacket(1, kClientDataStreamId1, false, false,
GetResponseHeaders("200 OK")));
mock_quic_data.AddRead(
- ConstructDataPacket(2, kStreamId5, false, true, 0, "hello!"));
+ ConstructDataPacket(2, kClientDataStreamId1, false, true, 0, "hello!"));
mock_quic_data.AddWrite(ConstructAckPacket(2, 1));
mock_quic_data.AddRead(SYNCHRONOUS, 0); // EOF
mock_quic_data.AddDelayedSocketDataToFactory(&socket_factory_, 1);
@@ -902,7 +899,7 @@ TEST_P(QuicNetworkTransactionTest, ConnectionCloseDuringConnect) {
MockQuicData mock_quic_data;
mock_quic_data.AddRead(ConstructConnectionClosePacket(1));
mock_quic_data.AddWrite(
- ConstructRequestHeadersPacket(1, kStreamId5, true, true,
+ ConstructRequestHeadersPacket(1, kClientDataStreamId1, true, true,
GetRequestHeaders("GET", "http", "/")));
mock_quic_data.AddWrite(ConstructAckPacket(2, 1));
mock_quic_data.AddDelayedSocketDataToFactory(&socket_factory_, 0);
diff --git a/net/quic/quic_packet_creator_test.cc b/net/quic/quic_packet_creator_test.cc
index 72faf7e..3e3b228 100644
--- a/net/quic/quic_packet_creator_test.cc
+++ b/net/quic/quic_packet_creator_test.cc
@@ -116,10 +116,10 @@ class QuicPacketCreatorTest : public ::testing::TestWithParam<TestParams> {
// Returns the number of bytes consumed by the non-data fields of a stream
// frame, assuming it is the last frame in the packet
size_t GetStreamFrameOverhead(InFecGroup is_in_fec_group) {
- return QuicFramer::GetMinStreamFrameSize(
- client_framer_.version(), kStreamId, kOffset, true, is_in_fec_group);
+ return QuicFramer::GetMinStreamFrameSize(client_framer_.version(),
+ kClientDataStreamId1, kOffset,
+ true, is_in_fec_group);
}
- static const QuicStreamId kStreamId = 1u;
static const QuicStreamOffset kOffset = 1u;
QuicFrames frames_;
@@ -503,12 +503,13 @@ TEST_P(QuicPacketCreatorTest, CreateAllFreeBytesForStreamFrames) {
creator_.options()->max_packet_length = i;
const bool should_have_room = i > overhead + GetStreamFrameOverhead(
NOT_IN_FEC_GROUP);
- ASSERT_EQ(should_have_room,
- creator_.HasRoomForStreamFrame(kStreamId, kOffset));
+ ASSERT_EQ(should_have_room, creator_.HasRoomForStreamFrame(
+ kClientDataStreamId1, kOffset));
if (should_have_room) {
QuicFrame frame;
size_t bytes_consumed = creator_.CreateStreamFrame(
- kStreamId, MakeIOVector("testdata"), kOffset, false, &frame);
+ kClientDataStreamId1, MakeIOVector("testdata"), kOffset, false,
+ &frame);
EXPECT_LT(0u, bytes_consumed);
ASSERT_TRUE(creator_.AddSavedFrame(frame));
SerializedPacket serialized_packet = creator_.SerializePacket();
@@ -530,7 +531,7 @@ TEST_P(QuicPacketCreatorTest, StreamFrameConsumption) {
size_t bytes_free = delta > 0 ? 0 : 0 - delta;
QuicFrame frame;
size_t bytes_consumed = creator_.CreateStreamFrame(
- kStreamId, MakeIOVector(data), kOffset, false, &frame);
+ kClientDataStreamId1, MakeIOVector(data), kOffset, false, &frame);
EXPECT_EQ(capacity - bytes_free, bytes_consumed);
ASSERT_TRUE(creator_.AddSavedFrame(frame));
@@ -559,7 +560,7 @@ TEST_P(QuicPacketCreatorTest, StreamFrameConsumptionWithFec) {
size_t bytes_free = delta > 0 ? 0 : 0 - delta;
QuicFrame frame;
size_t bytes_consumed = creator_.CreateStreamFrame(
- kStreamId, MakeIOVector(data), kOffset, false, &frame);
+ kClientDataStreamId1, MakeIOVector(data), kOffset, false, &frame);
EXPECT_EQ(capacity - bytes_free, bytes_consumed);
ASSERT_TRUE(creator_.AddSavedFrame(frame));
@@ -589,7 +590,7 @@ TEST_P(QuicPacketCreatorTest, CryptoStreamFramePacketPadding) {
QuicFrame frame;
size_t bytes_consumed = creator_.CreateStreamFrame(
- kStreamId, MakeIOVector(data), kOffset, false, &frame);
+ kCryptoStreamId, MakeIOVector(data), kOffset, false, &frame);
EXPECT_LT(0u, bytes_consumed);
ASSERT_TRUE(creator_.AddSavedFrame(frame));
SerializedPacket serialized_packet = creator_.SerializePacket();
@@ -622,7 +623,7 @@ TEST_P(QuicPacketCreatorTest, NonCryptoStreamFramePacketNonPadding) {
QuicFrame frame;
size_t bytes_consumed = creator_.CreateStreamFrame(
- kStreamId + 2, MakeIOVector(data), kOffset, false, &frame);
+ kClientDataStreamId1, MakeIOVector(data), kOffset, false, &frame);
EXPECT_LT(0u, bytes_consumed);
ASSERT_TRUE(creator_.AddSavedFrame(frame));
SerializedPacket serialized_packet = creator_.SerializePacket();
diff --git a/net/quic/quic_received_packet_manager.cc b/net/quic/quic_received_packet_manager.cc
index 49a056d5..3b47687 100644
--- a/net/quic/quic_received_packet_manager.cc
+++ b/net/quic/quic_received_packet_manager.cc
@@ -26,12 +26,110 @@ const size_t kMaxPacketsAfterNewMissing = 4;
}
+QuicReceivedPacketManager::EntropyTracker::EntropyTracker()
+ : packets_entropy_hash_(0),
+ first_gap_(1),
+ largest_observed_(0) {
+}
+
+QuicReceivedPacketManager::EntropyTracker::~EntropyTracker() {}
+
+QuicPacketEntropyHash QuicReceivedPacketManager::EntropyTracker::EntropyHash(
+ QuicPacketSequenceNumber sequence_number) const {
+ DCHECK_LE(sequence_number, largest_observed_);
+ if (sequence_number == largest_observed_) {
+ return packets_entropy_hash_;
+ }
+
+ DCHECK_GE(sequence_number, first_gap_);
+ ReceivedEntropyMap::const_iterator it =
+ packets_entropy_.upper_bound(sequence_number);
+ // When this map is empty we should only query entropy for
+ // largest_observed_, since no other entropy can be correctly
+ // calculated, because we're not storing the entropy for any prior packets.
+ // TODO(rtenneti): add support for LOG_IF_EVERY_N_SEC to chromium.
+ // LOG_IF_EVERY_N_SEC(DFATAL, it == packets_entropy_.end(), 10)
+ LOG_IF(DFATAL, it == packets_entropy_.end())
+ << "EntropyHash may be unknown. largest_received: "
+ << largest_observed_
+ << " sequence_number: " << sequence_number;
+
+ // TODO(satyamshekhar): Make this O(1).
+ QuicPacketEntropyHash hash = packets_entropy_hash_;
+ for (; it != packets_entropy_.end(); ++it) {
+ hash ^= it->second;
+ }
+ return hash;
+}
+
+void QuicReceivedPacketManager::EntropyTracker::RecordPacketEntropyHash(
+ QuicPacketSequenceNumber sequence_number,
+ QuicPacketEntropyHash entropy_hash) {
+ if (sequence_number < first_gap_) {
+ DVLOG(1) << "Ignoring received packet entropy for sequence_number:"
+ << sequence_number << " less than largest_peer_sequence_number:"
+ << first_gap_;
+ return;
+ }
+
+ if (sequence_number > largest_observed_) {
+ largest_observed_ = sequence_number;
+ }
+
+ packets_entropy_hash_ ^= entropy_hash;
+ DVLOG(2) << "setting cumulative received entropy hash to: "
+ << static_cast<int>(packets_entropy_hash_)
+ << " updated with sequence number " << sequence_number
+ << " entropy hash: " << static_cast<int>(entropy_hash);
+
+ packets_entropy_.insert(make_pair(sequence_number, entropy_hash));
+ AdvanceFirstGapAndGarbageCollectEntropyMap();
+}
+
+void QuicReceivedPacketManager::EntropyTracker::SetCumulativeEntropyUpTo(
+ QuicPacketSequenceNumber sequence_number,
+ QuicPacketEntropyHash entropy_hash) {
+ DCHECK_LE(sequence_number, largest_observed_);
+ if (sequence_number < first_gap_) {
+ DVLOG(1) << "Ignoring set entropy at:" << sequence_number
+ << " less than first_gap_:" << first_gap_;
+ return;
+ }
+ // Compute the current entropy based on the hash.
+ packets_entropy_hash_ = entropy_hash;
+ ReceivedEntropyMap::iterator it =
+ packets_entropy_.lower_bound(sequence_number);
+ // TODO(satyamshekhar): Make this O(1).
+ for (; it != packets_entropy_.end(); ++it) {
+ packets_entropy_hash_ ^= it->second;
+ }
+ // Update first_gap_ and discard old entropies.
+ first_gap_ = sequence_number;
+ packets_entropy_.erase(
+ packets_entropy_.begin(),
+ packets_entropy_.lower_bound(sequence_number));
+
+ // Garbage collect entries from the beginning of the map.
+ AdvanceFirstGapAndGarbageCollectEntropyMap();
+}
+
+void QuicReceivedPacketManager::EntropyTracker::
+AdvanceFirstGapAndGarbageCollectEntropyMap() {
+ while (!packets_entropy_.empty()) {
+ ReceivedEntropyMap::iterator it = packets_entropy_.begin();
+ if (it->first != first_gap_) {
+ DCHECK_GT(it->first, first_gap_);
+ break;
+ }
+ packets_entropy_.erase(it);
+ ++first_gap_;
+ }
+}
+
QuicReceivedPacketManager::QuicReceivedPacketManager(
CongestionFeedbackType congestion_type,
QuicConnectionStats* stats)
- : packets_entropy_hash_(0),
- largest_sequence_number_(0),
- peer_largest_observed_packet_(0),
+ : peer_largest_observed_packet_(0),
least_packet_awaited_by_peer_(1),
peer_least_packet_awaiting_ack_(0),
time_largest_observed_(QuicTime::Zero()),
@@ -53,9 +151,9 @@ void QuicReceivedPacketManager::RecordPacketReceived(
InsertMissingPacketsBetween(
&received_info_,
max(received_info_.largest_observed + 1, peer_least_packet_awaiting_ack_),
- header.packet_sequence_number);
+ sequence_number);
- if (received_info_.largest_observed > header.packet_sequence_number) {
+ if (received_info_.largest_observed > sequence_number) {
// We've gotten one of the out of order packets - remove it from our
// "missing packets" list.
DVLOG(1) << "Removing " << sequence_number << " from missing list";
@@ -71,11 +169,12 @@ void QuicReceivedPacketManager::RecordPacketReceived(
stats_->max_time_reordering_us = max(stats_->max_time_reordering_us,
reordering_time_us);
}
- if (header.packet_sequence_number > received_info_.largest_observed) {
- received_info_.largest_observed = header.packet_sequence_number;
+ if (sequence_number > received_info_.largest_observed) {
+ received_info_.largest_observed = sequence_number;
time_largest_observed_ = receipt_time;
}
- RecordPacketEntropyHash(sequence_number, header.entropy_hash);
+ entropy_tracker_.RecordPacketEntropyHash(sequence_number,
+ header.entropy_hash);
receive_algorithm_->RecordIncomingPacket(
bytes, sequence_number, receipt_time);
@@ -119,23 +218,6 @@ void QuicReceivedPacketManager::UpdateReceivedPacketInfo(
approximate_now.Subtract(time_largest_observed_);
}
-void QuicReceivedPacketManager::RecordPacketEntropyHash(
- QuicPacketSequenceNumber sequence_number,
- QuicPacketEntropyHash entropy_hash) {
- if (sequence_number < largest_sequence_number_) {
- DVLOG(1) << "Ignoring received packet entropy for sequence_number:"
- << sequence_number << " less than largest_peer_sequence_number:"
- << largest_sequence_number_;
- return;
- }
- packets_entropy_.insert(make_pair(sequence_number, entropy_hash));
- packets_entropy_hash_ ^= entropy_hash;
- DVLOG(2) << "setting cumulative received entropy hash to: "
- << static_cast<int>(packets_entropy_hash_)
- << " updated with sequence number " << sequence_number
- << " entropy hash: " << static_cast<int>(entropy_hash);
-}
-
bool QuicReceivedPacketManager::GenerateCongestionFeedback(
QuicCongestionFeedbackFrame* feedback) {
return receive_algorithm_->GenerateCongestionFeedback(feedback);
@@ -143,55 +225,7 @@ bool QuicReceivedPacketManager::GenerateCongestionFeedback(
QuicPacketEntropyHash QuicReceivedPacketManager::EntropyHash(
QuicPacketSequenceNumber sequence_number) const {
- DCHECK_LE(sequence_number, received_info_.largest_observed);
- DCHECK_GE(sequence_number, largest_sequence_number_);
- if (sequence_number == received_info_.largest_observed) {
- return packets_entropy_hash_;
- }
-
- ReceivedEntropyMap::const_iterator it =
- packets_entropy_.upper_bound(sequence_number);
- // When this map is empty we should only query entropy for
- // received_info_.largest_observed, since no other entropy can be correctly
- // calculated, because we're not storing the entropy for any prior packets.
- // TODO(rtenneti): add support for LOG_IF_EVERY_N_SEC to chromium.
- // LOG_IF_EVERY_N_SEC(DFATAL, it == packets_entropy_.end(), 10)
- LOG_IF(DFATAL, it == packets_entropy_.end())
- << "EntropyHash may be unknown. largest_received: "
- << received_info_.largest_observed
- << " sequence_number: " << sequence_number;
-
- // TODO(satyamshekhar): Make this O(1).
- QuicPacketEntropyHash hash = packets_entropy_hash_;
- for (; it != packets_entropy_.end(); ++it) {
- hash ^= it->second;
- }
- return hash;
-}
-
-void QuicReceivedPacketManager::RecalculateEntropyHash(
- QuicPacketSequenceNumber peer_least_unacked,
- QuicPacketEntropyHash entropy_hash) {
- DCHECK_LE(peer_least_unacked, received_info_.largest_observed);
- if (peer_least_unacked < largest_sequence_number_) {
- DVLOG(1) << "Ignoring received peer_least_unacked:" << peer_least_unacked
- << " less than largest_peer_sequence_number:"
- << largest_sequence_number_;
- return;
- }
- largest_sequence_number_ = peer_least_unacked;
- packets_entropy_hash_ = entropy_hash;
- ReceivedEntropyMap::iterator it =
- packets_entropy_.lower_bound(peer_least_unacked);
- // TODO(satyamshekhar): Make this O(1).
- for (; it != packets_entropy_.end(); ++it) {
- packets_entropy_hash_ ^= it->second;
- }
- // Discard entropies before least unacked.
- packets_entropy_.erase(
- packets_entropy_.begin(),
- packets_entropy_.lower_bound(
- min(peer_least_unacked, received_info_.largest_observed)));
+ return entropy_tracker_.EntropyHash(sequence_number);
}
void QuicReceivedPacketManager::UpdatePacketInformationReceivedByPeer(
@@ -225,13 +259,12 @@ void QuicReceivedPacketManager::UpdatePacketInformationSentByPeer(
DCHECK_LE(peer_least_packet_awaiting_ack_, stop_waiting.least_unacked);
if (stop_waiting.least_unacked > peer_least_packet_awaiting_ack_) {
bool missed_packets = DontWaitForPacketsBefore(stop_waiting.least_unacked);
- if (missed_packets || stop_waiting.least_unacked >
- received_info_.largest_observed + 1) {
+ if (missed_packets) {
DVLOG(1) << "Updating entropy hashed since we missed packets";
// There were some missing packets that we won't ever get now. Recalculate
// the received entropy hash.
- RecalculateEntropyHash(stop_waiting.least_unacked,
- stop_waiting.entropy_hash);
+ entropy_tracker_.SetCumulativeEntropyUpTo(stop_waiting.least_unacked,
+ stop_waiting.entropy_hash);
}
peer_least_packet_awaiting_ack_ = stop_waiting.least_unacked;
}
diff --git a/net/quic/quic_received_packet_manager.h b/net/quic/quic_received_packet_manager.h
index 05339f1..1b28331 100644
--- a/net/quic/quic_received_packet_manager.h
+++ b/net/quic/quic_received_packet_manager.h
@@ -15,6 +15,7 @@
namespace net {
namespace test {
+class EntropyTrackerPeer;
class QuicConnectionPeer;
class QuicReceivedPacketManagerPeer;
} // namespace test
@@ -27,6 +28,72 @@ struct QuicConnectionStats;
class NET_EXPORT_PRIVATE QuicReceivedPacketManager :
public QuicReceivedEntropyHashCalculatorInterface {
public:
+ class NET_EXPORT_PRIVATE EntropyTracker {
+ public:
+ EntropyTracker();
+ ~EntropyTracker();
+
+ // Compute the XOR of the entropy of all received packets up to
+ // and including sequence_number.
+ // Requires that either:
+ // sequence_number == largest_observed_
+ // or:
+ // sequence_number > first_gap_ &&
+ // sequence_number < largest_observed_ &&
+ // sequence_number in packets_entropy_
+ QuicPacketEntropyHash EntropyHash(
+ QuicPacketSequenceNumber sequence_number) const;
+
+ // Record the received entropy hash against |sequence_number|.
+ // Performs garbage collection to advance first_gap_ if
+ // sequence_number == first_gap_.
+ void RecordPacketEntropyHash(QuicPacketSequenceNumber sequence_number,
+ QuicPacketEntropyHash entropy_hash);
+
+ // Sets the entropy hash up to but not including a sequence number based
+ // on the hash provided by a StopWaiting frame. Clears older packet
+ // entropy entries and performs garbage collection up to the first gap.
+ void SetCumulativeEntropyUpTo(QuicPacketSequenceNumber sequence_number,
+ QuicPacketEntropyHash entropy_hash);
+
+ private:
+ friend class test::EntropyTrackerPeer;
+
+ typedef std::map<QuicPacketSequenceNumber,
+ QuicPacketEntropyHash> ReceivedEntropyMap;
+
+ // Recomputes first_gap_ and removes packets_entropy_ entries that are no
+ // longer needed to compute EntropyHash.
+ void AdvanceFirstGapAndGarbageCollectEntropyMap();
+
+ // TODO(satyamshekhar): Can be optimized using an interval set like data
+ // structure.
+ // Map of received sequence numbers to their corresponding entropy.
+ // Stores an entry for every received packet whose sequence_number is larger
+ // than first_gap_. Packets without the entropy bit set have an entropy
+ // value of 0.
+ // TODO(ianswett): When the entropy flag is off, the entropy
+ // should not be 0.
+ ReceivedEntropyMap packets_entropy_;
+
+ // Cumulative hash of entropy of all received packets.
+ QuicPacketEntropyHash packets_entropy_hash_;
+
+ // Sequence number of the first packet that we do not know the entropy of.
+ // If there are no gaps in the received packet sequence,
+ // packets_entropy_ will be empty and first_gap_ will be equal to
+ // 'largest_observed_ + 1' since that's the first packet for which
+ // entropy is unknown. If there are gaps, packets_entropy_ will
+ // contain entries for all received packets with sequence_number >
+ // first_gap_.
+ QuicPacketSequenceNumber first_gap_;
+
+ // Sequence number of the largest observed packet.
+ QuicPacketSequenceNumber largest_observed_;
+
+ DISALLOW_COPY_AND_ASSIGN(EntropyTracker);
+ };
+
explicit QuicReceivedPacketManager(CongestionFeedbackType congestion_type,
QuicConnectionStats* stats);
virtual ~QuicReceivedPacketManager();
@@ -94,40 +161,14 @@ class NET_EXPORT_PRIVATE QuicReceivedPacketManager :
friend class test::QuicConnectionPeer;
friend class test::QuicReceivedPacketManagerPeer;
- typedef std::map<QuicPacketSequenceNumber,
- QuicPacketEntropyHash> ReceivedEntropyMap;
-
- // Record the received entropy hash against |sequence_number|.
- void RecordPacketEntropyHash(QuicPacketSequenceNumber sequence_number,
- QuicPacketEntropyHash entropy_hash);
-
- // Recalculate the entropy hash and clears old packet entropies,
- // now that the sender sent us the |entropy_hash| for packets up to,
- // but not including, |peer_least_unacked|.
- void RecalculateEntropyHash(QuicPacketSequenceNumber peer_least_unacked,
- QuicPacketEntropyHash entropy_hash);
-
// Deletes all missing packets before least unacked. The connection won't
// process any packets with sequence number before |least_unacked| that it
// received after this call. Returns true if there were missing packets before
// |least_unacked| unacked, false otherwise.
bool DontWaitForPacketsBefore(QuicPacketSequenceNumber least_unacked);
- // TODO(satyamshekhar): Can be optimized using an interval set like data
- // structure.
- // Map of received sequence numbers to their corresponding entropy.
- // Every received packet has an entry, and packets without the entropy bit set
- // have an entropy value of 0.
- // TODO(ianswett): When the entropy flag is off, the entropy should not be 0.
- ReceivedEntropyMap packets_entropy_;
-
- // Cumulative hash of entropy of all received packets.
- QuicPacketEntropyHash packets_entropy_hash_;
-
- // The largest sequence number cleared by RecalculateEntropyHash.
- // Received entropy cannot be calculated for numbers less than it.
- QuicPacketSequenceNumber largest_sequence_number_;
-
+ // Tracks entropy hashes of received packets.
+ EntropyTracker entropy_tracker_;
// Track some peer state so we can do less bookkeeping.
// Largest sequence number that the peer has observed. Mostly received,
diff --git a/net/quic/quic_received_packet_manager_test.cc b/net/quic/quic_received_packet_manager_test.cc
index 1b893b7..30c84c5 100644
--- a/net/quic/quic_received_packet_manager_test.cc
+++ b/net/quic/quic_received_packet_manager_test.cc
@@ -18,8 +18,172 @@ using std::vector;
namespace net {
namespace test {
+
+class EntropyTrackerPeer {
+ public:
+ static QuicPacketSequenceNumber first_gap(
+ const QuicReceivedPacketManager::EntropyTracker& tracker) {
+ return tracker.first_gap_;
+ }
+ static QuicPacketSequenceNumber largest_observed(
+ const QuicReceivedPacketManager::EntropyTracker& tracker) {
+ return tracker.largest_observed_;
+ }
+ static int packets_entropy_size(
+ const QuicReceivedPacketManager::EntropyTracker& tracker) {
+ return tracker.packets_entropy_.size();
+ }
+ static bool IsTrackingPacket(
+ const QuicReceivedPacketManager::EntropyTracker& tracker,
+ QuicPacketSequenceNumber sequence_number) {
+ return tracker.packets_entropy_.find(sequence_number) !=
+ tracker.packets_entropy_.end();
+ }
+};
+
namespace {
+// Entropy of individual packets is not tracked if there are no gaps.
+TEST(EntropyTrackerTest, NoGaps) {
+ QuicReceivedPacketManager::EntropyTracker tracker;
+
+ tracker.RecordPacketEntropyHash(1, 23);
+ tracker.RecordPacketEntropyHash(2, 42);
+
+ EXPECT_EQ(23 ^ 42, tracker.EntropyHash(2));
+ EXPECT_EQ(3u, EntropyTrackerPeer::first_gap(tracker));
+
+ EXPECT_EQ(2u, EntropyTrackerPeer::largest_observed(tracker));
+ EXPECT_EQ(0, EntropyTrackerPeer::packets_entropy_size(tracker));
+ EXPECT_FALSE(EntropyTrackerPeer::IsTrackingPacket(tracker, 1));
+ EXPECT_FALSE(EntropyTrackerPeer::IsTrackingPacket(tracker, 2));
+}
+
+// Entropy of individual packets is tracked as long as there are gaps.
+// Filling the first gap results in entropy getting garbage collected.
+TEST(EntropyTrackerTest, FillGaps) {
+ QuicReceivedPacketManager::EntropyTracker tracker;
+
+ tracker.RecordPacketEntropyHash(2, 5);
+ tracker.RecordPacketEntropyHash(5, 17);
+ tracker.RecordPacketEntropyHash(6, 23);
+ tracker.RecordPacketEntropyHash(9, 42);
+
+ EXPECT_EQ(1u, EntropyTrackerPeer::first_gap(tracker));
+ EXPECT_EQ(9u, EntropyTrackerPeer::largest_observed(tracker));
+ EXPECT_EQ(4, EntropyTrackerPeer::packets_entropy_size(tracker));
+
+ EXPECT_EQ(5, tracker.EntropyHash(2));
+ EXPECT_EQ(5 ^ 17, tracker.EntropyHash(5));
+ EXPECT_EQ(5 ^ 17 ^ 23, tracker.EntropyHash(6));
+ EXPECT_EQ(5 ^ 17 ^ 23 ^ 42, tracker.EntropyHash(9));
+
+ EXPECT_FALSE(EntropyTrackerPeer::IsTrackingPacket(tracker, 1));
+ EXPECT_TRUE(EntropyTrackerPeer::IsTrackingPacket(tracker, 2));
+ EXPECT_TRUE(EntropyTrackerPeer::IsTrackingPacket(tracker, 5));
+ EXPECT_TRUE(EntropyTrackerPeer::IsTrackingPacket(tracker, 6));
+ EXPECT_TRUE(EntropyTrackerPeer::IsTrackingPacket(tracker, 9));
+
+ // Fill the gap at 1.
+ tracker.RecordPacketEntropyHash(1, 2);
+
+ EXPECT_EQ(3u, EntropyTrackerPeer::first_gap(tracker));
+ EXPECT_EQ(9u, EntropyTrackerPeer::largest_observed(tracker));
+ EXPECT_EQ(3, EntropyTrackerPeer::packets_entropy_size(tracker));
+
+ EXPECT_EQ(2 ^ 5 ^ 17, tracker.EntropyHash(5));
+ EXPECT_EQ(2 ^ 5 ^ 17 ^ 23, tracker.EntropyHash(6));
+ EXPECT_EQ(2 ^ 5 ^ 17 ^ 23 ^ 42, tracker.EntropyHash(9));
+
+ EXPECT_FALSE(EntropyTrackerPeer::IsTrackingPacket(tracker, 1));
+ EXPECT_FALSE(EntropyTrackerPeer::IsTrackingPacket(tracker, 2));
+ EXPECT_TRUE(EntropyTrackerPeer::IsTrackingPacket(tracker, 5));
+ EXPECT_TRUE(EntropyTrackerPeer::IsTrackingPacket(tracker, 6));
+ EXPECT_TRUE(EntropyTrackerPeer::IsTrackingPacket(tracker, 9));
+
+ // Fill the gap at 4.
+ tracker.RecordPacketEntropyHash(4, 2);
+
+ EXPECT_EQ(3u, EntropyTrackerPeer::first_gap(tracker));
+ EXPECT_EQ(9u, EntropyTrackerPeer::largest_observed(tracker));
+ EXPECT_EQ(4, EntropyTrackerPeer::packets_entropy_size(tracker));
+
+ EXPECT_EQ(5, tracker.EntropyHash(4));
+ EXPECT_EQ(5 ^ 17, tracker.EntropyHash(5));
+ EXPECT_EQ(5 ^ 17 ^ 23, tracker.EntropyHash(6));
+ EXPECT_EQ(5 ^ 17 ^ 23 ^ 42, tracker.EntropyHash(9));
+
+ EXPECT_FALSE(EntropyTrackerPeer::IsTrackingPacket(tracker, 3));
+ EXPECT_TRUE(EntropyTrackerPeer::IsTrackingPacket(tracker, 4));
+ EXPECT_TRUE(EntropyTrackerPeer::IsTrackingPacket(tracker, 5));
+ EXPECT_TRUE(EntropyTrackerPeer::IsTrackingPacket(tracker, 6));
+ EXPECT_TRUE(EntropyTrackerPeer::IsTrackingPacket(tracker, 9));
+
+ // Fill the gap at 3. Entropy for packets 3 to 6 are forgotten.
+ tracker.RecordPacketEntropyHash(3, 2);
+
+ EXPECT_EQ(7u, EntropyTrackerPeer::first_gap(tracker));
+ EXPECT_EQ(9u, EntropyTrackerPeer::largest_observed(tracker));
+ EXPECT_EQ(1, EntropyTrackerPeer::packets_entropy_size(tracker));
+
+ EXPECT_EQ(2 ^ 5 ^ 17 ^ 23 ^ 42, tracker.EntropyHash(9));
+
+ EXPECT_FALSE(EntropyTrackerPeer::IsTrackingPacket(tracker, 3));
+ EXPECT_FALSE(EntropyTrackerPeer::IsTrackingPacket(tracker, 4));
+ EXPECT_FALSE(EntropyTrackerPeer::IsTrackingPacket(tracker, 5));
+ EXPECT_FALSE(EntropyTrackerPeer::IsTrackingPacket(tracker, 6));
+ EXPECT_TRUE(EntropyTrackerPeer::IsTrackingPacket(tracker, 9));
+
+ // Fill in the rest.
+ tracker.RecordPacketEntropyHash(7, 2);
+ tracker.RecordPacketEntropyHash(8, 2);
+
+ EXPECT_EQ(10u, EntropyTrackerPeer::first_gap(tracker));
+ EXPECT_EQ(9u, EntropyTrackerPeer::largest_observed(tracker));
+ EXPECT_EQ(0, EntropyTrackerPeer::packets_entropy_size(tracker));
+
+ EXPECT_EQ(2 ^ 5 ^ 17 ^ 23 ^ 42, tracker.EntropyHash(9));
+}
+
+TEST(EntropyTrackerTest, SetCumulativeEntropyUpTo) {
+ QuicReceivedPacketManager::EntropyTracker tracker;
+
+ tracker.RecordPacketEntropyHash(2, 5);
+ tracker.RecordPacketEntropyHash(5, 17);
+ tracker.RecordPacketEntropyHash(6, 23);
+ tracker.RecordPacketEntropyHash(9, 42);
+
+ EXPECT_EQ(1u, EntropyTrackerPeer::first_gap(tracker));
+ EXPECT_EQ(9u, EntropyTrackerPeer::largest_observed(tracker));
+ EXPECT_EQ(4, EntropyTrackerPeer::packets_entropy_size(tracker));
+
+ // Inform the tracker about value of the hash at a gap.
+ tracker.SetCumulativeEntropyUpTo(3, 7);
+ EXPECT_EQ(3u, EntropyTrackerPeer::first_gap(tracker));
+ EXPECT_EQ(9u, EntropyTrackerPeer::largest_observed(tracker));
+ EXPECT_EQ(3, EntropyTrackerPeer::packets_entropy_size(tracker));
+
+ EXPECT_EQ(7 ^ 17, tracker.EntropyHash(5));
+ EXPECT_EQ(7 ^ 17 ^ 23, tracker.EntropyHash(6));
+ EXPECT_EQ(7 ^ 17 ^ 23 ^ 42, tracker.EntropyHash(9));
+
+ // Inform the tracker about value of the hash at a known location.
+ tracker.SetCumulativeEntropyUpTo(6, 1);
+ EXPECT_EQ(7u, EntropyTrackerPeer::first_gap(tracker));
+ EXPECT_EQ(9u, EntropyTrackerPeer::largest_observed(tracker));
+ EXPECT_EQ(1, EntropyTrackerPeer::packets_entropy_size(tracker));
+
+ EXPECT_EQ(1 ^ 23 ^ 42, tracker.EntropyHash(9));
+
+ // Inform the tracker about value of the hash at the last location.
+ tracker.SetCumulativeEntropyUpTo(9, 21);
+ EXPECT_EQ(10u, EntropyTrackerPeer::first_gap(tracker));
+ EXPECT_EQ(9u, EntropyTrackerPeer::largest_observed(tracker));
+ EXPECT_EQ(0, EntropyTrackerPeer::packets_entropy_size(tracker));
+
+ EXPECT_EQ(42 ^ 21, tracker.EntropyHash(9));
+}
+
class QuicReceivedPacketManagerTest : public ::testing::Test {
protected:
QuicReceivedPacketManagerTest() : received_manager_(kTCP, &stats_) { }
@@ -63,6 +227,7 @@ TEST_F(QuicReceivedPacketManagerTest, ReceivedPacketEntropyHash) {
hash ^= entropies[index].second;
++index;
}
+ if (i < 3) continue;
EXPECT_EQ(hash, received_manager_.EntropyHash(i));
}
// Reorder by 5 when 2 is received after 7.
@@ -83,34 +248,34 @@ TEST_F(QuicReceivedPacketManagerTest, EntropyHashAboveLargestObserved) {
EXPECT_EQ(0, received_manager_.EntropyHash(3));
}
-TEST_F(QuicReceivedPacketManagerTest, RecalculateEntropyHash) {
+TEST_F(QuicReceivedPacketManagerTest, SetCumulativeEntropyUpTo) {
vector<pair<QuicPacketSequenceNumber, QuicPacketEntropyHash> > entropies;
entropies.push_back(make_pair(1, 12));
entropies.push_back(make_pair(2, 1));
entropies.push_back(make_pair(3, 33));
entropies.push_back(make_pair(4, 3));
- entropies.push_back(make_pair(5, 34));
- entropies.push_back(make_pair(6, 29));
+ entropies.push_back(make_pair(6, 34));
+ entropies.push_back(make_pair(7, 29));
QuicPacketEntropyHash entropy_hash = 0;
for (size_t i = 0; i < entropies.size(); ++i) {
RecordPacketReceipt(entropies[i].first, entropies[i].second);
entropy_hash ^= entropies[i].second;
}
- EXPECT_EQ(entropy_hash, received_manager_.EntropyHash(6));
+ EXPECT_EQ(entropy_hash, received_manager_.EntropyHash(7));
- // Now set the entropy hash up to 4 to be 100.
+ // Now set the entropy hash up to 5 to be 100.
entropy_hash ^= 100;
- for (size_t i = 0; i < 3; ++i) {
+ for (size_t i = 0; i < 4; ++i) {
entropy_hash ^= entropies[i].second;
}
- QuicReceivedPacketManagerPeer::RecalculateEntropyHash(
- &received_manager_, 4, 100);
- EXPECT_EQ(entropy_hash, received_manager_.EntropyHash(6));
+ QuicReceivedPacketManagerPeer::SetCumulativeEntropyUpTo(
+ &received_manager_, 5, 100);
+ EXPECT_EQ(entropy_hash, received_manager_.EntropyHash(7));
- QuicReceivedPacketManagerPeer::RecalculateEntropyHash(
+ QuicReceivedPacketManagerPeer::SetCumulativeEntropyUpTo(
&received_manager_, 1, 50);
- EXPECT_EQ(entropy_hash, received_manager_.EntropyHash(6));
+ EXPECT_EQ(entropy_hash, received_manager_.EntropyHash(7));
// No reordering.
EXPECT_EQ(0u, stats_.max_sequence_reordering);
diff --git a/net/quic/quic_sent_packet_manager.cc b/net/quic/quic_sent_packet_manager.cc
index f2eb6d3..f73bfd3 100644
--- a/net/quic/quic_sent_packet_manager.cc
+++ b/net/quic/quic_sent_packet_manager.cc
@@ -132,6 +132,13 @@ void QuicSentPacketManager::OnIncomingAck(
InvokeLossDetection(ack_receive_time);
MaybeInvokeCongestionEvent(largest_observed_acked, bytes_in_flight);
+ // If we have received a truncated ack, then we need to clear out some
+ // previous transmissions to allow the peer to actually ACK new packets.
+ if (received_info.is_truncated) {
+ unacked_packets_.ClearPreviousRetransmissions(
+ received_info.missing_packets.size() / 2);
+ }
+
// Anytime we are making forward progress and have a new RTT estimate, reset
// the backoff counters.
if (largest_observed_acked) {
@@ -153,11 +160,6 @@ void QuicSentPacketManager::MaybeInvokeCongestionEvent(
}
}
-void QuicSentPacketManager::DiscardUnackedPacket(
- QuicPacketSequenceNumber sequence_number) {
- MarkPacketHandled(sequence_number, QuicTime::Delta::Zero());
-}
-
void QuicSentPacketManager::HandleAckForSentPackets(
const ReceivedPacketInfo& received_info) {
// Go through the packets we have not received an ack for and see if this
@@ -176,7 +178,8 @@ void QuicSentPacketManager::HandleAckForSentPackets(
// 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 = MarkPacketHandled(sequence_number, delta_largest_observed);
+ ++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
@@ -210,14 +213,6 @@ void QuicSentPacketManager::HandleAckForSentPackets(
revived_it != received_info.revived_packets.end(); ++revived_it) {
MarkPacketRevived(*revived_it, delta_largest_observed);
}
-
- // If we have received a truncated ack, then we need to
- // clear out some previous transmissions to allow the peer
- // to actually ACK new packets.
- if (received_info.is_truncated) {
- unacked_packets_.ClearPreviousRetransmissions(
- received_info.missing_packets.size() / 2);
- }
}
bool QuicSentPacketManager::HasRetransmittableFrames(
@@ -264,14 +259,8 @@ void QuicSentPacketManager::NeuterUnencryptedPackets() {
// they are not retransmitted or considered lost from a congestion control
// perspective.
pending_retransmissions_.erase(it->first);
+ unacked_packets_.RemoveRetransmittibility(it->first, largest_observed_);
unacked_packets_.SetNotPending(it->first);
- // TODO(ianswett): Clean this up so UnackedPacketMap maintains the correct
- // invariants between the various transmissions for NeuterPacket.
- SequenceNumberSet all_transmissions = *it->second.all_transmissions;
- for (SequenceNumberSet::const_iterator all_it = all_transmissions.begin();
- all_it != all_transmissions.end(); ++all_it) {
- unacked_packets_.NeuterPacket(*all_it);
- }
}
}
}
@@ -317,7 +306,7 @@ QuicSentPacketManager::PendingRetransmission
++it;
} while (it != pending_retransmissions_.end());
}
- DCHECK(unacked_packets_.IsUnacked(sequence_number));
+ DCHECK(unacked_packets_.IsUnacked(sequence_number)) << sequence_number;
const TransmissionInfo& transmission_info =
unacked_packets_.GetTransmissionInfo(sequence_number);
DCHECK(transmission_info.retransmittable_frames);
@@ -334,24 +323,23 @@ void QuicSentPacketManager::MarkPacketRevived(
if (!unacked_packets_.IsUnacked(sequence_number)) {
return;
}
- // This packet has been revived at the receiver. If we were going to
- // retransmit it, do not retransmit it anymore.
- pending_retransmissions_.erase(sequence_number);
const TransmissionInfo& transmission_info =
unacked_packets_.GetTransmissionInfo(sequence_number);
+ QuicPacketSequenceNumber newest_transmission =
+ *transmission_info.all_transmissions->rbegin();
+ // This packet has been revived at the receiver. If we were going to
+ // retransmit it, do not retransmit it anymore.
+ pending_retransmissions_.erase(newest_transmission);
+
// The AckNotifierManager needs to be notified for revived packets,
// since it indicates the packet arrived from the appliction's perspective.
if (transmission_info.retransmittable_frames) {
ack_notifier_manager_.OnPacketAcked(
- sequence_number, delta_largest_observed);
+ newest_transmission, delta_largest_observed);
}
- if (!transmission_info.pending) {
- unacked_packets_.RemovePacket(sequence_number);
- } else {
- unacked_packets_.NeuterPacket(sequence_number);
- }
+ unacked_packets_.RemoveRetransmittibility(sequence_number, largest_observed_);
}
QuicUnackedPacketMap::const_iterator QuicSentPacketManager::MarkPacketHandled(
@@ -363,15 +351,9 @@ QuicUnackedPacketMap::const_iterator QuicSentPacketManager::MarkPacketHandled(
}
const TransmissionInfo& transmission_info =
unacked_packets_.GetTransmissionInfo(sequence_number);
- // If this packet is pending, remove it.
- if (transmission_info.pending) {
- unacked_packets_.SetNotPending(sequence_number);
- }
- SequenceNumberSet all_transmissions = *transmission_info.all_transmissions;
- SequenceNumberSet::reverse_iterator all_transmissions_it =
- all_transmissions.rbegin();
- QuicPacketSequenceNumber newest_transmission = *all_transmissions_it;
+ QuicPacketSequenceNumber newest_transmission =
+ *transmission_info.all_transmissions->rbegin();
// Remove the most recent packet, if it is pending retransmission.
pending_retransmissions_.erase(newest_transmission);
@@ -389,31 +371,20 @@ QuicUnackedPacketMap::const_iterator QuicSentPacketManager::MarkPacketHandled(
ack_notifier_manager_.OnPacketAcked(newest_transmission,
delta_largest_observed);
+ // If it's a crypto handshake packet, discard it and all retransmissions,
+ // since they won't be acked now that one has been processed.
// TODO(ianswett): Instead of handling all crypto packets in a special way,
// only handle NULL encrypted packets in a special way.
- bool has_crypto_handshake = HasCryptoHandshake(
- unacked_packets_.GetTransmissionInfo(newest_transmission));
- while (all_transmissions_it != all_transmissions.rend()) {
- QuicPacketSequenceNumber previous_transmission = *all_transmissions_it;
- const TransmissionInfo& transmission_info =
- unacked_packets_.GetTransmissionInfo(previous_transmission);
- DCHECK(!ContainsKey(pending_retransmissions_, previous_transmission));
- if (has_crypto_handshake) {
- // If it's a crypto handshake packet, discard it and all retransmissions,
- // since they won't be acked now that one has been processed.
- unacked_packets_.SetNotPending(previous_transmission);
- }
- if (!transmission_info.pending) {
- unacked_packets_.RemovePacket(previous_transmission);
- } else {
- unacked_packets_.NeuterPacket(previous_transmission);
- }
- ++all_transmissions_it;
+ if (HasCryptoHandshake(
+ unacked_packets_.GetTransmissionInfo(newest_transmission))) {
+ unacked_packets_.SetNotPending(newest_transmission);
}
+ unacked_packets_.SetNotPending(sequence_number);
+ unacked_packets_.RemoveRetransmittibility(sequence_number, largest_observed_);
QuicUnackedPacketMap::const_iterator next_unacked = unacked_packets_.begin();
while (next_unacked != unacked_packets_.end() &&
- next_unacked->first < sequence_number) {
+ next_unacked->first <= sequence_number) {
++next_unacked;
}
return next_unacked;
@@ -619,7 +590,9 @@ void QuicSentPacketManager::InvokeLossDetection(QuicTime time) {
// a packet whose previous transmission has been acked, a packet that has
// been TLP retransmitted, or an FEC packet.
unacked_packets_.SetNotPending(sequence_number);
- unacked_packets_.RemovePacket(sequence_number);
+ if (QuicUnackedPacketMap::IsForRttOnly(transmission_info)) {
+ unacked_packets_.RemoveRttOnlyPacket(sequence_number);
+ }
}
}
}
diff --git a/net/quic/quic_sent_packet_manager.h b/net/quic/quic_sent_packet_manager.h
index cca7f4c..0c6c407 100644
--- a/net/quic/quic_sent_packet_manager.h
+++ b/net/quic/quic_sent_packet_manager.h
@@ -82,12 +82,6 @@ class NET_EXPORT_PRIVATE QuicSentPacketManager {
void OnIncomingAck(const ReceivedPacketInfo& received_info,
QuicTime ack_receive_time);
- // Discards any information for the packet corresponding to |sequence_number|.
- // If this packet has been retransmitted, information on those packets
- // will be discarded as well. Also discards it from the congestion window if
- // it is present.
- void DiscardUnackedPacket(QuicPacketSequenceNumber sequence_number);
-
// Returns true if the non-FEC packet |sequence_number| is unacked.
bool IsUnacked(QuicPacketSequenceNumber sequence_number) const;
diff --git a/net/quic/quic_sent_packet_manager_test.cc b/net/quic/quic_sent_packet_manager_test.cc
index aef7c10..f3a9f30 100644
--- a/net/quic/quic_sent_packet_manager_test.cc
+++ b/net/quic/quic_sent_packet_manager_test.cc
@@ -444,7 +444,7 @@ TEST_F(QuicSentPacketManagerTest, RetransmitTwiceThenAckFirst) {
EXPECT_TRUE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_));
VerifyRetransmittablePackets(NULL, 0);
- // Ensure packet 2 is lost when 4 and 5 are sent and acked.
+ // Ensure packet 2 is lost when 4 is sent and 3 and 4 are acked.
SendDataPacket(4);
received_info.largest_observed = 4;
received_info.missing_packets.insert(2);
@@ -616,14 +616,6 @@ TEST_F(QuicSentPacketManagerTest, GetLeastUnackedSentPacketUnackedFec) {
EXPECT_EQ(1u, manager_.GetLeastUnackedSentPacket());
}
-TEST_F(QuicSentPacketManagerTest, GetLeastUnackedSentPacketDiscardUnacked) {
- SerializedPacket serialized_packet(CreateDataPacket(1));
-
- manager_.OnSerializedPacket(serialized_packet);
- manager_.DiscardUnackedPacket(1u);
- EXPECT_EQ(0u, manager_.GetLeastUnackedSentPacket());
-}
-
TEST_F(QuicSentPacketManagerTest, GetLeastUnackedPacketAndDiscard) {
VerifyUnackedPackets(NULL, 0);
@@ -643,19 +635,12 @@ TEST_F(QuicSentPacketManagerTest, GetLeastUnackedPacketAndDiscard) {
VerifyUnackedPackets(unacked, arraysize(unacked));
VerifyRetransmittablePackets(NULL, 0);
- manager_.DiscardUnackedPacket(1);
- EXPECT_EQ(2u, manager_.GetLeastUnackedSentPacket());
-
// Ack 2, which has never been sent, so there's no rtt update.
ReceivedPacketInfo received_info;
received_info.largest_observed = 2;
manager_.OnIncomingAck(received_info, clock_.Now());
EXPECT_EQ(3u, manager_.GetLeastUnackedSentPacket());
-
- // Discard the 3rd packet and ensure there are no FEC packets.
- manager_.DiscardUnackedPacket(3);
- EXPECT_FALSE(manager_.HasUnackedPackets());
}
TEST_F(QuicSentPacketManagerTest, GetSentTime) {
diff --git a/net/quic/quic_session_test.cc b/net/quic/quic_session_test.cc
index 511e345..34025de 100644
--- a/net/quic/quic_session_test.cc
+++ b/net/quic/quic_session_test.cc
@@ -29,11 +29,11 @@
using base::hash_map;
using std::set;
using std::vector;
-using testing::_;
using testing::InSequence;
using testing::InvokeWithoutArgs;
using testing::Return;
using testing::StrictMock;
+using testing::_;
namespace net {
namespace test {
@@ -273,8 +273,8 @@ TEST_P(QuicSessionTest, IsClosedStreamLocallyCreated) {
}
TEST_P(QuicSessionTest, IsClosedStreamPeerCreated) {
- QuicStreamId stream_id1 = 5;
- QuicStreamId stream_id2 = stream_id1 + 2;
+ QuicStreamId stream_id1 = kClientDataStreamId1;
+ QuicStreamId stream_id2 = kClientDataStreamId2;
QuicDataStream* stream1 = session_.GetIncomingDataStream(stream_id1);
QuicDataStreamPeer::SetHeadersDecompressed(stream1, true);
QuicDataStream* stream2 = session_.GetIncomingDataStream(stream_id2);
@@ -294,7 +294,7 @@ TEST_P(QuicSessionTest, IsClosedStreamPeerCreated) {
}
TEST_P(QuicSessionTest, StreamIdTooLarge) {
- QuicStreamId stream_id = 5;
+ QuicStreamId stream_id = kClientDataStreamId1;
session_.GetIncomingDataStream(stream_id);
EXPECT_CALL(*connection_, SendConnectionClose(QUIC_INVALID_STREAM_ID));
session_.GetIncomingDataStream(stream_id + kMaxStreamIdDelta + 2);
@@ -568,7 +568,7 @@ TEST_P(QuicSessionTest, IncreasedTimeoutAfterCryptoHandshake) {
}
TEST_P(QuicSessionTest, RstStreamBeforeHeadersDecompressed) {
- QuicStreamId stream_id1 = 5;
+ QuicStreamId stream_id1 = kClientDataStreamId1;
// Send two bytes of payload.
QuicStreamFrame data1(stream_id1, false, 0, MakeIOVector("HT"));
vector<QuicStreamFrame> frames;
@@ -589,8 +589,7 @@ TEST_P(QuicSessionTest, MultipleRstStreamsCauseSingleConnectionClose) {
// multiple connection close frames.
// Create valid stream.
- const QuicStreamId kStreamId = 5;
- QuicStreamFrame data1(kStreamId, false, 0, MakeIOVector("HT"));
+ QuicStreamFrame data1(kClientDataStreamId1, false, 0, MakeIOVector("HT"));
vector<QuicStreamFrame> frames;
frames.push_back(data1);
session_.OnStreamFrames(frames);
diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc
index 27903e9..8189989 100644
--- a/net/quic/quic_stream_factory_test.cc
+++ b/net/quic/quic_stream_factory_test.cc
@@ -169,7 +169,7 @@ class QuicStreamFactoryTest : public ::testing::TestWithParam<QuicVersion> {
}
scoped_ptr<QuicEncryptedPacket> ConstructRstPacket() {
- QuicStreamId stream_id = 5;
+ QuicStreamId stream_id = kClientDataStreamId1;
return maker_.MakeRstPacket(
1, true, stream_id,
AdjustErrorForVersion(QUIC_RST_FLOW_CONTROL_ACCOUNTING, GetParam()));
@@ -663,7 +663,7 @@ TEST_P(QuicStreamFactoryTest, MaxOpenStream) {
MockRead reads[] = {
MockRead(ASYNC, OK, 0) // EOF
};
- QuicStreamId stream_id = 5;
+ QuicStreamId stream_id = kClientDataStreamId1;
scoped_ptr<QuicEncryptedPacket> rst(
maker_.MakeRstPacket(1, true, stream_id, QUIC_STREAM_CANCELLED));
MockWrite writes[] = {
diff --git a/net/quic/quic_unacked_packet_map.cc b/net/quic/quic_unacked_packet_map.cc
index a8fe3b5..92c24f7 100644
--- a/net/quic/quic_unacked_packet_map.cc
+++ b/net/quic/quic_unacked_packet_map.cc
@@ -90,8 +90,11 @@ void QuicUnackedPacketMap::ClearPreviousRetransmissions(size_t num_to_clear) {
break;
}
+ it->second.all_transmissions->erase(sequence_number);
+ LOG_IF(DFATAL, it->second.all_transmissions->empty())
+ << "Previous retransmissions must have a newer transmission.";
++it;
- RemovePacket(sequence_number);
+ unacked_packets_.erase(sequence_number);
--num_to_clear;
}
}
@@ -119,38 +122,36 @@ void QuicUnackedPacketMap::NackPacket(QuicPacketSequenceNumber sequence_number,
it->second.nack_count = max(min_nacks, it->second.nack_count);
}
-void QuicUnackedPacketMap::RemovePacket(
- QuicPacketSequenceNumber sequence_number) {
+void QuicUnackedPacketMap::RemoveRetransmittibility(
+ QuicPacketSequenceNumber sequence_number,
+ QuicPacketSequenceNumber largest_observed) {
UnackedPacketMap::iterator it = unacked_packets_.find(sequence_number);
if (it == unacked_packets_.end()) {
LOG(DFATAL) << "packet is not unacked: " << sequence_number;
return;
}
- TransmissionInfo* transmission_info = &it->second;
- DCHECK(!transmission_info->pending);
- MaybeRemoveRetransmittableFrames(transmission_info);
- transmission_info->all_transmissions->erase(sequence_number);
- if (transmission_info->all_transmissions->empty()) {
- delete transmission_info->all_transmissions;
+ 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
+ // frames associated with this packet.
+ for (SequenceNumberSet::reverse_iterator it = all_transmissions->rbegin();
+ it != all_transmissions->rend(); ++it) {
+ TransmissionInfo* transmission_info = FindOrNull(unacked_packets_, *it);
+ if (transmission_info == NULL) {
+ LOG(DFATAL) << "All transmissions in all_transmissions must be present "
+ << "in the unacked packet map.";
+ continue;
+ }
+ MaybeRemoveRetransmittableFrames(transmission_info);
+ if (sequence_number <= largest_observed && !transmission_info->pending) {
+ unacked_packets_.erase(*it);
+ } else {
+ transmission_info->all_transmissions = new SequenceNumberSet();
+ transmission_info->all_transmissions->insert(*it);
+ }
}
- unacked_packets_.erase(it);
-}
-void QuicUnackedPacketMap::NeuterPacket(
- 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;
- }
- TransmissionInfo* transmission_info = &it->second;
- // TODO(ianswett): Ensure packets are pending before neutering them.
- MaybeRemoveRetransmittableFrames(transmission_info);
- if (transmission_info->all_transmissions->size() > 1) {
- transmission_info->all_transmissions->erase(sequence_number);
- transmission_info->all_transmissions = new SequenceNumberSet();
- transmission_info->all_transmissions->insert(sequence_number);
- }
+ delete all_transmissions;
}
void QuicUnackedPacketMap::MaybeRemoveRetransmittableFrames(
@@ -165,6 +166,21 @@ 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;
+ }
+ 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) {
diff --git a/net/quic/quic_unacked_packet_map.h b/net/quic/quic_unacked_packet_map.h
index 12a96a2..4861595 100644
--- a/net/quic/quic_unacked_packet_map.h
+++ b/net/quic/quic_unacked_packet_map.h
@@ -110,14 +110,20 @@ class NET_EXPORT_PRIVATE QuicUnackedPacketMap {
// Returns true if there are any pending crypto packets.
bool HasPendingCryptoPackets() const;
- // Removes entries from the unacked packet map, and deletes
- // the retransmittable frames associated with the packet.
- // Does not remove any previous or subsequent transmissions of this packet.
- void RemovePacket(QuicPacketSequenceNumber sequence_number);
-
- // Neuters the specified packet. Deletes any retransmittable
- // frames, and sets all_transmissions to only include itself.
- void NeuterPacket(QuicPacketSequenceNumber sequence_number);
+ // 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 RemoveRetransmittibility(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
diff --git a/net/quic/quic_write_blocked_list_test.cc b/net/quic/quic_write_blocked_list_test.cc
index 1643bc3..0633f63 100644
--- a/net/quic/quic_write_blocked_list_test.cc
+++ b/net/quic/quic_write_blocked_list_test.cc
@@ -4,6 +4,7 @@
//
#include "net/quic/quic_write_blocked_list.h"
+#include "net/quic/test_tools/quic_test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace net {
@@ -93,7 +94,7 @@ TEST(QuicWriteBlockedListTest, NoDuplicateEntries) {
// Try to add a stream to the write blocked list multiple times at the same
// priority.
- const QuicStreamId kBlockedId = 5;
+ const QuicStreamId kBlockedId = kClientDataStreamId1;
write_blocked_list.PushBack(kBlockedId,
QuicWriteBlockedList::kHighestPriority);
write_blocked_list.PushBack(kBlockedId,
diff --git a/net/quic/reliable_quic_stream_test.cc b/net/quic/reliable_quic_stream_test.cc
index 48e8616..935554f 100644
--- a/net/quic/reliable_quic_stream_test.cc
+++ b/net/quic/reliable_quic_stream_test.cc
@@ -37,7 +37,6 @@ namespace {
const char kData1[] = "FooAndBar";
const char kData2[] = "EepAndBaz";
const size_t kDataLen = 9;
-const QuicStreamId kStreamId = 3;
const bool kIsServer = true;
const bool kShouldProcessData = true;
@@ -119,9 +118,7 @@ class ReliableQuicStreamTest : public ::testing::TestWithParam<bool> {
QuicConfigPeer::SetReceivedInitialFlowControlWindow(
session_->config(), initial_flow_control_window_bytes_);
- stream_.reset(new TestStream(kStreamId, session_.get(),
- stream_should_process_data));
- stream2_.reset(new TestStream(kStreamId + 2, session_.get(),
+ stream_.reset(new TestStream(kHeadersStreamId, session_.get(),
stream_should_process_data));
write_blocked_list_ =
QuicSessionPeer::GetWriteblockedStreams(session_.get());
@@ -143,7 +140,6 @@ class ReliableQuicStreamTest : public ::testing::TestWithParam<bool> {
MockConnection* connection_;
scoped_ptr<MockSession> session_;
scoped_ptr<TestStream> stream_;
- scoped_ptr<TestStream> stream2_;
SpdyHeaderBlock headers_;
QuicWriteBlockedList* write_blocked_list_;
uint32 initial_flow_control_window_bytes_;
@@ -156,10 +152,10 @@ 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);
- EXPECT_CALL(*session_, WritevData(kStreamId, _, _, _, _)).WillOnce(
- Return(QuicConsumedData(kDataLen, true)));
+ connection_->version(), PACKET_8BYTE_CONNECTION_ID,
+ !kIncludeVersion, PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP);
+ EXPECT_CALL(*session_, WritevData(kHeadersStreamId, _, _, _, _))
+ .WillOnce(Return(QuicConsumedData(kDataLen, true)));
stream_->WriteOrBufferData(kData1, false, NULL);
EXPECT_FALSE(HasWriteBlockedStreams());
}
@@ -178,8 +174,8 @@ TEST_F(ReliableQuicStreamTest, BlockIfOnlySomeDataConsumed) {
// Write some data and no fin. If we consume some but not all of the data,
// we should be write blocked a not all the data was consumed.
- EXPECT_CALL(*session_, WritevData(kStreamId, _, _, _, _)).WillOnce(
- Return(QuicConsumedData(1, false)));
+ EXPECT_CALL(*session_, WritevData(kHeadersStreamId, _, _, _, _))
+ .WillOnce(Return(QuicConsumedData(1, false)));
stream_->WriteOrBufferData(StringPiece(kData1, 2), false, NULL);
ASSERT_EQ(1u, write_blocked_list_->NumBlockedStreams());
}
@@ -191,8 +187,8 @@ TEST_F(ReliableQuicStreamTest, BlockIfFinNotConsumedWithData) {
// we should be write blocked because the fin was not consumed.
// (This should never actually happen as the fin should be sent out with the
// last data)
- EXPECT_CALL(*session_, WritevData(kStreamId, _, _, _, _)).WillOnce(
- Return(QuicConsumedData(2, false)));
+ EXPECT_CALL(*session_, WritevData(kHeadersStreamId, _, _, _, _))
+ .WillOnce(Return(QuicConsumedData(2, false)));
stream_->WriteOrBufferData(StringPiece(kData1, 2), true, NULL);
ASSERT_EQ(1u, write_blocked_list_->NumBlockedStreams());
}
@@ -202,8 +198,8 @@ TEST_F(ReliableQuicStreamTest, BlockIfSoloFinNotConsumed) {
// Write no data and a fin. If we consume nothing we should be write blocked,
// as the fin was not consumed.
- EXPECT_CALL(*session_, WritevData(kStreamId, _, _, _, _)).WillOnce(
- Return(QuicConsumedData(0, false)));
+ EXPECT_CALL(*session_, WritevData(kHeadersStreamId, _, _, _, _))
+ .WillOnce(Return(QuicConsumedData(0, false)));
stream_->WriteOrBufferData(StringPiece(), true, NULL);
ASSERT_EQ(1u, write_blocked_list_->NumBlockedStreams());
}
@@ -260,8 +256,8 @@ TEST_F(ReliableQuicStreamTest, RstAlwaysSentIfNoFinSent) {
EXPECT_FALSE(rst_sent());
// Write some data, with no FIN.
- EXPECT_CALL(*session_, WritevData(kStreamId, _, _, _, _)).WillOnce(
- Return(QuicConsumedData(1, false)));
+ EXPECT_CALL(*session_, WritevData(kHeadersStreamId, _, _, _, _))
+ .WillOnce(Return(QuicConsumedData(1, false)));
stream_->WriteOrBufferData(StringPiece(kData1, 1), false, NULL);
EXPECT_FALSE(fin_sent());
EXPECT_FALSE(rst_sent());
@@ -283,8 +279,8 @@ TEST_F(ReliableQuicStreamTest, RstNotSentIfFinSent) {
EXPECT_FALSE(rst_sent());
// Write some data, with FIN.
- EXPECT_CALL(*session_, WritevData(kStreamId, _, _, _, _)).WillOnce(
- Return(QuicConsumedData(1, true)));
+ EXPECT_CALL(*session_, WritevData(kHeadersStreamId, _, _, _, _))
+ .WillOnce(Return(QuicConsumedData(1, true)));
stream_->WriteOrBufferData(StringPiece(kData1, 1), true, NULL);
EXPECT_TRUE(fin_sent());
EXPECT_FALSE(rst_sent());
@@ -404,27 +400,27 @@ TEST_F(ReliableQuicStreamTest, WriteOrBufferDataWithQuicAckNotifier) {
scoped_refptr<QuicAckNotifier::DelegateInterface> proxy_delegate;
- EXPECT_CALL(*session_, WritevData(kStreamId, _, _, _, _)).WillOnce(DoAll(
- WithArgs<4>(Invoke(CreateFunctor(
- &SaveProxyAckNotifierDelegate, &proxy_delegate))),
- Return(QuicConsumedData(kFirstWriteSize, false))));
+ EXPECT_CALL(*session_, WritevData(kHeadersStreamId, _, _, _, _))
+ .WillOnce(DoAll(WithArgs<4>(Invoke(CreateFunctor(
+ &SaveProxyAckNotifierDelegate, &proxy_delegate))),
+ Return(QuicConsumedData(kFirstWriteSize, false))));
stream_->WriteOrBufferData(kData, false, delegate.get());
EXPECT_TRUE(HasWriteBlockedStreams());
- EXPECT_CALL(*session_, WritevData(kStreamId, _, _, _, proxy_delegate.get())).
- WillOnce(
- Return(QuicConsumedData(kSecondWriteSize, false)));
+ EXPECT_CALL(*session_,
+ WritevData(kHeadersStreamId, _, _, _, proxy_delegate.get()))
+ .WillOnce(Return(QuicConsumedData(kSecondWriteSize, false)));
stream_->OnCanWrite();
// No ack expected for an empty write.
- EXPECT_CALL(*session_, WritevData(kStreamId, _, _, _, proxy_delegate.get())).
- WillOnce(
- Return(QuicConsumedData(0, false)));
+ EXPECT_CALL(*session_,
+ WritevData(kHeadersStreamId, _, _, _, proxy_delegate.get()))
+ .WillOnce(Return(QuicConsumedData(0, false)));
stream_->OnCanWrite();
- EXPECT_CALL(*session_, WritevData(kStreamId, _, _, _, proxy_delegate.get())).
- WillOnce(
- Return(QuicConsumedData(kLastWriteSize, false)));
+ EXPECT_CALL(*session_,
+ WritevData(kHeadersStreamId, _, _, _, proxy_delegate.get()))
+ .WillOnce(Return(QuicConsumedData(kLastWriteSize, false)));
stream_->OnCanWrite();
// There were two writes, so OnAckNotification is not propagated
@@ -459,10 +455,10 @@ TEST_F(ReliableQuicStreamTest, WriteOrBufferDataAckNotificationBeforeFlush) {
scoped_refptr<QuicAckNotifier::DelegateInterface> proxy_delegate;
- EXPECT_CALL(*session_, WritevData(kStreamId, _, _, _, _)).WillOnce(DoAll(
- WithArgs<4>(Invoke(CreateFunctor(
- &SaveProxyAckNotifierDelegate, &proxy_delegate))),
- Return(QuicConsumedData(kInitialWriteSize, false))));
+ EXPECT_CALL(*session_, WritevData(kHeadersStreamId, _, _, _, _))
+ .WillOnce(DoAll(WithArgs<4>(Invoke(CreateFunctor(
+ &SaveProxyAckNotifierDelegate, &proxy_delegate))),
+ Return(QuicConsumedData(kInitialWriteSize, false))));
stream_->WriteOrBufferData(kData, false, delegate.get());
EXPECT_TRUE(HasWriteBlockedStreams());
@@ -470,10 +466,10 @@ TEST_F(ReliableQuicStreamTest, WriteOrBufferDataAckNotificationBeforeFlush) {
proxy_delegate->OnAckNotification(1, 2, 3, 4, zero_);
proxy_delegate = NULL;
- EXPECT_CALL(*session_, WritevData(kStreamId, _, _, _, _)).WillOnce(DoAll(
- WithArgs<4>(Invoke(CreateFunctor(
- &SaveProxyAckNotifierDelegate, &proxy_delegate))),
- Return(QuicConsumedData(kDataSize - kInitialWriteSize, false))));
+ EXPECT_CALL(*session_, WritevData(kHeadersStreamId, _, _, _, _)).WillOnce(
+ DoAll(WithArgs<4>(Invoke(CreateFunctor(
+ &SaveProxyAckNotifierDelegate, &proxy_delegate))),
+ Return(QuicConsumedData(kDataSize - kInitialWriteSize, false))));
stream_->OnCanWrite();
// Handle the ack for the second write.
@@ -490,10 +486,10 @@ TEST_F(ReliableQuicStreamTest, WriteAndBufferDataWithAckNotiferNoBuffer) {
scoped_refptr<QuicAckNotifier::DelegateInterface> proxy_delegate;
- EXPECT_CALL(*session_, WritevData(kStreamId, _, _, _, _)).WillOnce(DoAll(
- WithArgs<4>(Invoke(CreateFunctor(
- &SaveProxyAckNotifierDelegate, &proxy_delegate))),
- Return(QuicConsumedData(kDataLen, true))));
+ EXPECT_CALL(*session_, WritevData(kHeadersStreamId, _, _, _, _))
+ .WillOnce(DoAll(WithArgs<4>(Invoke(CreateFunctor(
+ &SaveProxyAckNotifierDelegate, &proxy_delegate))),
+ Return(QuicConsumedData(kDataLen, true))));
stream_->WriteOrBufferData(kData1, true, delegate.get());
EXPECT_FALSE(HasWriteBlockedStreams());
@@ -511,15 +507,15 @@ TEST_F(ReliableQuicStreamTest, BufferOnWriteAndBufferDataWithAckNotifer) {
scoped_refptr<QuicAckNotifier::DelegateInterface> proxy_delegate;
- EXPECT_CALL(*session_, WritevData(kStreamId, _, _, _, _)).WillOnce(
- Return(QuicConsumedData(0, false)));
+ EXPECT_CALL(*session_, WritevData(kHeadersStreamId, _, _, _, _))
+ .WillOnce(Return(QuicConsumedData(0, false)));
stream_->WriteOrBufferData(kData1, true, delegate.get());
EXPECT_TRUE(HasWriteBlockedStreams());
- EXPECT_CALL(*session_, WritevData(kStreamId, _, _, _, _)).WillOnce(DoAll(
- WithArgs<4>(Invoke(CreateFunctor(
- &SaveProxyAckNotifierDelegate, &proxy_delegate))),
- Return(QuicConsumedData(kDataLen, true))));
+ EXPECT_CALL(*session_, WritevData(kHeadersStreamId, _, _, _, _))
+ .WillOnce(DoAll(WithArgs<4>(Invoke(CreateFunctor(
+ &SaveProxyAckNotifierDelegate, &proxy_delegate))),
+ Return(QuicConsumedData(kDataLen, true))));
stream_->OnCanWrite();
// Handle the ack.
@@ -537,17 +533,17 @@ TEST_F(ReliableQuicStreamTest, WriteAndBufferDataWithAckNotiferOnlyFinRemains) {
scoped_refptr<QuicAckNotifier::DelegateInterface> proxy_delegate;
- EXPECT_CALL(*session_, WritevData(kStreamId, _, _, _, _)).WillOnce(DoAll(
- WithArgs<4>(Invoke(CreateFunctor(
- &SaveProxyAckNotifierDelegate, &proxy_delegate))),
- Return(QuicConsumedData(kDataLen, false))));
+ EXPECT_CALL(*session_, WritevData(kHeadersStreamId, _, _, _, _))
+ .WillOnce(DoAll(WithArgs<4>(Invoke(CreateFunctor(
+ &SaveProxyAckNotifierDelegate, &proxy_delegate))),
+ Return(QuicConsumedData(kDataLen, false))));
stream_->WriteOrBufferData(kData1, true, delegate.get());
EXPECT_TRUE(HasWriteBlockedStreams());
- EXPECT_CALL(*session_, WritevData(kStreamId, _, _, _, _)).WillOnce(DoAll(
- WithArgs<4>(Invoke(CreateFunctor(
- &SaveProxyAckNotifierDelegate, &proxy_delegate))),
- Return(QuicConsumedData(0, true))));
+ EXPECT_CALL(*session_, WritevData(kHeadersStreamId, _, _, _, _))
+ .WillOnce(DoAll(WithArgs<4>(Invoke(CreateFunctor(
+ &SaveProxyAckNotifierDelegate, &proxy_delegate))),
+ Return(QuicConsumedData(0, true))));
stream_->OnCanWrite();
// Handle the acks.
diff --git a/net/quic/test_tools/quic_received_packet_manager_peer.cc b/net/quic/test_tools/quic_received_packet_manager_peer.cc
index d25a209..2faf84e 100644
--- a/net/quic/test_tools/quic_received_packet_manager_peer.cc
+++ b/net/quic/test_tools/quic_received_packet_manager_peer.cc
@@ -11,12 +11,12 @@ namespace net {
namespace test {
// static
-void QuicReceivedPacketManagerPeer::RecalculateEntropyHash(
+void QuicReceivedPacketManagerPeer::SetCumulativeEntropyUpTo(
QuicReceivedPacketManager* received_packet_manager,
QuicPacketSequenceNumber peer_least_unacked,
QuicPacketEntropyHash entropy_hash) {
- received_packet_manager->RecalculateEntropyHash(peer_least_unacked,
- entropy_hash);
+ received_packet_manager->entropy_tracker_.SetCumulativeEntropyUpTo(
+ peer_least_unacked, entropy_hash);
}
// static
diff --git a/net/quic/test_tools/quic_received_packet_manager_peer.h b/net/quic/test_tools/quic_received_packet_manager_peer.h
index 4607a0c..c3cb2d3 100644
--- a/net/quic/test_tools/quic_received_packet_manager_peer.h
+++ b/net/quic/test_tools/quic_received_packet_manager_peer.h
@@ -15,7 +15,7 @@ namespace test {
class QuicReceivedPacketManagerPeer {
public:
- static void RecalculateEntropyHash(
+ static void SetCumulativeEntropyUpTo(
QuicReceivedPacketManager* received_packet_manager,
QuicPacketSequenceNumber peer_least_unacked,
QuicPacketEntropyHash entropy_hash);
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h
index 6901824..3bf2bf3 100644
--- a/net/quic/test_tools/quic_test_utils.h
+++ b/net/quic/test_tools/quic_test_utils.h
@@ -31,6 +31,12 @@ static const QuicConnectionId kTestConnectionId = 42;
static const int kTestPort = 123;
static const uint32 kInitialFlowControlWindowForTest = 32 * 1024; // 32 KB
+// Data stream IDs start at 5: the crypto stream is 1, headers stream is 3.
+static const QuicStreamId kClientDataStreamId1 = 5;
+static const QuicStreamId kClientDataStreamId2 = 7;
+static const QuicStreamId kClientDataStreamId3 = 9;
+static const QuicStreamId kClientDataStreamId4 = 11;
+
// Returns the test peer IP address.
IPAddressNumber TestPeerIPAddress();