summaryrefslogtreecommitdiffstats
path: root/net/quic
diff options
context:
space:
mode:
authorrtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-02-09 10:45:41 +0000
committerrtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-02-09 10:45:41 +0000
commitbdf2d434f0f0f832237257fe837a24cf4514fdaa (patch)
tree03f08727c56150f40d453204b80c08daefd039e7 /net/quic
parent70e263e2fbd7c254a0bf462cd8e409a0102eec10 (diff)
downloadchromium_src-bdf2d434f0f0f832237257fe837a24cf4514fdaa.zip
chromium_src-bdf2d434f0f0f832237257fe837a24cf4514fdaa.tar.gz
chromium_src-bdf2d434f0f0f832237257fe837a24cf4514fdaa.tar.bz2
Land Recent QUIC Changes.
Add a LOG(DFATAL) if the sequence number length is too small to fit the least_unacked delta in a QUIC ack frame. Merge internal change: 61228351 https://codereview.chromium.org/156233004/ Change the types of the arguments to two methods in QuicReceivedPacketManager to be more specific. No behavior changes. Merge internal change: 61215502 https://codereview.chromium.org/157803006/ Add convenience version() method to QuicServerSessionTest. Merge internal change: 61210235 https://codereview.chromium.org/158173002/ Add convenience version() method to QuicSessionTest. Merge internal change: 61206589 https://codereview.chromium.org/158063003/ Fix bug in QuicSentPacketManager::ClearPreviousRetransmissions where pending packets were abandoned instead of being kept unacked so they could be detected to be lost. Merge internal change: 61197933 https://codereview.chromium.org/158073007/ Add QUIC_VERSION_15 to add a revived_packets set to replace the deprecated accumulated_number_of_lost_packets field. FEC requires a way to communicate that the peer doesn't need a packet retransmitted, without indicating it's been received to the send algorithm. Merge internal change: 61159374 https://codereview.chromium.org/157403006/ Rename previous_transmissions to all_transmission in the QUIC unacked packet map. Change all_transmission to include all transmissions of a packet, even if there is only one, instead of becoming null. Merge internal change: 61144526 https://codereview.chromium.org/158153002/ Use an alternative fix for OneShotVisitor of CryptoFramer that doesn't require a done() method. Detect an old-style Public Reset packet by checking for a sequence number length of 6 in public flags. This requires updating the expected error details messages in PublicResetPacket unit tests. Merge internal change: 61152017 https://codereview.chromium.org/153993015/ Refactor QuicSentPacketManager::MarkPacketHandled to simplify implementation in preparation for breaking out the unacked packet map. Also fixes a minor bug in which a packet which has been marked for retransmission would still be retransmitted if a previous transmission was acked. Merge internal change: 61139074 https://codereview.chromium.org/137923007/ Doing early validation of quic config, to change a potential crash-during-serving to a crash-on-startup. Changing a serving crash to a start-up crash. Not flag protected Merge internal change: 61136961 https://codereview.chromium.org/157383006/ Remove parity tracking in FEC groups as part of the migration to QUIC_VERSION_15, which does not need it. Merge internal change: 61136827 https://codereview.chromium.org/157913003/ Comment out flaky test expectation while the root cause is investigated. Merge internal change: 61104556 https://codereview.chromium.org/135933005/ QUIC - clean up changes - fixed during merge with internal source code. Merge internal change: 61045294 https://codereview.chromium.org/157403005/ Fix problems with absolute value function. The standard library provides seven absolute value functions.  From C, there is abs, labs, llabs, fabs, fabsf, and fabsl for the types int, long, long long, double, float and long double.  Due to numeric conversions, these functions can accept arguments of any numeric types, silently converting between types.  C++ libraries has std::abs, which provides overloads for all these types, making it a better choice.  The following problems have been observed, along with their fixes: 1) The wrong sized absolute value was used.  Using abs for a long long would cause a cast to int first, resulting in unexpected values outside of the range (INT_MIN, INT_MAX).  Switch to using std::abs 2) Using the wrong type of absolute value function.  Passing a floating point number to an integer absolute value will cause rounding of values, especially important for values close to zero.  Switch to using std::abs 3) Taking the absolute value of an unsigned value.  This usually has no effect, but may have some effects from casting.  Fixed by removing the absolute value function. 4) Attempting to find the absolute difference between two unsigned values.  These were transformed from abs(a - b) to (a > b ? a - b : b - a).  This ternary expression is usually stored in another variable. 5) Accidentally capturing the conditional such as abs(a - b < threshold).  Moving the parentheses over to fix. 6) Some static_casts were used to, such as from uint32 -> int64, to get a signed value in the absolute value. 7) A few types were changed from unsigned to signed. Merge internal change: 61013787 https://codereview.chromium.org/136123012/ Pass the whole QuicRstStreamFrame to OnStreamReset. Preparation for dealing with byte_offset updates that arrive in the RST frame. (minor) QUIC OnStreamReset now takes QuicRstStreamFrame as argument. Merge internal change: 60995908 https://codereview.chromium.org/142373006/ R=rch@chromium.org Review URL: https://codereview.chromium.org/157803007 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@249994 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/quic')
-rw-r--r--net/quic/congestion_control/cubic.cc4
-rw-r--r--net/quic/congestion_control/cubic_test.cc2
-rw-r--r--net/quic/congestion_control/inter_arrival_overuse_detector.cc4
-rw-r--r--net/quic/congestion_control/tcp_cubic_sender.cc3
-rw-r--r--net/quic/crypto/crypto_framer.cc21
-rw-r--r--net/quic/crypto/strike_register.cc12
-rw-r--r--net/quic/crypto/strike_register.h3
-rw-r--r--net/quic/quic_connection.cc34
-rw-r--r--net/quic/quic_connection_test.cc27
-rw-r--r--net/quic/quic_fec_group.cc18
-rw-r--r--net/quic/quic_fec_group.h8
-rw-r--r--net/quic/quic_fec_group_test.cc15
-rw-r--r--net/quic/quic_framer.cc136
-rw-r--r--net/quic/quic_framer.h2
-rw-r--r--net/quic/quic_framer_test.cc751
-rw-r--r--net/quic/quic_packet_creator.cc21
-rw-r--r--net/quic/quic_packet_creator.h1
-rw-r--r--net/quic/quic_protocol.cc9
-rw-r--r--net/quic/quic_protocol.h10
-rw-r--r--net/quic/quic_received_packet_manager.cc48
-rw-r--r--net/quic/quic_received_packet_manager.h18
-rw-r--r--net/quic/quic_received_packet_manager_test.cc8
-rw-r--r--net/quic/quic_sent_packet_manager.cc275
-rw-r--r--net/quic/quic_sent_packet_manager.h39
-rw-r--r--net/quic/quic_sent_packet_manager_test.cc75
-rw-r--r--net/quic/quic_session.cc2
-rw-r--r--net/quic/quic_session_test.cc22
-rw-r--r--net/quic/reliable_quic_stream.cc4
-rw-r--r--net/quic/reliable_quic_stream.h2
-rw-r--r--net/quic/test_tools/quic_sent_packet_manager_peer.cc2
30 files changed, 1203 insertions, 373 deletions
diff --git a/net/quic/congestion_control/cubic.cc b/net/quic/congestion_control/cubic.cc
index 938faaea..bb21e3c 100644
--- a/net/quic/congestion_control/cubic.cc
+++ b/net/quic/congestion_control/cubic.cc
@@ -28,11 +28,11 @@ const uint64 kCubeFactor = (GG_UINT64_C(1) << kCubeScale) /
kCubeCongestionWindowScale;
const uint32 kNumConnections = 2;
-const float kBeta = static_cast<float>(0.7); // Default Cubic backoff factor.
+const float kBeta = 0.7f; // Default Cubic backoff factor.
// Additional backoff factor when loss occurs in the concave part of the Cubic
// curve. This additional backoff factor is expected to give up bandwidth to
// new concurrent flows and speed up convergence.
-const float kBetaLastMax = static_cast<float>(0.85);
+const float kBetaLastMax = 0.85f;
// kNConnectionBeta is the backoff factor after loss for our N-connection
// emulation, which emulates the effective backoff of an ensemble of N TCP-Reno
diff --git a/net/quic/congestion_control/cubic_test.cc b/net/quic/congestion_control/cubic_test.cc
index 00bd37b..bb5e93d 100644
--- a/net/quic/congestion_control/cubic_test.cc
+++ b/net/quic/congestion_control/cubic_test.cc
@@ -11,7 +11,7 @@
namespace net {
namespace test {
-const float kBeta = static_cast<float>(0.7); // Default Cubic backoff factor.
+const float kBeta = 0.7f; // Default Cubic backoff factor.
const uint32 kNumConnections = 2;
const float kNConnectionBeta = (kNumConnections - 1 + kBeta) / kNumConnections;
const float kNConnectionAlpha = 3 * kNumConnections * kNumConnections *
diff --git a/net/quic/congestion_control/inter_arrival_overuse_detector.cc b/net/quic/congestion_control/inter_arrival_overuse_detector.cc
index 5e500b3..e397c1e 100644
--- a/net/quic/congestion_control/inter_arrival_overuse_detector.cc
+++ b/net/quic/congestion_control/inter_arrival_overuse_detector.cc
@@ -163,9 +163,9 @@ void InterArrivalOveruseDetector::DetectDrift(int64 sigma_delta) {
return;
}
if ((sigma_delta * kDetectTimeDiffStandardDeviation >
- estimated_congestion_delay_.ToMicroseconds()) &&
+ estimated_congestion_delay_.ToMicroseconds()) &&
(sigma_delta * kDetectDriftStandardDeviation >
- abs(accumulated_deltas_.ToMicroseconds()))) {
+ std::abs(accumulated_deltas_.ToMicroseconds()))) {
if (delta_estimate_ != kBandwidthSteady) {
DVLOG(1) << "Bandwidth estimate drift: Steady"
<< " mean:" << delta_mean_
diff --git a/net/quic/congestion_control/tcp_cubic_sender.cc b/net/quic/congestion_control/tcp_cubic_sender.cc
index 742129b..25183ef 100644
--- a/net/quic/congestion_control/tcp_cubic_sender.cc
+++ b/net/quic/congestion_control/tcp_cubic_sender.cc
@@ -340,7 +340,8 @@ void TcpCubicSender::UpdateRtt(QuicTime::Delta rtt) {
} else {
mean_deviation_ = QuicTime::Delta::FromMicroseconds(
kOneMinusBeta * mean_deviation_.ToMicroseconds() +
- kBeta * abs(smoothed_rtt_.ToMicroseconds() - rtt.ToMicroseconds()));
+ kBeta *
+ std::abs(smoothed_rtt_.ToMicroseconds() - rtt.ToMicroseconds()));
smoothed_rtt_ = QuicTime::Delta::FromMicroseconds(
kOneMinusAlpha * smoothed_rtt_.ToMicroseconds() +
kAlpha * rtt.ToMicroseconds());
diff --git a/net/quic/crypto/crypto_framer.cc b/net/quic/crypto/crypto_framer.cc
index f2e7682..5cb1674 100644
--- a/net/quic/crypto/crypto_framer.cc
+++ b/net/quic/crypto/crypto_framer.cc
@@ -24,28 +24,22 @@ const size_t kNumEntriesSize = sizeof(uint16);
// OneShotVisitor is a framer visitor that records a single handshake message.
class OneShotVisitor : public CryptoFramerVisitorInterface {
public:
- explicit OneShotVisitor(CryptoHandshakeMessage* out)
- : out_(out),
- error_(false),
- done_(false) {
- }
+ OneShotVisitor() : error_(false) {}
virtual void OnError(CryptoFramer* framer) OVERRIDE { error_ = true; }
virtual void OnHandshakeMessage(
const CryptoHandshakeMessage& message) OVERRIDE {
- *out_ = message;
- done_ = true;
+ out_.reset(new CryptoHandshakeMessage(message));
}
bool error() const { return error_; }
- bool done() const { return done_; }
+ CryptoHandshakeMessage* release() { return out_.release(); }
private:
- CryptoHandshakeMessage* const out_;
+ scoped_ptr<CryptoHandshakeMessage> out_;
bool error_;
- bool done_;
};
} // namespace
@@ -61,17 +55,16 @@ CryptoFramer::~CryptoFramer() {}
// static
CryptoHandshakeMessage* CryptoFramer::ParseMessage(StringPiece in) {
- scoped_ptr<CryptoHandshakeMessage> msg(new CryptoHandshakeMessage);
- OneShotVisitor visitor(msg.get());
+ OneShotVisitor visitor;
CryptoFramer framer;
framer.set_visitor(&visitor);
- if (!framer.ProcessInput(in) || visitor.error() || !visitor.done() ||
+ if (!framer.ProcessInput(in) || visitor.error() ||
framer.InputBytesRemaining()) {
return NULL;
}
- return msg.release();
+ return visitor.release();
}
bool CryptoFramer::ProcessInput(StringPiece input) {
diff --git a/net/quic/crypto/strike_register.cc b/net/quic/crypto/strike_register.cc
index f45bfab..9aec6ff 100644
--- a/net/quic/crypto/strike_register.cc
+++ b/net/quic/crypto/strike_register.cc
@@ -60,6 +60,13 @@ class StrikeRegister::InternalNode {
// to consider times that are before the creation time.
static const uint32 kCreationTimeFromInternalEpoch = 63115200.0; // 2 years.
+void StrikeRegister::ValidateStrikeRegisterConfig(unsigned max_entries) {
+ // We only have 23 bits of index available.
+ CHECK_LT(max_entries, 1u << 23);
+ CHECK_GT(max_entries, 1u); // There must be at least two entries.
+ CHECK_EQ(sizeof(InternalNode), 8u); // in case of compiler changes.
+}
+
StrikeRegister::StrikeRegister(unsigned max_entries,
uint32 current_time,
uint32 window_secs,
@@ -78,10 +85,7 @@ StrikeRegister::StrikeRegister(unsigned max_entries,
horizon_valid_(startup == DENY_REQUESTS_AT_STARTUP) {
memcpy(orbit_, orbit, sizeof(orbit_));
- // We only have 23 bits of index available.
- CHECK_LT(max_entries, 1u << 23);
- CHECK_GT(max_entries, 1u); // There must be at least two entries.
- CHECK_EQ(sizeof(InternalNode), 8u); // in case of compiler changes.
+ ValidateStrikeRegisterConfig(max_entries);
internal_nodes_ = new InternalNode[max_entries];
external_nodes_.reset(new uint8[kExternalNodeSize * max_entries]);
diff --git a/net/quic/crypto/strike_register.h b/net/quic/crypto/strike_register.h
index fda62a8..6e86840 100644
--- a/net/quic/crypto/strike_register.h
+++ b/net/quic/crypto/strike_register.h
@@ -81,6 +81,9 @@ class NET_EXPORT_PRIVATE StrikeRegister {
// external node. We flag the 24th bit to mark a pointer as external.
static const uint32 kExternalFlag;
+ // Allows early validation before a strike register is created.
+ static void ValidateStrikeRegisterConfig(unsigned max_entries);
+
// Construct a new set which can hold, at most, |max_entries| (which must be
// less than 2**23). See the comments around StartupType about initial
// behaviour. Otherwise, all nonces that are outside +/- |window_secs| from
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc
index 5565b28..59421ca 100644
--- a/net/quic/quic_connection.cc
+++ b/net/quic/quic_connection.cc
@@ -368,6 +368,11 @@ bool QuicConnection::OnPacketHeader(const QuicPacketHeader& header) {
debug_visitor_->OnPacketHeader(header);
}
+ if (header.fec_flag && framer_.version() <= QUIC_VERSION_14) {
+ DLOG(WARNING) << "Ignoring FEC packets for versions prior to 15.";
+ return false;
+ }
+
if (!ProcessValidatedPacket()) {
return false;
}
@@ -473,8 +478,10 @@ bool QuicConnection::OnAckFrame(const QuicAckFrame& incoming_ack) {
void QuicConnection::ProcessAckFrame(const QuicAckFrame& incoming_ack) {
largest_seen_packet_with_ack_ = last_header_.packet_sequence_number;
- received_packet_manager_.UpdatePacketInformationReceivedByPeer(incoming_ack);
- received_packet_manager_.UpdatePacketInformationSentByPeer(incoming_ack);
+ received_packet_manager_.UpdatePacketInformationReceivedByPeer(
+ incoming_ack.received_info);
+ received_packet_manager_.UpdatePacketInformationSentByPeer(
+ incoming_ack.sent_info);
// Possibly close any FecGroups which are now irrelevant.
CloseFecGroupsBefore(incoming_ack.sent_info.least_unacked + 1);
@@ -574,6 +581,15 @@ bool QuicConnection::ValidateAckFrame(const QuicAckFrame& incoming_ack) {
return false;
}
+ for (SequenceNumberSet::const_iterator iter =
+ incoming_ack.received_info.revived_packets.begin();
+ iter != incoming_ack.received_info.revived_packets.end(); ++iter) {
+ if (!ContainsKey(incoming_ack.received_info.missing_packets, *iter)) {
+ DLOG(ERROR) << ENDPOINT
+ << "Peer specified revived packet which was not missing.";
+ return false;
+ }
+ }
return true;
}
@@ -582,8 +598,7 @@ void QuicConnection::OnFecData(const QuicFecData& fec) {
DCHECK_NE(0u, last_header_.fec_group);
QuicFecGroup* group = GetFecGroup();
if (group != NULL) {
- group->UpdateFec(last_header_.packet_sequence_number,
- last_header_.entropy_flag, fec);
+ group->UpdateFec(last_header_.packet_sequence_number, fec);
}
}
@@ -645,10 +660,13 @@ void QuicConnection::OnPacketComplete() {
return;
}
- received_packet_manager_.RecordPacketReceived(last_size_,
- last_header_,
- time_of_last_received_packet_,
- last_packet_revived_);
+ if (last_packet_revived_) {
+ received_packet_manager_.RecordPacketRevived(
+ last_header_.packet_sequence_number);
+ } else {
+ received_packet_manager_.RecordPacketReceived(
+ last_size_, last_header_, time_of_last_received_packet_);
+ }
for (size_t i = 0; i < last_stream_frames_.size(); ++i) {
stats_.stream_bytes_received +=
last_stream_frames_[i].data.TotalBufferSize();
diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc
index 4e82472..c1e20f0 100644
--- a/net/quic/quic_connection_test.cc
+++ b/net/quic/quic_connection_test.cc
@@ -638,7 +638,7 @@ class QuicConnectionTest : public ::testing::TestWithParam<bool> {
}
size_t ProcessFecProtectedPacket(QuicPacketSequenceNumber number,
- bool expect_revival, bool entropy_flag) {
+ bool expect_revival, bool entropy_flag) {
if (expect_revival) {
EXPECT_CALL(visitor_, OnStreamFrames(_)).WillOnce(Return(accept_packet_));
}
@@ -1847,7 +1847,9 @@ TEST_F(QuicConnectionTest, RetransmitWriteBlockedAckedOriginalThenSent) {
ProcessAckPacket(&ack);
connection_.OnPacketSent(WriteResult(WRITE_STATUS_OK, 0));
- EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
+ // The retransmission alarm should not be set because there are
+ // no unacked packets.
+ EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
}
TEST_F(QuicConnectionTest, ResumptionAlarmWhenWriteBlocked) {
@@ -1983,8 +1985,9 @@ TEST_F(QuicConnectionTest, ReviveMissingPacketAfterDataPacketsThenFecPacket) {
// Don't send missing packet 2.
ProcessFecProtectedPacket(3, false, !kEntropyFlag);
ProcessFecPacket(4, 1, true, kEntropyFlag, NULL);
- // Entropy flag should be true, so entropy should not be 0.
- EXPECT_NE(0u, QuicConnectionPeer::ReceivedEntropyHash(&connection_, 2));
+ // Ensure QUIC no longer revives entropy for lost packets.
+ EXPECT_EQ(0u, QuicConnectionPeer::ReceivedEntropyHash(&connection_, 2));
+ EXPECT_NE(0u, QuicConnectionPeer::ReceivedEntropyHash(&connection_, 4));
}
TEST_F(QuicConnectionTest, ReviveMissingPacketAfterDataPacket) {
@@ -2007,8 +2010,9 @@ TEST_F(QuicConnectionTest, ReviveMissingPacketAfterDataPackets) {
ProcessFecProtectedPacket(3, false, kEntropyFlag);
ProcessFecProtectedPacket(4, false, kEntropyFlag);
ProcessFecProtectedPacket(5, true, !kEntropyFlag);
- // Entropy flag should be true, so entropy should be 0.
- EXPECT_NE(0u, QuicConnectionPeer::ReceivedEntropyHash(&connection_, 2));
+ // Ensure entropy is not revived for the missing packet.
+ EXPECT_EQ(0u, QuicConnectionPeer::ReceivedEntropyHash(&connection_, 2));
+ EXPECT_NE(0u, QuicConnectionPeer::ReceivedEntropyHash(&connection_, 3));
}
TEST_F(QuicConnectionTest, RTO) {
@@ -2781,6 +2785,17 @@ TEST_F(QuicConnectionTest, ReceivedEntropyHashCalculation) {
EXPECT_EQ(146u, outgoing_ack()->received_info.entropy_hash);
}
+TEST_F(QuicConnectionTest, ReceivedEntropyHashCalculationHalfFEC) {
+ // FEC packets should not change the entropy hash calculation.
+ EXPECT_CALL(visitor_, OnStreamFrames(_)).WillRepeatedly(Return(true));
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ ProcessDataPacket(1, 1, kEntropyFlag);
+ ProcessFecPacket(4, 1, false, kEntropyFlag, NULL);
+ ProcessDataPacket(3, 3, !kEntropyFlag);
+ ProcessFecPacket(7, 3, false, kEntropyFlag, NULL);
+ EXPECT_EQ(146u, outgoing_ack()->received_info.entropy_hash);
+}
+
TEST_F(QuicConnectionTest, UpdateEntropyForReceivedPackets) {
EXPECT_CALL(visitor_, OnStreamFrames(_)).WillRepeatedly(Return(true));
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
diff --git a/net/quic/quic_fec_group.cc b/net/quic/quic_fec_group.cc
index 8e37044..36b14bc 100644
--- a/net/quic/quic_fec_group.cc
+++ b/net/quic/quic_fec_group.cc
@@ -22,8 +22,7 @@ const QuicPacketSequenceNumber kNoSequenceNumber = kuint64max;
QuicFecGroup::QuicFecGroup()
: min_protected_packet_(kNoSequenceNumber),
max_protected_packet_(kNoSequenceNumber),
- payload_parity_len_(0),
- entropy_parity_(false) {
+ payload_parity_len_(0) {
}
QuicFecGroup::~QuicFecGroup() {}
@@ -41,7 +40,7 @@ bool QuicFecGroup::Update(const QuicPacketHeader& header,
<< header.packet_sequence_number;
return false;
}
- if (!UpdateParity(decrypted_payload, header.entropy_flag)) {
+ if (!UpdateParity(decrypted_payload)) {
return false;
}
received_packets_.insert(header.packet_sequence_number);
@@ -50,21 +49,19 @@ bool QuicFecGroup::Update(const QuicPacketHeader& header,
bool QuicFecGroup::UpdateFec(
QuicPacketSequenceNumber fec_packet_sequence_number,
- bool fec_packet_entropy,
const QuicFecData& fec) {
if (min_protected_packet_ != kNoSequenceNumber) {
return false;
}
SequenceNumberSet::const_iterator it = received_packets_.begin();
while (it != received_packets_.end()) {
- if ((*it < fec.fec_group) ||
- (*it >= fec_packet_sequence_number)) {
+ if ((*it < fec.fec_group) || (*it >= fec_packet_sequence_number)) {
DLOG(ERROR) << "FEC group does not cover received packet: " << *it;
return false;
}
++it;
}
- if (!UpdateParity(fec.redundancy, fec_packet_entropy)) {
+ if (!UpdateParity(fec.redundancy)) {
return false;
}
min_protected_packet_ = fec.fec_group;
@@ -110,7 +107,7 @@ size_t QuicFecGroup::Revive(QuicPacketHeader* header,
}
header->packet_sequence_number = missing;
- header->entropy_flag = entropy_parity_;
+ header->entropy_flag = false; // Unknown entropy.
received_packets_.insert(missing);
return payload_parity_len_;
@@ -125,7 +122,7 @@ bool QuicFecGroup::ProtectsPacketsBefore(QuicPacketSequenceNumber num) const {
return *received_packets_.begin() < num;
}
-bool QuicFecGroup::UpdateParity(StringPiece payload, bool entropy) {
+bool QuicFecGroup::UpdateParity(StringPiece payload) {
DCHECK_LE(payload.size(), kMaxPacketSize);
if (payload.size() > kMaxPacketSize) {
DLOG(ERROR) << "Illegal payload size: " << payload.size();
@@ -144,7 +141,6 @@ bool QuicFecGroup::UpdateParity(StringPiece payload, bool entropy) {
memset(payload_parity_ + payload.size(), 0,
kMaxPacketSize - payload.size());
}
- entropy_parity_ = entropy;
return true;
}
// Update the parity by XORing in the data (padding with 0s if necessary).
@@ -152,8 +148,6 @@ bool QuicFecGroup::UpdateParity(StringPiece payload, bool entropy) {
uint8 byte = i < payload.size() ? payload[i] : 0x00;
payload_parity_[i] ^= byte;
}
- // xor of boolean values.
- entropy_parity_ = (entropy_parity_ != entropy);
return true;
}
diff --git a/net/quic/quic_fec_group.h b/net/quic/quic_fec_group.h
index d905d03..f296b9c 100644
--- a/net/quic/quic_fec_group.h
+++ b/net/quic/quic_fec_group.h
@@ -31,7 +31,6 @@ class NET_EXPORT_PRIVATE QuicFecGroup {
// not claim to protect all the packets previously seen in this group.
// |fec_packet_entropy|: XOR of entropy of all packets in the fec group.
bool UpdateFec(QuicPacketSequenceNumber fec_packet_sequence_number,
- bool fec_packet_entropy,
const QuicFecData& fec);
// Returns true if a packet can be revived from this FEC group.
@@ -57,10 +56,6 @@ class NET_EXPORT_PRIVATE QuicFecGroup {
return base::StringPiece(payload_parity_, payload_parity_len_);
}
- bool entropy_parity() const {
- return entropy_parity_;
- }
-
QuicPacketSequenceNumber min_protected_packet() const {
return min_protected_packet_;
}
@@ -70,7 +65,7 @@ class NET_EXPORT_PRIVATE QuicFecGroup {
}
private:
- bool UpdateParity(base::StringPiece payload, bool entropy);
+ bool UpdateParity(base::StringPiece payload);
// Returns the number of missing packets, or size_t max if the number
// of missing packets is not known.
size_t NumMissingPackets() const;
@@ -88,7 +83,6 @@ class NET_EXPORT_PRIVATE QuicFecGroup {
// The cumulative parity calculation of all received packets.
char payload_parity_[kMaxPacketSize];
size_t payload_parity_len_;
- bool entropy_parity_;
DISALLOW_COPY_AND_ASSIGN(QuicFecGroup);
};
diff --git a/net/quic/quic_fec_group_test.cc b/net/quic/quic_fec_group_test.cc
index 02ed5c9..df83382 100644
--- a/net/quic/quic_fec_group_test.cc
+++ b/net/quic/quic_fec_group_test.cc
@@ -36,8 +36,6 @@ const bool kEntropyFlag[] = {
true,
};
-const bool kTestFecPacketEntropy = false;
-
} // namespace
class QuicFecGroupTest : public ::testing::Test {
@@ -45,7 +43,6 @@ class QuicFecGroupTest : public ::testing::Test {
void RunTest(size_t num_packets, size_t lost_packet, bool out_of_order) {
size_t max_len = strlen(kData[0]);
scoped_ptr<char[]> redundancy(new char[max_len]);
- bool entropy_redundancy = false;
for (size_t packet = 0; packet < num_packets; ++packet) {
for (size_t i = 0; i < max_len; i++) {
if (packet == 0) {
@@ -57,7 +54,6 @@ class QuicFecGroupTest : public ::testing::Test {
uint8 byte = i > strlen(kData[packet]) ? 0x00 : kData[packet][i];
redundancy[i] = redundancy[i] ^ byte;
}
- entropy_redundancy = (entropy_redundancy != kEntropyFlag[packet]);
}
QuicFecGroup group;
@@ -72,7 +68,7 @@ class QuicFecGroupTest : public ::testing::Test {
QuicFecData fec;
fec.fec_group = 0;
fec.redundancy = StringPiece(redundancy.get(), strlen(kData[0]));
- ASSERT_TRUE(group.UpdateFec(num_packets, entropy_redundancy, fec));
+ ASSERT_TRUE(group.UpdateFec(num_packets, fec));
} else {
QuicPacketHeader header;
header.packet_sequence_number = packet;
@@ -101,7 +97,7 @@ class QuicFecGroupTest : public ::testing::Test {
fec.fec_group = 0;
fec.redundancy = StringPiece(redundancy.get(), strlen(kData[0]));
- ASSERT_TRUE(group.UpdateFec(num_packets, entropy_redundancy, fec));
+ ASSERT_TRUE(group.UpdateFec(num_packets, fec));
}
QuicPacketHeader header;
char recovered[kMaxPacketSize];
@@ -113,7 +109,8 @@ class QuicFecGroupTest : public ::testing::Test {
EXPECT_EQ(lost_packet, header.packet_sequence_number)
<< "Failed to revive packet " << lost_packet << " out of "
<< num_packets;
- EXPECT_EQ(kEntropyFlag[lost_packet], header.entropy_flag);
+ // Revived packets have an unknown entropy.
+ EXPECT_FALSE(header.entropy_flag);
ASSERT_GE(len, strlen(kData[lost_packet])) << "Incorrect length";
for (size_t i = 0; i < strlen(kData[lost_packet]); i++) {
EXPECT_EQ(kData[lost_packet][i], recovered[i]);
@@ -158,7 +155,7 @@ TEST_F(QuicFecGroupTest, UpdateFecIfReceivedPacketIsNotCovered) {
fec.redundancy = redundancy;
header.packet_sequence_number = 2;
- ASSERT_FALSE(group.UpdateFec(2, kTestFecPacketEntropy, fec));
+ ASSERT_FALSE(group.UpdateFec(2, fec));
}
TEST_F(QuicFecGroupTest, ProtectsPacketsBefore) {
@@ -207,7 +204,7 @@ TEST_F(QuicFecGroupTest, ProtectsPacketsBeforeWithFecData) {
fec.redundancy = kData[0];
QuicFecGroup group;
- ASSERT_TRUE(group.UpdateFec(3, kTestFecPacketEntropy, fec));
+ ASSERT_TRUE(group.UpdateFec(3, fec));
EXPECT_FALSE(group.ProtectsPacketsBefore(1));
EXPECT_FALSE(group.ProtectsPacketsBefore(2));
diff --git a/net/quic/quic_framer.cc b/net/quic/quic_framer.cc
index 594cad92..90d9a89 100644
--- a/net/quic/quic_framer.cc
+++ b/net/quic/quic_framer.cc
@@ -5,6 +5,7 @@
#include "net/quic/quic_framer.h"
#include "base/containers/hash_tables.h"
+#include "base/stl_util.h"
#include "net/quic/crypto/crypto_framer.h"
#include "net/quic/crypto/crypto_handshake_message.h"
#include "net/quic/crypto/quic_decrypter.h"
@@ -648,9 +649,9 @@ bool QuicFramer::ProcessPublicResetPacket(
const QuicPacketPublicHeader& public_header) {
QuicPublicResetPacket packet(public_header);
- if (reader_->BytesRemaining() <=
- kPublicResetNonceSize + PACKET_6BYTE_SEQUENCE_NUMBER) {
- // An old-style public reset packet.
+ if (public_header.sequence_number_length == PACKET_6BYTE_SEQUENCE_NUMBER) {
+ // An old-style public reset packet has the
+ // PACKET_PUBLIC_FLAGS_6BYTE_SEQUENCE bits set in the public flags.
// TODO(wtc): remove this when we drop support for QUIC_VERSION_13.
if (!reader_->ReadUInt64(&packet.nonce_proof)) {
set_detailed_error("Unable to read nonce proof.");
@@ -1377,6 +1378,26 @@ bool QuicFramer::ProcessReceivedInfo(uint8 frame_type,
last_sequence_number -= (range_length + 1);
}
+ if (quic_version_ > QUIC_VERSION_14) {
+ // Parse the revived packets list.
+ uint8 num_revived_packets;
+ if (!reader_->ReadBytes(&num_revived_packets, 1)) {
+ set_detailed_error("Unable to read num revived packets.");
+ return false;
+ }
+
+ for (size_t i = 0; i < num_revived_packets; ++i) {
+ QuicPacketSequenceNumber revived_packet = 0;
+ if (!reader_->ReadBytes(&revived_packet,
+ largest_observed_sequence_number_length)) {
+ set_detailed_error("Unable to read revived packet.");
+ return false;
+ }
+
+ received_info->revived_packets.insert(revived_packet);
+ }
+ }
+
return true;
}
@@ -1414,12 +1435,14 @@ bool QuicFramer::ProcessQuicCongestionFeedbackFrame(
case kInterArrival: {
CongestionFeedbackMessageInterArrival* inter_arrival =
&frame->inter_arrival;
- uint16 unused_accumulated_number_of_lost_packets;
- if (!reader_->ReadUInt16(
- &unused_accumulated_number_of_lost_packets)) {
- set_detailed_error(
- "Unable to read accumulated number of lost packets.");
- return false;
+ if (quic_version_ <= QUIC_VERSION_14) {
+ uint16 unused_accumulated_number_of_lost_packets;
+ if (!reader_->ReadUInt16(
+ &unused_accumulated_number_of_lost_packets)) {
+ set_detailed_error(
+ "Unable to read accumulated number of lost packets.");
+ return false;
+ }
}
uint8 num_received_packets;
if (!reader_->ReadBytes(&num_received_packets, 1)) {
@@ -1479,11 +1502,13 @@ bool QuicFramer::ProcessQuicCongestionFeedbackFrame(
}
case kTCP: {
CongestionFeedbackMessageTCP* tcp = &frame->tcp;
- uint16 unused_accumulated_number_of_lost_packets;
- if (!reader_->ReadUInt16(&unused_accumulated_number_of_lost_packets)) {
- set_detailed_error(
- "Unable to read accumulated number of lost packets.");
- return false;
+ if (quic_version_ <= QUIC_VERSION_14) {
+ uint16 unused_accumulated_number_of_lost_packets;
+ if (!reader_->ReadUInt16(&unused_accumulated_number_of_lost_packets)) {
+ set_detailed_error(
+ "Unable to read accumulated number of lost packets.");
+ return false;
+ }
}
// TODO(ianswett): Remove receive window, since it's constant.
uint16 receive_window = 0;
@@ -1769,12 +1794,18 @@ size_t QuicFramer::GetAckFrameSize(
QuicSequenceNumberLength missing_sequence_number_length =
GetMinSequenceNumberLength(ack_info.max_delta);
- return GetMinAckFrameSize(quic_version_,
- sequence_number_length,
- largest_observed_length) +
- (ack_info.nack_ranges.empty() ? 0 : kNumberOfMissingPacketsSize) +
- ack_info.nack_ranges.size() *
- (missing_sequence_number_length + PACKET_1BYTE_SEQUENCE_NUMBER);
+ size_t ack_size = GetMinAckFrameSize(quic_version_,
+ sequence_number_length,
+ largest_observed_length);
+ if (!ack_info.nack_ranges.empty()) {
+ ack_size += kNumberOfMissingPacketsSize +
+ (quic_version_ <= QUIC_VERSION_14 ? 0 : kNumberOfRevivedPacketsSize);
+ ack_size += ack_info.nack_ranges.size() *
+ (missing_sequence_number_length + PACKET_1BYTE_SEQUENCE_NUMBER);
+ ack_size +=
+ ack.received_info.revived_packets.size() * largest_observed_length;
+ }
+ return ack_size;
}
size_t QuicFramer::ComputeFrameLength(
@@ -1801,7 +1832,9 @@ size_t QuicFramer::ComputeFrameLength(
case kInterArrival: {
const CongestionFeedbackMessageInterArrival& inter_arrival =
congestion_feedback.inter_arrival;
- len += 2;
+ if (quic_version_ <= QUIC_VERSION_14) {
+ len += 2; // Accumulated number of lost packets.
+ }
len += 1; // Number received packets.
if (inter_arrival.received_packet_times.size() > 0) {
len += PACKET_6BYTE_SEQUENCE_NUMBER; // Smallest received.
@@ -1813,10 +1846,13 @@ size_t QuicFramer::ComputeFrameLength(
break;
}
case kFixRate:
- len += 4;
+ len += 4; // Bitrate.
break;
case kTCP:
- len += 4;
+ if (quic_version_ <= QUIC_VERSION_14) {
+ len += 2; // Accumulated number of lost packets.
+ }
+ len += 2; // Receive window.
break;
default:
set_detailed_error("Illegal feedback type.");
@@ -1970,7 +2006,8 @@ bool QuicFramer::AppendAckFrameAndTypeByte(
size_t available_range_bytes = writer->capacity() - writer->length() -
GetMinAckFrameSize(quic_version_,
header.public_header.sequence_number_length,
- largest_observed_length);
+ largest_observed_length) -
+ (quic_version_ <= QUIC_VERSION_14 ? 0 : kNumberOfRevivedPacketsSize);
size_t max_num_ranges = available_range_bytes /
(missing_sequence_number_length + PACKET_1BYTE_SEQUENCE_NUMBER);
max_num_ranges =
@@ -2012,6 +2049,15 @@ bool QuicFramer::AppendAckFrameAndTypeByte(
DCHECK_GE(header.packet_sequence_number, frame.sent_info.least_unacked);
const QuicPacketSequenceNumber least_unacked_delta =
header.packet_sequence_number - frame.sent_info.least_unacked;
+ const QuicPacketSequenceNumber length_shift =
+ header.public_header.sequence_number_length * 8;
+ if (least_unacked_delta >> length_shift > 0) {
+ LOG(DFATAL) << "sequence_number_length "
+ << header.public_header.sequence_number_length
+ << " is too small for least_unacked_delta: "
+ << least_unacked_delta;
+ return false;
+ }
if (!AppendPacketSequenceNumber(header.public_header.sequence_number_length,
least_unacked_delta, writer)) {
return false;
@@ -2085,8 +2131,32 @@ bool QuicFramer::AppendAckFrameAndTypeByte(
last_sequence_written = ack_iter->first - 1;
++num_ranges_written;
}
-
DCHECK_EQ(num_missing_ranges, num_ranges_written);
+
+ if (quic_version_ > QUIC_VERSION_14) {
+ // 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()));
+ num_revived_packets = min(
+ static_cast<size_t>(num_revived_packets),
+ (writer->capacity() - writer->length()) / largest_observed_length);
+ if (!writer->WriteBytes(&num_revived_packets, 1)) {
+ return false;
+ }
+
+ SequenceNumberSet::const_iterator iter =
+ received_info.revived_packets.begin();
+ for (int i = 0; i < num_revived_packets; ++i, ++iter) {
+ LOG_IF(DFATAL, !ContainsKey(received_info.missing_packets, *iter));
+ if (!AppendPacketSequenceNumber(largest_observed_length,
+ *iter, writer)) {
+ return false;
+ }
+ }
+ }
+
return true;
}
@@ -2101,9 +2171,11 @@ bool QuicFramer::AppendQuicCongestionFeedbackFrame(
case kInterArrival: {
const CongestionFeedbackMessageInterArrival& inter_arrival =
frame.inter_arrival;
- // accumulated_number_of_lost_packets is removed. Always write 0.
- if (!writer->WriteUInt16(0)) {
- return false;
+ if (quic_version_ <= QUIC_VERSION_14) {
+ // accumulated_number_of_lost_packets is removed. Always write 0.
+ if (!writer->WriteUInt16(0)) {
+ return false;
+ }
}
DCHECK_GE(numeric_limits<uint8>::max(),
inter_arrival.received_packet_times.size());
@@ -2165,9 +2237,11 @@ bool QuicFramer::AppendQuicCongestionFeedbackFrame(
DCHECK_LE(tcp.receive_window, 1u << 20);
// Simple bit packing, don't send the 4 least significant bits.
uint16 receive_window = static_cast<uint16>(tcp.receive_window >> 4);
- // accumulated_number_of_lost_packets is removed. Always write 0.
- if (!writer->WriteUInt16(0)) {
- return false;
+ if (quic_version_ <= QUIC_VERSION_14) {
+ // accumulated_number_of_lost_packets is removed. Always write 0.
+ if (!writer->WriteUInt16(0)) {
+ return false;
+ }
}
if (!writer->WriteUInt16(receive_window)) {
return false;
diff --git a/net/quic/quic_framer.h b/net/quic/quic_framer.h
index 438cbbd..bf2ab3d 100644
--- a/net/quic/quic_framer.h
+++ b/net/quic/quic_framer.h
@@ -47,6 +47,8 @@ const size_t kQuicEntropyHashSize = 1;
const size_t kQuicDeltaTimeLargestObservedSize = 2;
// Size in bytes reserved for the number of missing packets in ack frames.
const size_t kNumberOfMissingPacketsSize = 1;
+// Size in bytes reserved for the number of revived packets in ack frames.
+const size_t kNumberOfRevivedPacketsSize = 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 6adf405..b4c2b85 100644
--- a/net/quic/quic_framer_test.cc
+++ b/net/quic/quic_framer_test.cc
@@ -94,21 +94,22 @@ size_t GetFecGroupOffset(bool include_version,
kPrivateFlagsSize;
}
+// Index into the message tag of the public reset packet.
+// Public resets always have full guids.
+const size_t kPublicResetPacketMessageTagOffset =
+ kGuidOffset + PACKET_8BYTE_GUID;
+
+// TODO(wtc): remove this when we drop support for QUIC_VERSION_13.
// Index into the nonce proof of the public reset packet.
// Public resets always have full guids.
const size_t kPublicResetPacketNonceProofOffset =
kGuidOffset + PACKET_8BYTE_GUID;
+// TODO(wtc): remove this when we drop support for QUIC_VERSION_13.
// Index into the rejected sequence number of the public reset packet.
const size_t kPublicResetPacketRejectedSequenceNumberOffset =
kPublicResetPacketNonceProofOffset + kPublicResetNonceSize;
-// TODO(wtc): remove this when we drop support for QUIC_VERSION_13.
-// Size of the old-style public reset packet.
-const size_t kPublicResetPacketOldSize =
- kPublicResetPacketRejectedSequenceNumberOffset +
- PACKET_6BYTE_SEQUENCE_NUMBER;
-
class TestEncrypter : public QuicEncrypter {
public:
virtual ~TestEncrypter() {}
@@ -1656,7 +1657,11 @@ TEST_P(QuicFramerTest, StreamFrameInFecGroup) {
CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]);
}
-TEST_P(QuicFramerTest, AckFrame) {
+TEST_P(QuicFramerTest, AckFrameV14) {
+ if (framer_.version() > QUIC_VERSION_14) {
+ return;
+ }
+
unsigned char packet[] = {
// public flags (8 byte guid)
0x3C,
@@ -1755,6 +1760,231 @@ TEST_P(QuicFramerTest, AckFrame) {
}
}
+TEST_P(QuicFramerTest, AckFrame) {
+ if (framer_.version() <= QUIC_VERSION_14) {
+ return;
+ }
+
+ unsigned char packet[] = {
+ // public flags (8 byte guid)
+ 0x3C,
+ // guid
+ 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, not truncated, 6 byte largest observed, 1 byte delta)
+ 0x6C,
+ // entropy hash of sent packets till least awaiting - 1.
+ 0xAB,
+ // least packet sequence number awaiting an ack, delta from sequence number.
+ 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00,
+ // entropy hash of all received packets.
+ 0xBA,
+ // largest observed packet sequence number
+ 0xBF, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // Zero delta time.
+ 0x0, 0x0,
+ // num missing packets
+ 0x01,
+ // missing packet delta
+ 0x01,
+ // 0 more missing packets in range.
+ 0x00,
+ // Number of revived packets.
+ 0x00,
+ };
+
+ QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion));
+
+ EXPECT_EQ(0u, visitor_.stream_frames_.size());
+ ASSERT_EQ(1u, visitor_.ack_frames_.size());
+ const QuicAckFrame& frame = *visitor_.ack_frames_[0];
+ EXPECT_EQ(0xAB, frame.sent_info.entropy_hash);
+ EXPECT_EQ(0xBA, frame.received_info.entropy_hash);
+ EXPECT_EQ(GG_UINT64_C(0x0123456789ABF), frame.received_info.largest_observed);
+ ASSERT_EQ(1u, frame.received_info.missing_packets.size());
+ SequenceNumberSet::const_iterator missing_iter =
+ frame.received_info.missing_packets.begin();
+ EXPECT_EQ(GG_UINT64_C(0x0123456789ABE), *missing_iter);
+ EXPECT_EQ(GG_UINT64_C(0x0123456789AA0), frame.sent_info.least_unacked);
+
+ const size_t kSentEntropyOffset = kQuicFrameTypeSize;
+ const size_t kLeastUnackedOffset = kSentEntropyOffset + kQuicEntropyHashSize;
+ const size_t kReceivedEntropyOffset = kLeastUnackedOffset +
+ PACKET_6BYTE_SEQUENCE_NUMBER;
+ const size_t kLargestObservedOffset = kReceivedEntropyOffset +
+ kQuicEntropyHashSize;
+ const size_t kMissingDeltaTimeOffset = kLargestObservedOffset +
+ PACKET_6BYTE_SEQUENCE_NUMBER;
+ const size_t kNumMissingPacketOffset = kMissingDeltaTimeOffset +
+ kQuicDeltaTimeLargestObservedSize;
+ const size_t kMissingPacketsOffset = kNumMissingPacketOffset +
+ kNumberOfMissingPacketsSize;
+ const size_t kMissingPacketsRange = kMissingPacketsOffset +
+ PACKET_1BYTE_SEQUENCE_NUMBER;
+ const size_t kRevivedPacketsLength = kMissingPacketsRange +
+ PACKET_1BYTE_SEQUENCE_NUMBER;
+ // Now test framing boundaries
+ const size_t ack_frame_size = kRevivedPacketsLength +
+ PACKET_1BYTE_SEQUENCE_NUMBER;
+ for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) {
+ string expected_error;
+ if (i < kLeastUnackedOffset) {
+ expected_error = "Unable to read entropy hash for sent packets.";
+ } else if (i < kReceivedEntropyOffset) {
+ expected_error = "Unable to read least unacked delta.";
+ } else if (i < kLargestObservedOffset) {
+ expected_error = "Unable to read entropy hash for received packets.";
+ } else if (i < kMissingDeltaTimeOffset) {
+ expected_error = "Unable to read largest observed.";
+ } else if (i < kNumMissingPacketOffset) {
+ expected_error = "Unable to read delta time largest observed.";
+ } else if (i < kMissingPacketsOffset) {
+ expected_error = "Unable to read num missing packet ranges.";
+ } else if (i < kMissingPacketsRange) {
+ expected_error = "Unable to read missing sequence number delta.";
+ } else if (i < kRevivedPacketsLength) {
+ expected_error = "Unable to read missing sequence number range.";
+ } else {
+ expected_error = "Unable to read num revived packets.";
+ }
+ CheckProcessingFails(
+ packet,
+ i + GetPacketHeaderSize(PACKET_8BYTE_GUID, !kIncludeVersion,
+ PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP),
+ expected_error, QUIC_INVALID_ACK_DATA);
+ }
+}
+
+TEST_P(QuicFramerTest, AckFrameRevivedPackets) {
+ if (framer_.version() <= QUIC_VERSION_14) {
+ return;
+ }
+
+ unsigned char packet[] = {
+ // public flags (8 byte guid)
+ 0x3C,
+ // guid
+ 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, not truncated, 6 byte largest observed, 1 byte delta)
+ 0x6C,
+ // entropy hash of sent packets till least awaiting - 1.
+ 0xAB,
+ // least packet sequence number awaiting an ack, delta from sequence number.
+ 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00,
+ // entropy hash of all received packets.
+ 0xBA,
+ // largest observed packet sequence number
+ 0xBF, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // Zero delta time.
+ 0x0, 0x0,
+ // num missing packets
+ 0x01,
+ // missing packet delta
+ 0x01,
+ // 0 more missing packets in range.
+ 0x00,
+ // Number of revived packets.
+ 0x01,
+ // Revived packet sequence number.
+ 0xBE, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ };
+
+ QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion));
+
+ EXPECT_EQ(0u, visitor_.stream_frames_.size());
+ ASSERT_EQ(1u, visitor_.ack_frames_.size());
+ const QuicAckFrame& frame = *visitor_.ack_frames_[0];
+ EXPECT_EQ(0xAB, frame.sent_info.entropy_hash);
+ EXPECT_EQ(0xBA, frame.received_info.entropy_hash);
+ EXPECT_EQ(GG_UINT64_C(0x0123456789ABF), frame.received_info.largest_observed);
+ ASSERT_EQ(1u, frame.received_info.missing_packets.size());
+ SequenceNumberSet::const_iterator missing_iter =
+ frame.received_info.missing_packets.begin();
+ EXPECT_EQ(GG_UINT64_C(0x0123456789ABE), *missing_iter);
+ EXPECT_EQ(GG_UINT64_C(0x0123456789AA0), frame.sent_info.least_unacked);
+
+ const size_t kSentEntropyOffset = kQuicFrameTypeSize;
+ const size_t kLeastUnackedOffset = kSentEntropyOffset + kQuicEntropyHashSize;
+ const size_t kReceivedEntropyOffset = kLeastUnackedOffset +
+ PACKET_6BYTE_SEQUENCE_NUMBER;
+ const size_t kLargestObservedOffset = kReceivedEntropyOffset +
+ kQuicEntropyHashSize;
+ const size_t kMissingDeltaTimeOffset = kLargestObservedOffset +
+ PACKET_6BYTE_SEQUENCE_NUMBER;
+ const size_t kNumMissingPacketOffset = kMissingDeltaTimeOffset +
+ kQuicDeltaTimeLargestObservedSize;
+ const size_t kMissingPacketsOffset = kNumMissingPacketOffset +
+ kNumberOfMissingPacketsSize;
+ const size_t kMissingPacketsRange = kMissingPacketsOffset +
+ PACKET_1BYTE_SEQUENCE_NUMBER;
+ const size_t kRevivedPacketsLength = kMissingPacketsRange +
+ PACKET_1BYTE_SEQUENCE_NUMBER;
+ const size_t kRevivedPacketSequenceNumberLength = kRevivedPacketsLength +
+ PACKET_1BYTE_SEQUENCE_NUMBER;
+ // Now test framing boundaries
+ const size_t ack_frame_size = kRevivedPacketSequenceNumberLength +
+ PACKET_6BYTE_SEQUENCE_NUMBER;
+ for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) {
+ string expected_error;
+ if (i < kLeastUnackedOffset) {
+ expected_error = "Unable to read entropy hash for sent packets.";
+ } else if (i < kReceivedEntropyOffset) {
+ expected_error = "Unable to read least unacked delta.";
+ } else if (i < kLargestObservedOffset) {
+ expected_error = "Unable to read entropy hash for received packets.";
+ } else if (i < kMissingDeltaTimeOffset) {
+ expected_error = "Unable to read largest observed.";
+ } else if (i < kNumMissingPacketOffset) {
+ expected_error = "Unable to read delta time largest observed.";
+ } else if (i < kMissingPacketsOffset) {
+ expected_error = "Unable to read num missing packet ranges.";
+ } else if (i < kMissingPacketsRange) {
+ expected_error = "Unable to read missing sequence number delta.";
+ } else if (i < kRevivedPacketsLength) {
+ expected_error = "Unable to read missing sequence number range.";
+ } else if (i < kRevivedPacketSequenceNumberLength) {
+ expected_error = "Unable to read num revived packets.";
+ } else {
+ expected_error = "Unable to read revived packet.";
+ }
+ CheckProcessingFails(
+ packet,
+ i + GetPacketHeaderSize(PACKET_8BYTE_GUID, !kIncludeVersion,
+ PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP),
+ expected_error, QUIC_INVALID_ACK_DATA);
+ }
+}
+
TEST_P(QuicFramerTest, AckFrameNoNacks) {
unsigned char packet[] = {
// public flags (8 byte guid)
@@ -1815,6 +2045,91 @@ TEST_P(QuicFramerTest, AckFrameNoNacks) {
}
TEST_P(QuicFramerTest, AckFrame500Nacks) {
+ if (framer_.version() <= QUIC_VERSION_14) {
+ return;
+ }
+ unsigned char packet[] = {
+ // public flags (8 byte guid)
+ 0x3C,
+ // guid
+ 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, not truncated, 6 byte largest observed, 1 byte delta)
+ 0x6C,
+ // entropy hash of sent packets till least awaiting - 1.
+ 0xAB,
+ // least packet sequence number awaiting an ack, delta from sequence number.
+ 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00,
+ // entropy hash of all received packets.
+ 0xBA,
+ // largest observed packet sequence number
+ 0xBF, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // Zero delta time.
+ 0x0, 0x0,
+ // num missing packet ranges
+ 0x02,
+ // missing packet delta
+ 0x01,
+ // 243 more missing packets in range.
+ // The ranges are listed in this order so the re-constructed packet matches.
+ 0xF3,
+ // No gap between ranges
+ 0x00,
+ // 255 more missing packets in range.
+ 0xFF,
+ // No revived packets.
+ 0x00,
+ };
+
+ QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion));
+
+ EXPECT_EQ(0u, visitor_.stream_frames_.size());
+ ASSERT_EQ(1u, visitor_.ack_frames_.size());
+ QuicAckFrame* frame = visitor_.ack_frames_[0];
+ EXPECT_EQ(0xAB, frame->sent_info.entropy_hash);
+ EXPECT_EQ(0xBA, frame->received_info.entropy_hash);
+ EXPECT_EQ(GG_UINT64_C(0x0123456789ABF),
+ frame->received_info.largest_observed);
+ EXPECT_EQ(0u, frame->received_info.revived_packets.size());
+ ASSERT_EQ(500u, frame->received_info.missing_packets.size());
+ SequenceNumberSet::const_iterator first_missing_iter =
+ frame->received_info.missing_packets.begin();
+ EXPECT_EQ(GG_UINT64_C(0x0123456789ABE) - 499, *first_missing_iter);
+ SequenceNumberSet::const_reverse_iterator last_missing_iter =
+ frame->received_info.missing_packets.rbegin();
+ EXPECT_EQ(GG_UINT64_C(0x0123456789ABE), *last_missing_iter);
+ EXPECT_EQ(GG_UINT64_C(0x0123456789AA0), frame->sent_info.least_unacked);
+
+ // Verify that the packet re-serializes identically.
+ QuicFrames frames;
+ frames.push_back(QuicFrame(frame));
+ scoped_ptr<QuicPacket> data(
+ framer_.BuildUnsizedDataPacket(*visitor_.header_, frames).packet);
+ ASSERT_TRUE(data != NULL);
+
+ test::CompareCharArraysWithHexError("constructed packet",
+ data->data(), data->length(),
+ AsChars(packet), arraysize(packet));
+}
+
+TEST_P(QuicFramerTest, AckFrame500NacksV14) {
+ if (framer_.version() > QUIC_VERSION_14) {
+ return;
+ }
unsigned char packet[] = {
// public flags (8 byte guid)
0x3C,
@@ -1891,6 +2206,63 @@ TEST_P(QuicFramerTest, AckFrame500Nacks) {
}
TEST_P(QuicFramerTest, CongestionFeedbackFrameTCP) {
+ if (framer_.version() <= QUIC_VERSION_14) {
+ return;
+ }
+ unsigned char packet[] = {
+ // public flags (8 byte guid)
+ 0x3C,
+ // guid
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet sequence number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags
+ 0x00,
+
+ // frame type (congestion feedback frame)
+ 0x20,
+ // congestion feedback type (tcp)
+ 0x00,
+ // ack_frame.feedback.tcp.receive_window
+ 0x03, 0x04,
+ };
+
+ QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion));
+
+ EXPECT_EQ(0u, visitor_.stream_frames_.size());
+ ASSERT_EQ(1u, visitor_.congestion_feedback_frames_.size());
+ const QuicCongestionFeedbackFrame& frame =
+ *visitor_.congestion_feedback_frames_[0];
+ ASSERT_EQ(kTCP, frame.type);
+ EXPECT_EQ(0x4030u, frame.tcp.receive_window);
+
+ // Now test framing boundaries
+ for (size_t i = kQuicFrameTypeSize; i < 4; ++i) {
+ string expected_error;
+ if (i < 2) {
+ expected_error = "Unable to read congestion feedback type.";
+ } else if (i < 4) {
+ expected_error = "Unable to read receive window.";
+ }
+ CheckProcessingFails(
+ packet,
+ i + GetPacketHeaderSize(PACKET_8BYTE_GUID, !kIncludeVersion,
+ PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP),
+ expected_error, QUIC_INVALID_CONGESTION_FEEDBACK_DATA);
+ }
+}
+
+TEST_P(QuicFramerTest, CongestionFeedbackFrameTCPV14) {
+ if (framer_.version() > QUIC_VERSION_14) {
+ return;
+ }
unsigned char packet[] = {
// public flags (8 byte guid)
0x3C,
@@ -1946,6 +2318,102 @@ TEST_P(QuicFramerTest, CongestionFeedbackFrameTCP) {
}
TEST_P(QuicFramerTest, CongestionFeedbackFrameInterArrival) {
+ if (framer_.version() <= QUIC_VERSION_14) {
+ return;
+ }
+ unsigned char packet[] = {
+ // public flags (8 byte guid)
+ 0x3C,
+ // guid
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet sequence number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags
+ 0x00,
+
+ // frame type (congestion feedback frame)
+ 0x20,
+ // congestion feedback type (inter arrival)
+ 0x01,
+ // num received packets
+ 0x03,
+ // lowest sequence number
+ 0xBA, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // receive time
+ 0x87, 0x96, 0xA5, 0xB4,
+ 0xC3, 0xD2, 0xE1, 0x07,
+ // sequence delta
+ 0x01, 0x00,
+ // time delta
+ 0x01, 0x00, 0x00, 0x00,
+ // sequence delta (skip one packet)
+ 0x03, 0x00,
+ // time delta
+ 0x02, 0x00, 0x00, 0x00,
+ };
+
+ QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion));
+
+ EXPECT_EQ(0u, visitor_.stream_frames_.size());
+ ASSERT_EQ(1u, visitor_.congestion_feedback_frames_.size());
+ const QuicCongestionFeedbackFrame& frame =
+ *visitor_.congestion_feedback_frames_[0];
+ ASSERT_EQ(kInterArrival, frame.type);
+ ASSERT_EQ(3u, frame.inter_arrival.received_packet_times.size());
+ TimeMap::const_iterator iter =
+ frame.inter_arrival.received_packet_times.begin();
+ EXPECT_EQ(GG_UINT64_C(0x0123456789ABA), iter->first);
+ EXPECT_EQ(GG_INT64_C(0x07E1D2C3B4A59687),
+ iter->second.Subtract(start_).ToMicroseconds());
+ ++iter;
+ EXPECT_EQ(GG_UINT64_C(0x0123456789ABB), iter->first);
+ EXPECT_EQ(GG_INT64_C(0x07E1D2C3B4A59688),
+ iter->second.Subtract(start_).ToMicroseconds());
+ ++iter;
+ EXPECT_EQ(GG_UINT64_C(0x0123456789ABD), iter->first);
+ EXPECT_EQ(GG_INT64_C(0x07E1D2C3B4A59689),
+ iter->second.Subtract(start_).ToMicroseconds());
+
+ // Now test framing boundaries
+ for (size_t i = kQuicFrameTypeSize; i < 29; ++i) {
+ string expected_error;
+ if (i < 2) {
+ expected_error = "Unable to read congestion feedback type.";
+ } else if (i < 3) {
+ expected_error = "Unable to read num received packets.";
+ } else if (i < 9) {
+ expected_error = "Unable to read smallest received.";
+ } else if (i < 17) {
+ expected_error = "Unable to read time received.";
+ } else if (i < 19) {
+ expected_error = "Unable to read sequence delta in received packets.";
+ } else if (i < 23) {
+ expected_error = "Unable to read time delta in received packets.";
+ } else if (i < 25) {
+ expected_error = "Unable to read sequence delta in received packets.";
+ } else if (i < 29) {
+ expected_error = "Unable to read time delta in received packets.";
+ }
+ CheckProcessingFails(
+ packet,
+ i + GetPacketHeaderSize(PACKET_8BYTE_GUID, !kIncludeVersion,
+ PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP),
+ expected_error, QUIC_INVALID_CONGESTION_FEEDBACK_DATA);
+ }
+}
+
+TEST_P(QuicFramerTest, CongestionFeedbackFrameInterArrivalV14) {
+ if (framer_.version() > QUIC_VERSION_14) {
+ return;
+ }
unsigned char packet[] = {
// public flags (8 byte guid)
0x3C,
@@ -2533,21 +3001,10 @@ TEST_P(QuicFramerTest, PublicResetPacket) {
expected_error = "Unable to read public flags.";
CheckProcessingFails(packet, i, expected_error,
QUIC_INVALID_PACKET_HEADER);
- } else if (i < kPublicResetPacketNonceProofOffset) {
+ } else if (i < kPublicResetPacketMessageTagOffset) {
expected_error = "Unable to read GUID.";
CheckProcessingFails(packet, i, expected_error,
QUIC_INVALID_PACKET_HEADER);
- } else if (i < kPublicResetPacketRejectedSequenceNumberOffset) {
- expected_error = "Unable to read nonce proof.";
- CheckProcessingFails(packet, i, expected_error,
- QUIC_INVALID_PUBLIC_RST_PACKET);
- } else if (i < kPublicResetPacketOldSize) {
- expected_error = "Unable to read rejected sequence number.";
- CheckProcessingFails(packet, i, expected_error,
- QUIC_INVALID_PUBLIC_RST_PACKET);
- } else if (i == kPublicResetPacketOldSize) {
- // This looks like an old public reset packet, so there won't be an
- // error.
} else {
expected_error = "Unable to read reset message.";
CheckProcessingFails(packet, i, expected_error,
@@ -2556,6 +3013,40 @@ TEST_P(QuicFramerTest, PublicResetPacket) {
}
}
+TEST_P(QuicFramerTest, PublicResetPacketWithTrailingJunk) {
+ unsigned char packet[] = {
+ // public flags (public reset, 8 byte guid)
+ 0x0E,
+ // guid
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // message tag (kPRST)
+ 'P', 'R', 'S', 'T',
+ // num_entries (2) + padding
+ 0x02, 0x00, 0x00, 0x00,
+ // tag kRNON
+ 'R', 'N', 'O', 'N',
+ // end offset 8
+ 0x08, 0x00, 0x00, 0x00,
+ // tag kRSEQ
+ 'R', 'S', 'E', 'Q',
+ // end offset 16
+ 0x10, 0x00, 0x00, 0x00,
+ // nonce proof
+ 0x89, 0x67, 0x45, 0x23,
+ 0x01, 0xEF, 0xCD, 0xAB,
+ // rejected sequence number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12, 0x00, 0x00,
+ // trailing junk
+ 'j', 'u', 'n', 'k',
+ };
+
+ string expected_error = "Unable to read reset message.";
+ CheckProcessingFails(packet, arraysize(packet), expected_error,
+ QUIC_INVALID_PUBLIC_RST_PACKET);
+}
+
TEST_P(QuicFramerTest, PublicResetPacketWithClientAddress) {
unsigned char packet[] = {
// public flags (public reset, 8 byte guid)
@@ -2616,21 +3107,10 @@ TEST_P(QuicFramerTest, PublicResetPacketWithClientAddress) {
expected_error = "Unable to read public flags.";
CheckProcessingFails(packet, i, expected_error,
QUIC_INVALID_PACKET_HEADER);
- } else if (i < kPublicResetPacketNonceProofOffset) {
+ } else if (i < kPublicResetPacketMessageTagOffset) {
expected_error = "Unable to read GUID.";
CheckProcessingFails(packet, i, expected_error,
QUIC_INVALID_PACKET_HEADER);
- } else if (i < kPublicResetPacketRejectedSequenceNumberOffset) {
- expected_error = "Unable to read nonce proof.";
- CheckProcessingFails(packet, i, expected_error,
- QUIC_INVALID_PUBLIC_RST_PACKET);
- } else if (i < kPublicResetPacketOldSize) {
- expected_error = "Unable to read rejected sequence number.";
- CheckProcessingFails(packet, i, expected_error,
- QUIC_INVALID_PUBLIC_RST_PACKET);
- } else if (i == kPublicResetPacketOldSize) {
- // This looks like an old public reset packet, so there won't be an
- // error.
} else {
expected_error = "Unable to read reset message.";
CheckProcessingFails(packet, i, expected_error,
@@ -3091,6 +3571,80 @@ TEST_P(QuicFramerTest, BuildVersionNegotiationPacket) {
}
TEST_P(QuicFramerTest, BuildAckFramePacket) {
+ if (version_ <= QUIC_VERSION_14) {
+ return;
+ }
+ QuicPacketHeader header;
+ header.public_header.guid = 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;
+ ack_frame.received_info.entropy_hash = 0x43;
+ ack_frame.received_info.largest_observed = GG_UINT64_C(0x770123456789ABF);
+ ack_frame.received_info.delta_time_largest_observed = QuicTime::Delta::Zero();
+ ack_frame.received_info.missing_packets.insert(
+ GG_UINT64_C(0x770123456789ABE));
+ ack_frame.sent_info.entropy_hash = 0x14;
+ ack_frame.sent_info.least_unacked = GG_UINT64_C(0x770123456789AA0);
+
+ QuicFrames frames;
+ frames.push_back(QuicFrame(&ack_frame));
+
+ unsigned char packet[] = {
+ // public flags (8 byte guid)
+ 0x3C,
+ // guid
+ 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, not truncated, 6 byte largest observed, 1 byte delta)
+ 0x6C,
+ // entropy hash of sent packets till least awaiting - 1.
+ 0x14,
+ // least packet sequence number awaiting an ack, delta from sequence number.
+ 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00,
+ // entropy hash of all received packets.
+ 0x43,
+ // largest observed packet sequence number
+ 0xBF, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // Zero delta time.
+ 0x0, 0x0,
+ // num missing packet ranges
+ 0x01,
+ // missing packet delta
+ 0x01,
+ // 0 more missing packets in range.
+ 0x00,
+ // 0 revived packets.
+ 0x00,
+ };
+
+ scoped_ptr<QuicPacket> data(
+ framer_.BuildUnsizedDataPacket(header, frames).packet);
+ ASSERT_TRUE(data != NULL);
+
+ test::CompareCharArraysWithHexError("constructed packet",
+ data->data(), data->length(),
+ AsChars(packet), arraysize(packet));
+}
+
+TEST_P(QuicFramerTest, BuildAckFramePacketV14) {
+ if (version_ > QUIC_VERSION_14) {
+ return;
+ }
QuicPacketHeader header;
header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210);
header.public_header.reset_flag = false;
@@ -3157,6 +3711,58 @@ TEST_P(QuicFramerTest, BuildAckFramePacket) {
}
TEST_P(QuicFramerTest, BuildCongestionFeedbackFramePacketTCP) {
+ if (version_ <= QUIC_VERSION_14) {
+ return;
+ }
+ QuicPacketHeader header;
+ header.public_header.guid = 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;
+
+ QuicCongestionFeedbackFrame congestion_feedback_frame;
+ congestion_feedback_frame.type = kTCP;
+ congestion_feedback_frame.tcp.receive_window = 0x4030;
+
+ QuicFrames frames;
+ frames.push_back(QuicFrame(&congestion_feedback_frame));
+
+ unsigned char packet[] = {
+ // public flags (8 byte guid)
+ 0x3C,
+ // guid
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet sequence number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags
+ 0x00,
+
+ // frame type (congestion feedback frame)
+ 0x20,
+ // congestion feedback type (TCP)
+ 0x00,
+ // TCP receive window
+ 0x03, 0x04,
+ };
+
+ scoped_ptr<QuicPacket> data(
+ framer_.BuildUnsizedDataPacket(header, frames).packet);
+ ASSERT_TRUE(data != NULL);
+
+ test::CompareCharArraysWithHexError("constructed packet",
+ data->data(), data->length(),
+ AsChars(packet), arraysize(packet));
+}
+
+TEST_P(QuicFramerTest, BuildCongestionFeedbackFramePacketTCPV14) {
+ if (version_ > QUIC_VERSION_14) {
+ return;
+ }
QuicPacketHeader header;
header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210);
header.public_header.reset_flag = false;
@@ -3205,6 +3811,82 @@ TEST_P(QuicFramerTest, BuildCongestionFeedbackFramePacketTCP) {
}
TEST_P(QuicFramerTest, BuildCongestionFeedbackFramePacketInterArrival) {
+ if (version_ <= QUIC_VERSION_14) {
+ return;
+ }
+ QuicPacketHeader header;
+ header.public_header.guid = 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;
+
+ QuicCongestionFeedbackFrame frame;
+ frame.type = kInterArrival;
+ frame.inter_arrival.received_packet_times.insert(
+ make_pair(GG_UINT64_C(0x0123456789ABA),
+ start_.Add(QuicTime::Delta::FromMicroseconds(
+ GG_UINT64_C(0x07E1D2C3B4A59687)))));
+ frame.inter_arrival.received_packet_times.insert(
+ make_pair(GG_UINT64_C(0x0123456789ABB),
+ start_.Add(QuicTime::Delta::FromMicroseconds(
+ GG_UINT64_C(0x07E1D2C3B4A59688)))));
+ frame.inter_arrival.received_packet_times.insert(
+ make_pair(GG_UINT64_C(0x0123456789ABD),
+ start_.Add(QuicTime::Delta::FromMicroseconds(
+ GG_UINT64_C(0x07E1D2C3B4A59689)))));
+ QuicFrames frames;
+ frames.push_back(QuicFrame(&frame));
+
+ unsigned char packet[] = {
+ // public flags (8 byte guid)
+ 0x3C,
+ // guid
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet sequence number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags
+ 0x00,
+
+ // frame type (congestion feedback frame)
+ 0x20,
+ // congestion feedback type (inter arrival)
+ 0x01,
+ // num received packets
+ 0x03,
+ // lowest sequence number
+ 0xBA, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // receive time
+ 0x87, 0x96, 0xA5, 0xB4,
+ 0xC3, 0xD2, 0xE1, 0x07,
+ // sequence delta
+ 0x01, 0x00,
+ // time delta
+ 0x01, 0x00, 0x00, 0x00,
+ // sequence delta (skip one packet)
+ 0x03, 0x00,
+ // time delta
+ 0x02, 0x00, 0x00, 0x00,
+ };
+
+ scoped_ptr<QuicPacket> data(
+ framer_.BuildUnsizedDataPacket(header, frames).packet);
+ ASSERT_TRUE(data != NULL);
+
+ test::CompareCharArraysWithHexError("constructed packet",
+ data->data(), data->length(),
+ AsChars(packet), arraysize(packet));
+}
+
+TEST_P(QuicFramerTest, BuildCongestionFeedbackFramePacketInterArrivalV14) {
+ if (version_ > QUIC_VERSION_14) {
+ return;
+ }
QuicPacketHeader header;
header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210);
header.public_header.reset_flag = false;
@@ -3900,7 +4582,7 @@ TEST_P(QuicFramerTest, Truncation) {
QuicAckFrame ack_frame;
ack_frame.received_info.largest_observed = 601;
- ack_frame.sent_info.least_unacked = 0;
+ ack_frame.sent_info.least_unacked = header.packet_sequence_number - 1;
for (uint64 i = 1; i < ack_frame.received_info.largest_observed; i += 2) {
ack_frame.received_info.missing_packets.insert(i);
}
@@ -3924,7 +4606,8 @@ TEST_P(QuicFramerTest, Truncation) {
ASSERT_TRUE(framer_.ProcessPacket(*ack_packet));
ASSERT_EQ(1u, visitor_.ack_frames_.size());
const QuicAckFrame& processed_ack_frame = *visitor_.ack_frames_[0];
- EXPECT_EQ(0u, processed_ack_frame.sent_info.least_unacked);
+ EXPECT_EQ(header.packet_sequence_number - 1,
+ processed_ack_frame.sent_info.least_unacked);
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());
@@ -3948,7 +4631,7 @@ TEST_P(QuicFramerTest, CleanTruncation) {
QuicAckFrame ack_frame;
ack_frame.received_info.largest_observed = 201;
- ack_frame.sent_info.least_unacked = 0;
+ ack_frame.sent_info.least_unacked = header.packet_sequence_number - 2;
for (uint64 i = 1; i < ack_frame.received_info.largest_observed; ++i) {
ack_frame.received_info.missing_packets.insert(i);
}
diff --git a/net/quic/quic_packet_creator.cc b/net/quic/quic_packet_creator.cc
index 419404e..b399650 100644
--- a/net/quic/quic_packet_creator.cc
+++ b/net/quic/quic_packet_creator.cc
@@ -89,7 +89,9 @@ bool QuicPacketCreator::ShouldSendFec(bool force_close) const {
}
void QuicPacketCreator::MaybeStartFEC() {
- if (options_.max_packets_per_fec_group > 0 && fec_group_.get() == NULL) {
+ // Don't send FEC until QUIC_VERSION_15.
+ if (framer_->version() > QUIC_VERSION_14 &&
+ options_.max_packets_per_fec_group > 0 && 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;
@@ -315,7 +317,7 @@ SerializedPacket QuicPacketCreator::SerializePacket() {
LOG(DFATAL) << "Attempt to serialize empty packet";
}
QuicPacketHeader header;
- FillPacketHeader(fec_group_number_, false, false, &header);
+ FillPacketHeader(fec_group_number_, false, &header);
MaybeAddPadding();
@@ -351,8 +353,7 @@ SerializedPacket QuicPacketCreator::SerializeFec() {
DCHECK_LT(0u, fec_group_->NumReceivedPackets());
DCHECK_EQ(0u, queued_frames_.size());
QuicPacketHeader header;
- FillPacketHeader(fec_group_number_, true,
- fec_group_->entropy_parity(), &header);
+ FillPacketHeader(fec_group_number_, true, &header);
QuicFecData fec_data;
fec_data.fec_group = fec_group_->min_protected_packet();
fec_data.redundancy = fec_group_->payload_parity();
@@ -392,7 +393,6 @@ QuicEncryptedPacket* QuicPacketCreator::SerializeVersionNegotiationPacket(
void QuicPacketCreator::FillPacketHeader(QuicFecGroupNumber fec_group,
bool fec_flag,
- bool fec_entropy_flag,
QuicPacketHeader* header) {
header->public_header.guid = guid_;
header->public_header.reset_flag = false;
@@ -400,16 +400,7 @@ void QuicPacketCreator::FillPacketHeader(QuicFecGroupNumber fec_group,
header->fec_flag = fec_flag;
header->packet_sequence_number = ++sequence_number_;
header->public_header.sequence_number_length = sequence_number_length_;
-
- bool entropy_flag;
- if (fec_flag) {
- // FEC packets don't have an entropy of their own. Entropy flag for FEC
- // packets is the XOR of entropy of previous packets.
- entropy_flag = fec_entropy_flag;
- } else {
- entropy_flag = random_bool_source_->RandBool();
- }
- header->entropy_flag = entropy_flag;
+ header->entropy_flag = random_bool_source_->RandBool();
header->is_in_fec_group = fec_group == 0 ? NOT_IN_FEC_GROUP : IN_FEC_GROUP;
header->fec_group = fec_group;
}
diff --git a/net/quic/quic_packet_creator.h b/net/quic/quic_packet_creator.h
index b6756af..152085e 100644
--- a/net/quic/quic_packet_creator.h
+++ b/net/quic/quic_packet_creator.h
@@ -186,7 +186,6 @@ class NET_EXPORT_PRIVATE QuicPacketCreator : public QuicFecBuilderInterface {
void FillPacketHeader(QuicFecGroupNumber fec_group,
bool fec_flag,
- bool fec_entropy_flag,
QuicPacketHeader* header);
// Allows a frame to be added without creating retransmittable frames.
diff --git a/net/quic/quic_protocol.cc b/net/quic/quic_protocol.cc
index 7ca22b5..51ba4d9 100644
--- a/net/quic/quic_protocol.cc
+++ b/net/quic/quic_protocol.cc
@@ -157,6 +157,8 @@ QuicTag QuicVersionToQuicTag(const QuicVersion version) {
return MakeQuicTag('Q', '0', '1', '3');
case QUIC_VERSION_14:
return MakeQuicTag('Q', '0', '1', '4');
+ case QUIC_VERSION_15:
+ return MakeQuicTag('Q', '0', '1', '5');
default:
// This shold be an ERROR because we should never attempt to convert an
// invalid QuicVersion to be written to the wire.
@@ -186,6 +188,7 @@ string QuicVersionToString(const QuicVersion version) {
RETURN_STRING_LITERAL(QUIC_VERSION_12);
RETURN_STRING_LITERAL(QUIC_VERSION_13);
RETURN_STRING_LITERAL(QUIC_VERSION_14);
+ RETURN_STRING_LITERAL(QUIC_VERSION_15);
default:
return "QUIC_VERSION_UNSUPPORTED";
}
@@ -360,6 +363,12 @@ ostream& operator<<(ostream& os, const ReceivedPacketInfo& received_info) {
it != received_info.missing_packets.end(); ++it) {
os << *it << " ";
}
+ os << " ] revived_packets: [ ";
+ for (SequenceNumberSet::const_iterator it =
+ received_info.revived_packets.begin();
+ it != received_info.revived_packets.end(); ++it) {
+ os << *it << " ";
+ }
os << " ] ";
return os;
}
diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h
index b5cf2b6..8bb89fa 100644
--- a/net/quic/quic_protocol.h
+++ b/net/quic/quic_protocol.h
@@ -256,7 +256,8 @@ enum QuicVersion {
QUIC_VERSION_12 = 12,
QUIC_VERSION_13 = 13,
- QUIC_VERSION_14 = 14, // Current version.
+ QUIC_VERSION_14 = 14,
+ QUIC_VERSION_15 = 15, // Current version.
};
// This vector contains QUIC versions which we currently support.
@@ -266,7 +267,8 @@ enum QuicVersion {
//
// IMPORTANT: if you are addding to this list, follow the instructions at
// http://sites/quic/adding-and-removing-versions
-static const QuicVersion kSupportedQuicVersions[] = {QUIC_VERSION_14,
+static const QuicVersion kSupportedQuicVersions[] = {QUIC_VERSION_15,
+ QUIC_VERSION_14,
QUIC_VERSION_13,
QUIC_VERSION_12};
@@ -608,6 +610,10 @@ struct NET_EXPORT_PRIVATE ReceivedPacketInfo {
// Whether the ack had to be truncated when sent.
bool is_truncated;
+
+ // Packets which have been revived via FEC.
+ // All of these must also be in missing_packets.
+ SequenceNumberSet revived_packets;
};
// True if the sequence number is greater than largest_observed or is listed
diff --git a/net/quic/quic_received_packet_manager.cc b/net/quic/quic_received_packet_manager.cc
index a04ad97..2ebbd97 100644
--- a/net/quic/quic_received_packet_manager.cc
+++ b/net/quic/quic_received_packet_manager.cc
@@ -43,8 +43,7 @@ QuicReceivedPacketManager::~QuicReceivedPacketManager() {}
void QuicReceivedPacketManager::RecordPacketReceived(
QuicByteCount bytes,
const QuicPacketHeader& header,
- QuicTime receipt_time,
- bool revived) {
+ QuicTime receipt_time) {
QuicPacketSequenceNumber sequence_number = header.packet_sequence_number;
DCHECK(IsAwaitingPacket(sequence_number));
@@ -65,11 +64,14 @@ void QuicReceivedPacketManager::RecordPacketReceived(
}
RecordPacketEntropyHash(sequence_number, header.entropy_hash);
- // Don't update the receive algorithm for revived packets.
- if (!revived) {
- receive_algorithm_->RecordIncomingPacket(
- bytes, sequence_number, receipt_time);
- }
+ receive_algorithm_->RecordIncomingPacket(
+ bytes, sequence_number, receipt_time);
+}
+
+void QuicReceivedPacketManager::RecordPacketRevived(
+ QuicPacketSequenceNumber sequence_number) {
+ LOG_IF(DFATAL, !IsAwaitingPacket(sequence_number));
+ received_info_.revived_packets.insert(sequence_number);
}
bool QuicReceivedPacketManager::IsMissing(
@@ -180,22 +182,23 @@ void QuicReceivedPacketManager::RecalculateEntropyHash(
}
void QuicReceivedPacketManager::UpdatePacketInformationReceivedByPeer(
- const QuicAckFrame& incoming_ack) {
+ const ReceivedPacketInfo& received_info) {
// ValidateAck should fail if largest_observed ever shrinks.
- DCHECK_LE(peer_largest_observed_packet_,
- incoming_ack.received_info.largest_observed);
- peer_largest_observed_packet_ = incoming_ack.received_info.largest_observed;
+ DCHECK_LE(peer_largest_observed_packet_, received_info.largest_observed);
+ peer_largest_observed_packet_ = received_info.largest_observed;
- if (incoming_ack.received_info.missing_packets.empty()) {
+ if (received_info.missing_packets.empty()) {
least_packet_awaited_by_peer_ = peer_largest_observed_packet_ + 1;
} else {
- least_packet_awaited_by_peer_ =
- *(incoming_ack.received_info.missing_packets.begin());
+ least_packet_awaited_by_peer_ = *(received_info.missing_packets.begin());
}
}
bool QuicReceivedPacketManager::DontWaitForPacketsBefore(
QuicPacketSequenceNumber least_unacked) {
+ received_info_.revived_packets.erase(
+ received_info_.revived_packets.begin(),
+ received_info_.revived_packets.lower_bound(least_unacked));
size_t missing_packets_count = received_info_.missing_packets.size();
received_info_.missing_packets.erase(
received_info_.missing_packets.begin(),
@@ -204,22 +207,19 @@ bool QuicReceivedPacketManager::DontWaitForPacketsBefore(
}
void QuicReceivedPacketManager::UpdatePacketInformationSentByPeer(
- const QuicAckFrame& incoming_ack) {
+ const SentPacketInfo& sent_info) {
// ValidateAck() should fail if peer_least_packet_awaiting_ack_ shrinks.
- DCHECK_LE(peer_least_packet_awaiting_ack_,
- incoming_ack.sent_info.least_unacked);
- if (incoming_ack.sent_info.least_unacked > peer_least_packet_awaiting_ack_) {
- bool missed_packets =
- DontWaitForPacketsBefore(incoming_ack.sent_info.least_unacked);
- if (missed_packets || incoming_ack.sent_info.least_unacked >
+ DCHECK_LE(peer_least_packet_awaiting_ack_, sent_info.least_unacked);
+ if (sent_info.least_unacked > peer_least_packet_awaiting_ack_) {
+ bool missed_packets = DontWaitForPacketsBefore(sent_info.least_unacked);
+ if (missed_packets || sent_info.least_unacked >
received_info_.largest_observed + 1) {
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(incoming_ack.sent_info.least_unacked,
- incoming_ack.sent_info.entropy_hash);
+ RecalculateEntropyHash(sent_info.least_unacked, sent_info.entropy_hash);
}
- peer_least_packet_awaiting_ack_ = incoming_ack.sent_info.least_unacked;
+ peer_least_packet_awaiting_ack_ = sent_info.least_unacked;
}
DCHECK(received_info_.missing_packets.empty() ||
*received_info_.missing_packets.begin() >=
diff --git a/net/quic/quic_received_packet_manager.h b/net/quic/quic_received_packet_manager.h
index 9e2fb59..e089519 100644
--- a/net/quic/quic_received_packet_manager.h
+++ b/net/quic/quic_received_packet_manager.h
@@ -32,12 +32,11 @@ class NET_EXPORT_PRIVATE QuicReceivedPacketManager :
// bytes: the packet size in bytes including Quic Headers.
// header: the packet header.
// timestamp: the arrival time of the packet.
- // revived: true if the packet was lost and then recovered with help of a
- // FEC packet.
void RecordPacketReceived(QuicByteCount bytes,
const QuicPacketHeader& header,
- QuicTime receipt_time,
- bool revived);
+ QuicTime receipt_time);
+
+ void RecordPacketRevived(QuicPacketSequenceNumber sequence_number);
// Checks whether |sequence_number| is missing and less than largest observed.
bool IsMissing(QuicPacketSequenceNumber sequence_number);
@@ -62,12 +61,11 @@ class NET_EXPORT_PRIVATE QuicReceivedPacketManager :
virtual QuicPacketEntropyHash EntropyHash(
QuicPacketSequenceNumber sequence_number) const OVERRIDE;
- // These two are called by OnAckFrame.
- //
- // Updates internal state based on |incoming_ack.received_info|.
- void UpdatePacketInformationReceivedByPeer(const QuicAckFrame& incoming_ack);
- // Updates internal state based on |incoming_ack.sent_info|.
- void UpdatePacketInformationSentByPeer(const QuicAckFrame& incoming_ack);
+ // Updates internal state based on |received_info|.
+ void UpdatePacketInformationReceivedByPeer(
+ const ReceivedPacketInfo& received_nfo);
+ // Updates internal state based on |sent_info|.
+ void UpdatePacketInformationSentByPeer(const SentPacketInfo& sent_info);
// Returns whether the peer is missing packets.
bool HasMissingPackets();
diff --git a/net/quic/quic_received_packet_manager_test.cc b/net/quic/quic_received_packet_manager_test.cc
index 9d11129..e57a8fe 100644
--- a/net/quic/quic_received_packet_manager_test.cc
+++ b/net/quic/quic_received_packet_manager_test.cc
@@ -28,7 +28,7 @@ class QuicReceivedPacketManagerTest : public ::testing::Test {
QuicPacketHeader header;
header.packet_sequence_number = sequence_number;
header.entropy_hash = entropy_hash;
- received_manager_.RecordPacketReceived(0u, header, QuicTime::Zero(), false);
+ received_manager_.RecordPacketReceived(0u, header, QuicTime::Zero());
}
QuicReceivedPacketManager received_manager_;
@@ -105,9 +105,9 @@ TEST_F(QuicReceivedPacketManagerTest, RecalculateEntropyHash) {
TEST_F(QuicReceivedPacketManagerTest, DontWaitForPacketsBefore) {
QuicPacketHeader header;
header.packet_sequence_number = 2u;
- received_manager_.RecordPacketReceived(0u, header, QuicTime::Zero(), false);
+ received_manager_.RecordPacketReceived(0u, header, QuicTime::Zero());
header.packet_sequence_number = 7u;
- received_manager_.RecordPacketReceived(0u, header, QuicTime::Zero(), false);
+ received_manager_.RecordPacketReceived(0u, header, QuicTime::Zero());
EXPECT_TRUE(received_manager_.IsAwaitingPacket(3u));
EXPECT_TRUE(received_manager_.IsAwaitingPacket(6u));
EXPECT_TRUE(QuicReceivedPacketManagerPeer::DontWaitForPacketsBefore(
@@ -120,7 +120,7 @@ TEST_F(QuicReceivedPacketManagerTest, UpdateReceivedPacketInfo) {
QuicPacketHeader header;
header.packet_sequence_number = 2u;
QuicTime two_ms = QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(2));
- received_manager_.RecordPacketReceived(0u, header, two_ms, false);
+ received_manager_.RecordPacketReceived(0u, header, two_ms);
ReceivedPacketInfo info;
received_manager_.UpdateReceivedPacketInfo(&info, QuicTime::Zero());
diff --git a/net/quic/quic_sent_packet_manager.cc b/net/quic/quic_sent_packet_manager.cc
index 86aba1d..d46ffb98 100644
--- a/net/quic/quic_sent_packet_manager.cc
+++ b/net/quic/quic_sent_packet_manager.cc
@@ -63,6 +63,39 @@ COMPILE_ASSERT(kHistoryPeriodMs >= kBitrateSmoothingPeriodMs,
#define ENDPOINT (is_server_ ? "Server: " : " Client: ")
+
+QuicSentPacketManager::TransmissionInfo::TransmissionInfo()
+ : retransmittable_frames(NULL),
+ sequence_number_length(PACKET_1BYTE_SEQUENCE_NUMBER),
+ sent_time(QuicTime::Zero()),
+ all_transmissions(NULL),
+ pending(false) { }
+
+QuicSentPacketManager::TransmissionInfo::TransmissionInfo(
+ RetransmittableFrames* retransmittable_frames,
+ QuicPacketSequenceNumber sequence_number,
+ QuicSequenceNumberLength sequence_number_length)
+ : retransmittable_frames(retransmittable_frames),
+ sequence_number_length(sequence_number_length),
+ sent_time(QuicTime::Zero()),
+ all_transmissions(new SequenceNumberSet),
+ pending(false) {
+ all_transmissions->insert(sequence_number);
+}
+
+QuicSentPacketManager::TransmissionInfo::TransmissionInfo(
+ RetransmittableFrames* retransmittable_frames,
+ QuicPacketSequenceNumber sequence_number,
+ QuicSequenceNumberLength sequence_number_length,
+ SequenceNumberSet* all_transmissions)
+ : retransmittable_frames(retransmittable_frames),
+ sequence_number_length(sequence_number_length),
+ sent_time(QuicTime::Zero()),
+ all_transmissions(all_transmissions),
+ pending(false) {
+ all_transmissions->insert(sequence_number);
+}
+
QuicSentPacketManager::QuicSentPacketManager(bool is_server,
const QuicClock* clock,
QuicConnectionStats* stats,
@@ -84,10 +117,9 @@ QuicSentPacketManager::~QuicSentPacketManager() {
for (UnackedPacketMap::iterator it = unacked_packets_.begin();
it != unacked_packets_.end(); ++it) {
delete it->second.retransmittable_frames;
- // Only delete previous_transmissions once, for the newest packet.
- if (it->second.previous_transmissions != NULL &&
- it->first == *it->second.previous_transmissions->rbegin()) {
- delete it->second.previous_transmissions;
+ // Only delete all_transmissions once, for the newest packet.
+ if (it->first == *it->second.all_transmissions->rbegin()) {
+ delete it->second.all_transmissions;
}
}
STLDeleteValues(&packet_history_map_);
@@ -126,10 +158,12 @@ void QuicSentPacketManager::OnSerializedPacket(
}
}
+ QuicPacketSequenceNumber sequence_number = serialized_packet.sequence_number;
DCHECK(unacked_packets_.empty() ||
- unacked_packets_.rbegin()->first < serialized_packet.sequence_number);
- unacked_packets_[serialized_packet.sequence_number] =
+ unacked_packets_.rbegin()->first < sequence_number);
+ unacked_packets_[sequence_number] =
TransmissionInfo(serialized_packet.retransmittable_frames,
+ serialized_packet.sequence_number,
serialized_packet.sequence_number_length);
}
@@ -157,21 +191,9 @@ void QuicSentPacketManager::OnRetransmittedPacket(
// the retransmissions of it are acked.
transmission_info->retransmittable_frames = NULL;
unacked_packets_[new_sequence_number] =
- TransmissionInfo(frames, transmission_info->sequence_number_length);
-
- // Keep track of all sequence numbers that this packet
- // has been transmitted as.
- SequenceNumberSet* previous_transmissions =
- transmission_info->previous_transmissions;
- if (previous_transmissions == NULL) {
- // This is the first retransmission of this packet, so create a new entry.
- previous_transmissions = new SequenceNumberSet;
- transmission_info->previous_transmissions = previous_transmissions;
- previous_transmissions->insert(old_sequence_number);
- }
- previous_transmissions->insert(new_sequence_number);
- unacked_packets_[new_sequence_number].previous_transmissions =
- previous_transmissions;
+ TransmissionInfo(frames, new_sequence_number,
+ transmission_info->sequence_number_length,
+ transmission_info->all_transmissions);
}
bool QuicSentPacketManager::OnIncomingAck(
@@ -230,6 +252,26 @@ void QuicSentPacketManager::HandleAckForSentPackets(
ack_notifier_manager_.OnPacketAcked(sequence_number);
}
+ // Discard any retransmittable frames associated with revived packets.
+ for (SequenceNumberSet::const_iterator revived_it =
+ received_info.revived_packets.begin();
+ revived_it != received_info.revived_packets.end(); ++revived_it) {
+ TransmissionInfo* transmission_info =
+ FindOrNull(unacked_packets_, *revived_it);
+ if (transmission_info == NULL) {
+ continue;
+ }
+ // The retransmittable frames are removed from the most recent transmission.
+ transmission_info =
+ FindOrNull(unacked_packets_,
+ *transmission_info->all_transmissions->rbegin());
+ if (transmission_info->retransmittable_frames == NULL) {
+ continue;
+ }
+ delete transmission_info->retransmittable_frames;
+ transmission_info->retransmittable_frames = NULL;
+ }
+
// 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.
@@ -242,37 +284,15 @@ void QuicSentPacketManager::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 not a previous transmission then there is no point
- // in clearing out any further packets, because it will not affect
- // the high water mark.
- SequenceNumberSet* previous_transmissions =
- it->second.previous_transmissions;
- if (previous_transmissions == NULL) {
- if (it->second.retransmittable_frames == NULL) {
- // This is a current transmission, but a previous transmission has
- // been acked, so it's safe to remove.
- it = MarkPacketHandled(sequence_number, NOT_RECEIVED_BY_PEER);
- --num_to_clear;
- continue;
- }
- break;
- }
- QuicPacketSequenceNumber newest_transmission =
- *previous_transmissions->rbegin();
- if (sequence_number == newest_transmission) {
- break;
- }
- if (it->second.pending) {
+ // If this is a pending packet, 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) {
break;
}
- DCHECK(it->second.retransmittable_frames == NULL);
- previous_transmissions->erase(sequence_number);
- if (previous_transmissions->size() == 1) {
- unacked_packets_[newest_transmission].previous_transmissions = NULL;
- delete previous_transmissions;
- }
- unacked_packets_.erase(it++);
+ ++it;
+ RemovePacket(sequence_number);
--num_to_clear;
}
}
@@ -296,7 +316,7 @@ void QuicSentPacketManager::RetransmitUnackedPackets(
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.previous_transmissions == NULL &&
+ if (frames == NULL && unacked_it->second.all_transmissions->size() == 1 &&
retransmission_type == ALL_PACKETS) {
unacked_it = MarkPacketHandled(unacked_it->first, NOT_RECEIVED_BY_PEER);
continue;
@@ -368,11 +388,14 @@ bool QuicSentPacketManager::HasCryptoHandshake(
QuicSentPacketManager::UnackedPacketMap::iterator
QuicSentPacketManager::MarkPacketHandled(
- QuicPacketSequenceNumber sequence_number, ReceivedByPeer received_by_peer) {
- DCHECK(ContainsKey(unacked_packets_, sequence_number));
-
- // If this packet is pending, remove it and inform the send algorithm.
+ QuicPacketSequenceNumber sequence_number,
+ ReceivedByPeer received_by_peer) {
UnackedPacketMap::iterator it = unacked_packets_.find(sequence_number);
+ if (it == unacked_packets_.end()) {
+ LOG(DFATAL) << "Packet is not unacked: " << sequence_number;
+ return it;
+ }
+ // If this packet is pending, remove it and inform the send algorithm.
if (it->second.pending) {
size_t bytes_sent = packet_history_map_[sequence_number]->bytes_sent();
if (received_by_peer == RECEIVED_BY_PEER) {
@@ -384,69 +407,52 @@ QuicSentPacketManager::MarkPacketHandled(
it->second.pending = false;
}
- // If this packet has never been retransmitted, then simply drop it.
- if (it->second.previous_transmissions == NULL) {
- ++it;
- DiscardPacket(sequence_number);
- return it;
- }
-
- SequenceNumberSet* previous_transmissions = it->second.previous_transmissions;
- DCHECK(!previous_transmissions->empty());
- SequenceNumberSet::reverse_iterator previous_transmissions_it =
- previous_transmissions->rbegin();
- QuicPacketSequenceNumber newest_transmission = *previous_transmissions_it;
- TransmissionInfo* transmission_info =
- FindOrNull(unacked_packets_, newest_transmission);
+ SequenceNumberSet* all_transmissions = it->second.all_transmissions;
+ DCHECK(!all_transmissions->empty());
+ SequenceNumberSet::reverse_iterator all_transmissions_it =
+ all_transmissions->rbegin();
+ QuicPacketSequenceNumber newest_transmission = *all_transmissions_it;
if (newest_transmission != sequence_number) {
++stats_->packets_spuriously_retransmitted;
}
- if (newest_transmission == sequence_number) {
- DiscardPacket(newest_transmission);
- } else if (HasCryptoHandshake(*transmission_info)) {
- // If it's a crypto handshake packet, discard it and all retransmissions,
- // since they won't be acked now that one has been processed.
- if (transmission_info->pending) {
- OnPacketAbandoned(unacked_packets_.find(newest_transmission));
+
+ bool has_cryto_handshake = HasCryptoHandshake(
+ *FindOrNull(unacked_packets_, newest_transmission));
+ if (has_cryto_handshake) {
+ --pending_crypto_packet_count_;
+ }
+ while (all_transmissions_it != all_transmissions->rend()) {
+ QuicPacketSequenceNumber previous_transmission = *all_transmissions_it;
+ TransmissionInfo* transmission_info =
+ FindOrNull(unacked_packets_, previous_transmission);
+ if (transmission_info->retransmittable_frames != NULL) {
+ // Since some version of this packet has been acked, ensure that
+ // the data is not retransmitted again.
+ delete transmission_info->retransmittable_frames;
+ transmission_info->retransmittable_frames = NULL;
}
- DiscardPacket(newest_transmission);
- } else {
- // If we have received an ack for a previous transmission of a packet,
- // we want to keep the "new" transmission of the packet unacked,
- // but prevent the data from being retransmitted.
- delete transmission_info->retransmittable_frames;
- transmission_info->retransmittable_frames = NULL;
- transmission_info->previous_transmissions = NULL;
- }
-
- // Clear out information all previous transmissions unless they're pending.
- ++previous_transmissions_it;
- while (previous_transmissions_it != previous_transmissions->rend()) {
- QuicPacketSequenceNumber previous_transmission = *previous_transmissions_it;
- ++previous_transmissions_it;
- // If the packet was TLP retransmitted, the old copy is still pending.
- // Keep it until it is lost or acked.
- if (unacked_packets_[previous_transmission].pending) {
- // Previous transmissions will be deleted, so set it to NULL.
- unacked_packets_[previous_transmission].previous_transmissions = NULL;
- } else {
- DiscardPacket(previous_transmission);
+ if (ContainsKey(pending_retransmissions_, previous_transmission)) {
+ // Don't bother retransmitting this packet, if it has been
+ // marked for retransmission.
+ pending_retransmissions_.erase(previous_transmission);
}
- }
-
- delete previous_transmissions;
-
- if (ContainsKey(pending_retransmissions_, newest_transmission)) {
- pending_retransmissions_.erase(newest_transmission);
- if (!unacked_packets_[newest_transmission].pending) {
- // If the newest transmission has already been marked for retransmission
- // and has already been abandoned, then we should remove it from
- // unacked_packets_, as well as cancel the retransmission.
- DCHECK(ContainsKey(unacked_packets_, newest_transmission));
- DCHECK(!unacked_packets_[newest_transmission].previous_transmissions);
- unacked_packets_.erase(newest_transmission);
+ if (has_cryto_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.
+ if (transmission_info->pending) {
+ OnPacketAbandoned(unacked_packets_.find(newest_transmission));
+ }
+ transmission_info->pending = false;
+ }
+ if (!transmission_info->pending) {
+ unacked_packets_.erase(previous_transmission);
+ } else {
+ transmission_info->all_transmissions = new SequenceNumberSet;
+ transmission_info->all_transmissions->insert(previous_transmission);
}
+ ++all_transmissions_it;
}
+ delete all_transmissions;
UnackedPacketMap::iterator next_unacked = unacked_packets_.begin();
while (next_unacked != unacked_packets_.end() &&
@@ -456,25 +462,19 @@ QuicSentPacketManager::MarkPacketHandled(
return next_unacked;
}
-void QuicSentPacketManager::DiscardPacket(
+void QuicSentPacketManager::RemovePacket(
QuicPacketSequenceNumber sequence_number) {
- UnackedPacketMap::iterator unacked_it =
- unacked_packets_.find(sequence_number);
- DCHECK(unacked_it != unacked_packets_.end());
- // Ensure the packet is no longer pending when it's discarded.
- DCHECK(!unacked_it->second.pending);
-
- RetransmittableFrames* retransmittable_frames =
- unacked_it->second.retransmittable_frames;
- if (HasCryptoHandshake(unacked_it->second)) {
- --pending_crypto_packet_count_;
+ UnackedPacketMap::iterator it = unacked_packets_.find(sequence_number);
+ if (it == unacked_packets_.end()) {
+ LOG(DFATAL) << "packet is not unacked: " << sequence_number;
+ return;
}
-
- // Delete the retransmittable frames.
- delete retransmittable_frames;
- unacked_packets_.erase(unacked_it);
- pending_retransmissions_.erase(sequence_number);
- return;
+ const TransmissionInfo& transmission_info = it->second;
+ transmission_info.all_transmissions->erase(sequence_number);
+ if (transmission_info.all_transmissions->empty()) {
+ delete transmission_info.all_transmissions;
+ }
+ unacked_packets_.erase(it);
}
bool QuicSentPacketManager::IsUnacked(
@@ -546,7 +546,7 @@ bool QuicSentPacketManager::OnPacketSent(
transmission_type,
has_retransmittable_data)) {
DCHECK(it->second.retransmittable_frames == NULL);
- unacked_packets_.erase(it);
+ RemovePacket(sequence_number);
// Do not reset the retransmission timer, since the packet isn't tracked.
return false;
}
@@ -755,8 +755,8 @@ void QuicSentPacketManager::MaybeRetransmitOnAckFrame(
// unacked_packets_. This is either the current transmission of
// a packet whose previous transmission has been acked, or it
// is a packet that has been TLP retransmitted.
- RemovePreviousTransmission(sequence_number);
- unacked_packets_.erase(it++);
+ ++it;
+ RemovePacket(sequence_number);
}
}
}
@@ -961,19 +961,4 @@ void QuicSentPacketManager::MaybeEnablePacing() {
QuicTime::Delta::FromMicroseconds(1)));
}
-void QuicSentPacketManager::RemovePreviousTransmission(
- QuicPacketSequenceNumber sequence_number) {
- SequenceNumberSet* previous_transmissions =
- unacked_packets_[sequence_number].previous_transmissions;
- if (!previous_transmissions) {
- return;
- }
- previous_transmissions->erase(sequence_number);
- if (previous_transmissions->size() == 1) {
- QuicPacketSequenceNumber current = *previous_transmissions->begin();
- unacked_packets_[current].previous_transmissions = NULL;
- delete previous_transmissions;
- }
-}
-
} // namespace net
diff --git a/net/quic/quic_sent_packet_manager.h b/net/quic/quic_sent_packet_manager.h
index e767288..206a0da 100644
--- a/net/quic/quic_sent_packet_manager.h
+++ b/net/quic/quic_sent_packet_manager.h
@@ -189,29 +189,29 @@ class NET_EXPORT_PRIVATE QuicSentPacketManager {
HANDSHAKE_MODE,
};
- struct TransmissionInfo {
- TransmissionInfo()
- : retransmittable_frames(NULL),
- sequence_number_length(PACKET_1BYTE_SEQUENCE_NUMBER),
- sent_time(QuicTime::Zero()),
- previous_transmissions(NULL),
- pending(false) { }
+ struct NET_EXPORT_PRIVATE TransmissionInfo {
+ TransmissionInfo();
+
+ // Constructs a Transmission with a new all_tranmissions set
+ // containing |sequence_number|.
+ TransmissionInfo(RetransmittableFrames* retransmittable_frames,
+ QuicPacketSequenceNumber sequence_number,
+ QuicSequenceNumberLength sequence_number_length);
+
+ // Constructs a Transmission with the specified |all_tranmissions| set
+ // and inserts |sequence_number| into it.
TransmissionInfo(RetransmittableFrames* retransmittable_frames,
- QuicSequenceNumberLength sequence_number_length)
- : retransmittable_frames(retransmittable_frames),
- sequence_number_length(sequence_number_length),
- sent_time(QuicTime::Zero()),
- previous_transmissions(NULL),
- pending(false) {
- }
+ QuicPacketSequenceNumber sequence_number,
+ QuicSequenceNumberLength sequence_number_length,
+ SequenceNumberSet* all_transmissions);
RetransmittableFrames* retransmittable_frames;
QuicSequenceNumberLength sequence_number_length;
// Zero when the packet is serialized, non-zero once it's sent.
QuicTime sent_time;
- // Stores all previous transmissions if the packet has been retransmitted,
- // and is NULL otherwise.
- SequenceNumberSet* previous_transmissions;
+ // 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;
};
@@ -271,7 +271,7 @@ class NET_EXPORT_PRIVATE QuicSentPacketManager {
ReceivedByPeer received_by_peer);
// Removes entries from the unacked packet map.
- void DiscardPacket(QuicPacketSequenceNumber sequence_number);
+ void RemovePacket(QuicPacketSequenceNumber sequence_number);
// Request that |sequence_number| be retransmitted after the other pending
// retransmissions. Does not add it to the retransmissions if it's already
@@ -285,9 +285,6 @@ class NET_EXPORT_PRIVATE QuicSentPacketManager {
void CleanupPacketHistory();
- // Removes |sequence_number| as a previous transmission of any other packets.
- void RemovePreviousTransmission(QuicPacketSequenceNumber sequence_number);
-
// Newly serialized retransmittable and fec packets are added to this map,
// which contains owning pointers to any contained frames. If a packet is
// retransmitted, this map will contain entries for both the old and the new
diff --git a/net/quic/quic_sent_packet_manager_test.cc b/net/quic/quic_sent_packet_manager_test.cc
index a8e181a..939a5d3 100644
--- a/net/quic/quic_sent_packet_manager_test.cc
+++ b/net/quic/quic_sent_packet_manager_test.cc
@@ -149,6 +149,16 @@ class QuicSentPacketManagerTest : public ::testing::TestWithParam<bool> {
HAS_RETRANSMITTABLE_DATA);
}
+ void SendFecPacket(QuicPacketSequenceNumber sequence_number) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, sequence_number, _, _, _))
+ .Times(1).WillOnce(Return(true));
+ SerializedPacket packet(CreateFecPacket(sequence_number));
+ manager_.OnSerializedPacket(packet);
+ manager_.OnPacketSent(sequence_number, clock_.ApproximateNow(),
+ packet.packet->length(), NOT_RETRANSMISSION,
+ NO_RETRANSMITTABLE_DATA);
+ }
+
// Based on QuicConnection's WritePendingRetransmissions.
void RetransmitNextPacket(
QuicPacketSequenceNumber retransmission_sequence_number) {
@@ -250,9 +260,8 @@ TEST_F(QuicSentPacketManagerTest, RetransmitThenAckPrevious) {
received_info.largest_observed = 1;
EXPECT_TRUE(manager_.OnIncomingAck(received_info, clock_.ApproximateNow()));
- // 2 remains unacked, but no packets have retransmittable data.
- QuicPacketSequenceNumber unacked[] = { 2 };
- VerifyUnackedPackets(unacked, arraysize(unacked));
+ // No packets should be unacked.
+ VerifyUnackedPackets(NULL, 0);
EXPECT_FALSE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_));
VerifyRetransmittablePackets(NULL, 0);
@@ -262,6 +271,28 @@ TEST_F(QuicSentPacketManagerTest, RetransmitThenAckPrevious) {
EXPECT_EQ(1u, stats_.packets_spuriously_retransmitted);
}
+TEST_F(QuicSentPacketManagerTest, RetransmitAndSendThenAckPrevious) {
+ SendDataPacket(1);
+ RetransmitAndSendPacket(1, 2);
+ QuicTime::Delta rtt = QuicTime::Delta::FromMilliseconds(15);
+ clock_.AdvanceTime(rtt);
+
+ // Ack 1 but not 2.
+ EXPECT_CALL(*send_algorithm_, UpdateRtt(rtt));
+ EXPECT_CALL(*send_algorithm_, OnPacketAcked(1, _));
+ ReceivedPacketInfo received_info;
+ received_info.largest_observed = 1;
+ EXPECT_TRUE(manager_.OnIncomingAck(received_info, clock_.ApproximateNow()));
+
+ // 2 remains unacked, but no packets have retransmittable data.
+ QuicPacketSequenceNumber unacked[] = { 2 };
+ VerifyUnackedPackets(unacked, arraysize(unacked));
+ EXPECT_TRUE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_));
+ VerifyRetransmittablePackets(NULL, 0);
+
+ EXPECT_EQ(1u, stats_.packets_spuriously_retransmitted);
+}
+
TEST_F(QuicSentPacketManagerTest, RetransmitThenAckPreviousThenNackRetransmit) {
SendDataPacket(1);
RetransmitPacket(1, 2);
@@ -386,6 +417,40 @@ TEST_F(QuicSentPacketManagerTest, RetransmitTwiceThenAckFirst) {
EXPECT_EQ(1u, stats_.packets_spuriously_retransmitted);
}
+TEST_F(QuicSentPacketManagerTest, LoseButDontRetransmitRevivedPacket) {
+ SendDataPacket(1);
+ SendDataPacket(2);
+ SendFecPacket(3);
+ SendDataPacket(4);
+
+ // Ack 2 and 3, and mark 1 as revived.
+ ReceivedPacketInfo received_info;
+ received_info.largest_observed = 3;
+ received_info.missing_packets.insert(1);
+ received_info.revived_packets.insert(1);
+ EXPECT_CALL(*send_algorithm_, UpdateRtt(_));
+ EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(2);
+ manager_.OnIncomingAck(received_info, clock_.ApproximateNow());
+
+ EXPECT_FALSE(manager_.HasPendingRetransmissions());
+ QuicPacketSequenceNumber unacked[] = { 1, 4 };
+ VerifyUnackedPackets(unacked, arraysize(unacked));
+ EXPECT_TRUE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_));
+ QuicPacketSequenceNumber retransmittable[] = { 4 };
+ VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable));
+
+ // Ack the 4th packet and expect the 1st to be considered lost.
+ received_info.largest_observed = 4;
+ EXPECT_CALL(*send_algorithm_, UpdateRtt(_));
+ EXPECT_CALL(*send_algorithm_, OnPacketLost(1, _));
+ EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(1, _));
+ EXPECT_CALL(*send_algorithm_, OnPacketAcked(4, _));
+ manager_.OnIncomingAck(received_info, clock_.ApproximateNow());
+
+ EXPECT_FALSE(manager_.HasPendingRetransmissions());
+ VerifyRetransmittablePackets(NULL, 0);
+}
+
TEST_F(QuicSentPacketManagerTest, TruncatedAck) {
SendDataPacket(1);
RetransmitAndSendPacket(1, 2);
@@ -445,13 +510,13 @@ TEST_F(QuicSentPacketManagerTest, AckPreviousTransmissionThenTruncatedAck) {
received_info.missing_packets.insert(6);
received_info.is_truncated = true;
EXPECT_CALL(*send_algorithm_, OnPacketAcked(1, _));
+ EXPECT_CALL(*send_algorithm_, OnPacketLost(3, _));
EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(3, _));
- EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(4, _));
manager_.OnIncomingAck(received_info, QuicTime::Zero());
}
// High water mark will be raised.
- QuicPacketSequenceNumber unacked[] = { 5, 6, 7, 8, 9 };
+ QuicPacketSequenceNumber unacked[] = { 4, 5, 6, 7, 8, 9 };
VerifyUnackedPackets(unacked, arraysize(unacked));
QuicPacketSequenceNumber retransmittable[] = { 5, 6, 7, 8, 9 };
VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable));
diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc
index 9c73fd9..a7de3fd 100644
--- a/net/quic/quic_session.cc
+++ b/net/quic/quic_session.cc
@@ -241,7 +241,7 @@ void QuicSession::OnRstStream(const QuicRstStreamFrame& frame) {
QUIC_STREAM_RST_BEFORE_HEADERS_DECOMPRESSED);
}
}
- stream->OnStreamReset(frame.error_code);
+ stream->OnStreamReset(frame);
}
void QuicSession::OnGoAway(const QuicGoAwayFrame& frame) {
diff --git a/net/quic/quic_session_test.cc b/net/quic/quic_session_test.cc
index 21cbd60..4de8d2a 100644
--- a/net/quic/quic_session_test.cc
+++ b/net/quic/quic_session_test.cc
@@ -175,6 +175,8 @@ class QuicSessionTest : public ::testing::TestWithParam<QuicVersion> {
closed_streams_.insert(id);
}
+ QuicVersion version() const { return connection_->version(); }
+
MockConnection* connection_;
TestSession session_;
set<QuicStreamId> closed_streams_;
@@ -216,7 +218,7 @@ TEST_P(QuicSessionTest, IsClosedStreamLocallyCreated) {
EXPECT_EQ(2u, stream2->id());
TestStream* stream4 = session_.CreateOutgoingDataStream();
EXPECT_EQ(4u, stream4->id());
- if (GetParam() <= QUIC_VERSION_12) {
+ if (version() <= QUIC_VERSION_12) {
QuicDataStreamPeer::SetHeadersDecompressed(stream2, true);
QuicDataStreamPeer::SetHeadersDecompressed(stream4, true);
}
@@ -229,7 +231,7 @@ TEST_P(QuicSessionTest, IsClosedStreamLocallyCreated) {
}
TEST_P(QuicSessionTest, IsClosedStreamPeerCreated) {
- QuicStreamId stream_id1 = GetParam() > QUIC_VERSION_12 ? 5 : 3;
+ QuicStreamId stream_id1 = version() > QUIC_VERSION_12 ? 5 : 3;
QuicStreamId stream_id2 = stream_id1 + 2;
QuicDataStream* stream1 = session_.GetIncomingDataStream(stream_id1);
QuicDataStreamPeer::SetHeadersDecompressed(stream1, true);
@@ -250,14 +252,14 @@ TEST_P(QuicSessionTest, IsClosedStreamPeerCreated) {
}
TEST_P(QuicSessionTest, StreamIdTooLarge) {
- QuicStreamId stream_id = GetParam() > QUIC_VERSION_12 ? 5 : 3;
+ QuicStreamId stream_id = version() > QUIC_VERSION_12 ? 5 : 3;
session_.GetIncomingDataStream(stream_id);
EXPECT_CALL(*connection_, SendConnectionClose(QUIC_INVALID_STREAM_ID));
session_.GetIncomingDataStream(stream_id + 102);
}
TEST_P(QuicSessionTest, DecompressionError) {
- if (GetParam() > QUIC_VERSION_12) {
+ if (version() > QUIC_VERSION_12) {
QuicHeadersStream* stream = QuicSessionPeer::GetHeadersStream(&session_);
const unsigned char data[] = {
0x80, 0x03, 0x00, 0x01, // SPDY/3 SYN_STREAM frame
@@ -493,10 +495,10 @@ TEST_P(QuicSessionTest, IncreasedTimeoutAfterCryptoHandshake) {
}
TEST_P(QuicSessionTest, ZombieStream) {
- QuicStreamId stream_id1 = GetParam() > QUIC_VERSION_12 ? 5 : 3;
+ QuicStreamId stream_id1 = version() > QUIC_VERSION_12 ? 5 : 3;
QuicStreamId stream_id2 = stream_id1 + 2;
StrictMock<MockConnection>* connection =
- new StrictMock<MockConnection>(false, SupportedVersions(GetParam()));
+ new StrictMock<MockConnection>(false, SupportedVersions(version()));
TestSession session(connection);
TestStream* stream1 = session.CreateOutgoingDataStream();
@@ -535,10 +537,10 @@ TEST_P(QuicSessionTest, ZombieStream) {
}
TEST_P(QuicSessionTest, ZombieStreamConnectionClose) {
- QuicStreamId stream_id1 = GetParam() > QUIC_VERSION_12 ? 5 : 3;
+ QuicStreamId stream_id1 = version() > QUIC_VERSION_12 ? 5 : 3;
QuicStreamId stream_id2 = stream_id1 + 2;
StrictMock<MockConnection>* connection =
- new StrictMock<MockConnection>(false, SupportedVersions(GetParam()));
+ new StrictMock<MockConnection>(false, SupportedVersions(version()));
TestSession session(connection);
TestStream* stream1 = session.CreateOutgoingDataStream();
@@ -562,7 +564,7 @@ TEST_P(QuicSessionTest, ZombieStreamConnectionClose) {
}
TEST_P(QuicSessionTest, RstStreamBeforeHeadersDecompressed) {
- QuicStreamId stream_id1 = GetParam() > QUIC_VERSION_12 ? 5 : 3;
+ QuicStreamId stream_id1 = version() > QUIC_VERSION_12 ? 5 : 3;
// Send two bytes of payload.
QuicStreamFrame data1(stream_id1, false, 0, MakeIOVector("HT"));
vector<QuicStreamFrame> frames;
@@ -570,7 +572,7 @@ TEST_P(QuicSessionTest, RstStreamBeforeHeadersDecompressed) {
EXPECT_TRUE(session_.OnStreamFrames(frames));
EXPECT_EQ(1u, session_.GetNumOpenStreams());
- if (GetParam() <= QUIC_VERSION_12) {
+ if (version() <= QUIC_VERSION_12) {
// Send a reset before the headers have been decompressed. This causes
// an unrecoverable compression context state.
EXPECT_CALL(*connection_, SendConnectionClose(
diff --git a/net/quic/reliable_quic_stream.cc b/net/quic/reliable_quic_stream.cc
index fd32984..b032b5a 100644
--- a/net/quic/reliable_quic_stream.cc
+++ b/net/quic/reliable_quic_stream.cc
@@ -72,8 +72,8 @@ bool ReliableQuicStream::OnStreamFrame(const QuicStreamFrame& frame) {
return accepted;
}
-void ReliableQuicStream::OnStreamReset(QuicRstStreamErrorCode error) {
- stream_error_ = error;
+void ReliableQuicStream::OnStreamReset(const QuicRstStreamFrame& frame) {
+ stream_error_ = frame.error_code;
CloseWriteSide();
CloseReadSide();
}
diff --git a/net/quic/reliable_quic_stream.h b/net/quic/reliable_quic_stream.h
index 822baeb..bc1798d 100644
--- a/net/quic/reliable_quic_stream.h
+++ b/net/quic/reliable_quic_stream.h
@@ -51,7 +51,7 @@ class NET_EXPORT_PRIVATE ReliableQuicStream {
virtual void OnClose();
// Called when we get a stream reset from the peer.
- virtual void OnStreamReset(QuicRstStreamErrorCode error);
+ virtual void OnStreamReset(const QuicRstStreamFrame& frame);
// Called when we get or send a connection close, and should immediately
// close the stream. This is not passed through the sequencer,
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 772497c..edbc52b 100644
--- a/net/quic/test_tools/quic_sent_packet_manager_peer.cc
+++ b/net/quic/test_tools/quic_sent_packet_manager_peer.cc
@@ -68,7 +68,7 @@ bool QuicSentPacketManagerPeer::IsRetransmission(
DCHECK(sent_packet_manager->HasRetransmittableFrames(sequence_number));
return sent_packet_manager->HasRetransmittableFrames(sequence_number) &&
sent_packet_manager->
- unacked_packets_[sequence_number].previous_transmissions != NULL;
+ unacked_packets_[sequence_number].all_transmissions->size() > 1;
}
// static