Land Recent QUIC Changes.
Remove unused QuicDecrypter::Decrypt method and implementations.
Merge internal change: 84548556
https://codereview.chromium.org/868953002/
Changed verify_details_ check to verify_details_.get() to keep code in
sync with internal source.
Merge internal change: 84442484
https://codereview.chromium.org/872483002/
Removing an obselete TOOD. It is obselte becasue FrameOverlapsBufferedData
does this.
Merge internal change: 84372263
https://codereview.chromium.org/871733002/
Replace the map in QuicAckNotifier with a counter.
No functionality change.
This reduces memory and CPU usage of the ack notifier.
Merge internal change: 84345868
https://codereview.chromium.org/867033002/
Change some of QUIC's AckNotifier datastructures from maps to hashmaps
and sets to lists. No behavior change.
This should reduce CPU consumption substantially, particularly on
internal servers.
Merge internal change: 84156430
https://codereview.chromium.org/870733002/
Add a new RTO connection option to QUIC. Flag protected behind the
existing flag FLAGS_quic_use_new_rto.
This new RTO connection option uses loss detection to reduce the
congestion window after an RTO, instead of always reducing the
CWND to 2.
Merge internal change: 84036848
https://codereview.chromium.org/824693007/
QUIC - sync'ing with internal source tree changes.
Minor change to keep the code similar to chromium and internal tree.
Merge internal change: 83993217
https://codereview.chromium.org/870723002/
Fix a bug in QUIC's RTO. Flag protected by FLAGS_quic_use_new_rto.
Ensures a beta based loss reduction is not triggered directly before
OnRetransmissionTimeout when recovering from RTO.
Merge internal change: 83986840
https://codereview.chromium.org/868813003/
[email protected]
Review URL: https://codereview.chromium.org/868993002
Cr-Commit-Position: refs/heads/master@{#313081}
diff --git a/net/quic/crypto/aead_base_decrypter.h b/net/quic/crypto/aead_base_decrypter.h
index 5118b11..1aeb6713 100644
--- a/net/quic/crypto/aead_base_decrypter.h
+++ b/net/quic/crypto/aead_base_decrypter.h
@@ -42,11 +42,6 @@
// QuicDecrypter implementation
bool SetKey(base::StringPiece key) override;
bool SetNoncePrefix(base::StringPiece nonce_prefix) override;
- bool Decrypt(base::StringPiece nonce,
- base::StringPiece associated_data,
- base::StringPiece ciphertext,
- unsigned char* output,
- size_t* output_length) override;
QuicData* DecryptPacket(QuicPacketSequenceNumber sequence_number,
base::StringPiece associated_data,
base::StringPiece ciphertext) override;
@@ -80,6 +75,12 @@
#endif // !defined(USE_OPENSSL)
private:
+ bool Decrypt(base::StringPiece nonce,
+ base::StringPiece associated_data,
+ base::StringPiece ciphertext,
+ unsigned char* output,
+ size_t* output_length);
+
#if defined(USE_OPENSSL)
const EVP_AEAD* const aead_alg_;
#else
diff --git a/net/quic/crypto/aes_128_gcm_12_decrypter_test.cc b/net/quic/crypto/aes_128_gcm_12_decrypter_test.cc
index 037bf7e..377d2b5 100644
--- a/net/quic/crypto/aes_128_gcm_12_decrypter_test.cc
+++ b/net/quic/crypto/aes_128_gcm_12_decrypter_test.cc
@@ -257,15 +257,13 @@
StringPiece nonce,
StringPiece associated_data,
StringPiece ciphertext) {
- size_t plaintext_size = ciphertext.length();
- scoped_ptr<char[]> plaintext(new char[plaintext_size]);
-
- if (!decrypter->Decrypt(nonce, associated_data, ciphertext,
- reinterpret_cast<unsigned char*>(plaintext.get()),
- &plaintext_size)) {
- return nullptr;
- }
- return new QuicData(plaintext.release(), plaintext_size, true);
+ QuicPacketSequenceNumber sequence_number;
+ StringPiece nonce_prefix(nonce.data(),
+ nonce.size() - sizeof(sequence_number));
+ decrypter->SetNoncePrefix(nonce_prefix);
+ memcpy(&sequence_number, nonce.data() + nonce_prefix.size(),
+ sizeof(sequence_number));
+ return decrypter->DecryptPacket(sequence_number, associated_data, ciphertext);
}
TEST(Aes128Gcm12DecrypterTest, Decrypt) {
diff --git a/net/quic/crypto/chacha20_poly1305_decrypter_test.cc b/net/quic/crypto/chacha20_poly1305_decrypter_test.cc
index 312e2d4..54ca9ff4 100644
--- a/net/quic/crypto/chacha20_poly1305_decrypter_test.cc
+++ b/net/quic/crypto/chacha20_poly1305_decrypter_test.cc
@@ -75,15 +75,13 @@
StringPiece nonce,
StringPiece associated_data,
StringPiece ciphertext) {
- size_t plaintext_size = ciphertext.length();
- scoped_ptr<char[]> plaintext(new char[plaintext_size]);
-
- if (!decrypter->Decrypt(nonce, associated_data, ciphertext,
- reinterpret_cast<unsigned char*>(plaintext.get()),
- &plaintext_size)) {
- return nullptr;
- }
- return new QuicData(plaintext.release(), plaintext_size, true);
+ QuicPacketSequenceNumber sequence_number;
+ StringPiece nonce_prefix(nonce.data(),
+ nonce.size() - sizeof(sequence_number));
+ decrypter->SetNoncePrefix(nonce_prefix);
+ memcpy(&sequence_number, nonce.data() + nonce_prefix.size(),
+ sizeof(sequence_number));
+ return decrypter->DecryptPacket(sequence_number, associated_data, ciphertext);
}
TEST(ChaCha20Poly1305DecrypterTest, Decrypt) {
diff --git a/net/quic/crypto/crypto_protocol.h b/net/quic/crypto/crypto_protocol.h
index 9a7f6c6..ae7e78d 100644
--- a/net/quic/crypto/crypto_protocol.h
+++ b/net/quic/crypto/crypto_protocol.h
@@ -58,6 +58,7 @@
const QuicTag k1CON = TAG('1', 'C', 'O', 'N'); // Emulate a single connection
const QuicTag kNTLP = TAG('N', 'T', 'L', 'P'); // No tail loss probe
const QuicTag kNCON = TAG('N', 'C', 'O', 'N'); // N Connection Congestion Ctrl
+const QuicTag kNRTO = TAG('N', 'R', 'T', 'O'); // CWND reduction on loss
// Loss detection algorithm types
const QuicTag kNACK = TAG('N', 'A', 'C', 'K'); // TCP style nack counting
diff --git a/net/quic/crypto/crypto_secret_boxer.cc b/net/quic/crypto/crypto_secret_boxer.cc
index 5d8a11b..445d888 100644
--- a/net/quic/crypto/crypto_secret_boxer.cc
+++ b/net/quic/crypto/crypto_secret_boxer.cc
@@ -74,26 +74,29 @@
return false;
}
- char nonce[kBoxNonceSize];
- memcpy(nonce, ciphertext.data(), kBoxNonceSize);
+ StringPiece nonce(ciphertext.data(), kBoxNonceSize);
ciphertext.remove_prefix(kBoxNonceSize);
-
- size_t len = ciphertext.size();
- out_storage->resize(len);
- char* data = const_cast<char*>(out_storage->data());
+ QuicPacketSequenceNumber sequence_number;
+ StringPiece nonce_prefix(nonce.data(),
+ nonce.size() - sizeof(sequence_number));
+ memcpy(&sequence_number, nonce.data() + nonce_prefix.size(),
+ sizeof(sequence_number));
scoped_ptr<QuicDecrypter> decrypter(QuicDecrypter::Create(kAESG));
if (!decrypter->SetKey(key_)) {
DLOG(DFATAL) << "CryptoSecretBoxer's decrypter->SetKey failed.";
return false;
}
- if (!decrypter->Decrypt(StringPiece(nonce, kBoxNonceSize), StringPiece(),
- ciphertext, reinterpret_cast<unsigned char*>(data),
- &len)) {
+ decrypter->SetNoncePrefix(nonce_prefix);
+ scoped_ptr<QuicData> decrypted(
+ decrypter->DecryptPacket(sequence_number, StringPiece(), ciphertext));
+ if (!decrypted.get()) {
return false;
}
- out->set(data, len);
+ out_storage->resize(decrypted->length());
+ out_storage->assign(decrypted->data(), decrypted->length());
+ out->set(out_storage->data(), decrypted->length());
return true;
}
diff --git a/net/quic/crypto/null_decrypter.cc b/net/quic/crypto/null_decrypter.cc
index 77aee4c..4411b7c0 100644
--- a/net/quic/crypto/null_decrypter.cc
+++ b/net/quic/crypto/null_decrypter.cc
@@ -19,31 +19,6 @@
return nonce_prefix.empty();
}
-bool NullDecrypter::Decrypt(StringPiece /*nonce*/,
- StringPiece associated_data,
- StringPiece ciphertext,
- unsigned char* output,
- size_t* output_length) {
- QuicDataReader reader(ciphertext.data(), ciphertext.length());
-
- uint128 hash;
- if (!ReadHash(&reader, &hash)) {
- return false;
- }
-
- StringPiece plaintext = reader.ReadRemainingPayload();
-
- // TODO(rch): avoid buffer copy here
- string buffer = associated_data.as_string();
- plaintext.AppendToString(&buffer);
- if (hash != ComputeHash(buffer)) {
- return false;
- }
- memcpy(output, plaintext.data(), plaintext.length());
- *output_length = plaintext.length();
- return true;
-}
-
QuicData* NullDecrypter::DecryptPacket(QuicPacketSequenceNumber /*seq_number*/,
StringPiece associated_data,
StringPiece ciphertext) {
diff --git a/net/quic/crypto/null_decrypter.h b/net/quic/crypto/null_decrypter.h
index 6f23290..db98a99 100644
--- a/net/quic/crypto/null_decrypter.h
+++ b/net/quic/crypto/null_decrypter.h
@@ -24,11 +24,6 @@
// QuicDecrypter implementation
bool SetKey(base::StringPiece key) override;
bool SetNoncePrefix(base::StringPiece nonce_prefix) override;
- bool Decrypt(base::StringPiece nonce,
- base::StringPiece associated_data,
- base::StringPiece ciphertext,
- unsigned char* output,
- size_t* output_length) override;
QuicData* DecryptPacket(QuicPacketSequenceNumber sequence_number,
base::StringPiece associated_data,
base::StringPiece ciphertext) override;
diff --git a/net/quic/crypto/quic_decrypter.h b/net/quic/crypto/quic_decrypter.h
index 06c76370..9e6e1d2 100644
--- a/net/quic/crypto/quic_decrypter.h
+++ b/net/quic/crypto/quic_decrypter.h
@@ -39,18 +39,6 @@
// packet sequence number, even when retransmitting a lost packet.
virtual bool SetNoncePrefix(base::StringPiece nonce_prefix) = 0;
- // Decrypt authenticates |associated_data| and |ciphertext| and then decrypts
- // |ciphertext| into |output|, using |nonce|. |nonce| must be 8 bytes longer
- // than the nonce prefix length returned by GetNoncePrefixSize() (of the
- // encrypter). |output| must be as long as |ciphertext| on entry and, on
- // successful return, the true length of the plaintext will be written to
- // |*output_length|.
- virtual bool Decrypt(base::StringPiece nonce,
- base::StringPiece associated_data,
- base::StringPiece ciphertext,
- unsigned char* output,
- size_t* output_length) = 0;
-
// Returns a newly created QuicData object containing the decrypted
// |ciphertext| or nullptr if there is an error. |sequence_number| is
// appended to the |nonce_prefix| value provided in SetNoncePrefix()
diff --git a/net/quic/quic_ack_notifier.cc b/net/quic/quic_ack_notifier.cc
index 1780985..b399a61b 100644
--- a/net/quic/quic_ack_notifier.cc
+++ b/net/quic/quic_ack_notifier.cc
@@ -14,19 +14,13 @@
namespace net {
-QuicAckNotifier::PacketInfo::PacketInfo() : packet_payload_size(0) {
-}
-
-QuicAckNotifier::PacketInfo::PacketInfo(int payload_size)
- : packet_payload_size(payload_size) {
-}
-
QuicAckNotifier::DelegateInterface::DelegateInterface() {}
QuicAckNotifier::DelegateInterface::~DelegateInterface() {}
QuicAckNotifier::QuicAckNotifier(DelegateInterface* delegate)
: delegate_(delegate),
+ unacked_packets_(0),
retransmitted_packet_count_(0),
retransmitted_byte_count_(0) {
DCHECK(delegate);
@@ -38,16 +32,17 @@
void QuicAckNotifier::AddSequenceNumber(
const QuicPacketSequenceNumber& sequence_number,
int packet_payload_size) {
- sequence_numbers_.insert(make_pair(sequence_number,
- PacketInfo(packet_payload_size)));
-
+ ++unacked_packets_;
DVLOG(1) << "AckNotifier waiting for packet: " << sequence_number;
}
bool QuicAckNotifier::OnAck(QuicPacketSequenceNumber sequence_number,
QuicTime::Delta delta_largest_observed) {
- DCHECK(ContainsKey(sequence_numbers_, sequence_number));
- sequence_numbers_.erase(sequence_number);
+ if (unacked_packets_ <= 0) {
+ LOG(DFATAL) << "Acked more packets than were tracked.";
+ return true;
+ }
+ --unacked_packets_;
if (IsEmpty()) {
// We have seen all the sequence numbers we were waiting for, trigger
// callback notification.
@@ -59,26 +54,9 @@
return false;
}
-void QuicAckNotifier::UpdateSequenceNumber(
- QuicPacketSequenceNumber old_sequence_number,
- QuicPacketSequenceNumber new_sequence_number) {
- DCHECK(!ContainsKey(sequence_numbers_, new_sequence_number));
-
- PacketInfo packet_info;
- auto it = sequence_numbers_.find(old_sequence_number);
- if (it != sequence_numbers_.end()) {
- packet_info = it->second;
- sequence_numbers_.erase(it);
- } else {
- DLOG(DFATAL) << "Old sequence number not found.";
- }
-
+void QuicAckNotifier::OnPacketRetransmitted(int packet_payload_size) {
++retransmitted_packet_count_;
- retransmitted_byte_count_ += packet_info.packet_payload_size;
- sequence_numbers_.insert(make_pair(new_sequence_number, packet_info));
-
- DVLOG(1) << "AckNotifier waiting for packet: " << new_sequence_number
- << " (retransmitted " << old_sequence_number << ").";
+ retransmitted_byte_count_ += packet_payload_size;
}
}; // namespace net
diff --git a/net/quic/quic_ack_notifier.h b/net/quic/quic_ack_notifier.h
index f8d813e..160108e 100644
--- a/net/quic/quic_ack_notifier.h
+++ b/net/quic/quic_ack_notifier.h
@@ -55,30 +55,20 @@
bool OnAck(QuicPacketSequenceNumber sequence_number,
QuicTime::Delta delta_largest_observed);
- bool IsEmpty() { return sequence_numbers_.empty(); }
+ bool IsEmpty() { return unacked_packets_ == 0; }
- // If a packet is retransmitted by the connection it will be sent with a
- // different sequence number. Updates our internal set of sequence_numbers to
- // track the latest number.
- void UpdateSequenceNumber(QuicPacketSequenceNumber old_sequence_number,
- QuicPacketSequenceNumber new_sequence_number);
+ // If a packet is retransmitted by the connection, it will be sent with a
+ // different sequence number.
+ void OnPacketRetransmitted(int packet_payload_size);
private:
- struct PacketInfo {
- PacketInfo();
- explicit PacketInfo(int payload_size);
-
- int packet_payload_size;
- };
-
// The delegate's OnAckNotification() method will be called once we have been
// notified of ACKs for all the sequence numbers we are tracking.
// This is not owned by OnAckNotifier and must outlive it.
scoped_refptr<DelegateInterface> delegate_;
- // Sequence numbers this notifier is waiting to hear about. The
- // delegate will not be called until this is empty.
- base::hash_map<QuicPacketSequenceNumber, PacketInfo> sequence_numbers_;
+ // The number of unacked packets being tracked.
+ int unacked_packets_;
// Number of packets that had to be retransmitted.
int retransmitted_packet_count_;
@@ -88,6 +78,6 @@
DISALLOW_COPY_AND_ASSIGN(QuicAckNotifier);
};
-}; // namespace net
+} // namespace net
#endif // NET_QUIC_QUIC_ACK_NOTIFIER_H_
diff --git a/net/quic/quic_ack_notifier_manager.cc b/net/quic/quic_ack_notifier_manager.cc
index 129a951e..0d37752 100644
--- a/net/quic/quic_ack_notifier_manager.cc
+++ b/net/quic/quic_ack_notifier_manager.cc
@@ -34,8 +34,8 @@
// One or more AckNotifiers are registered as interested in this sequence
// number. Iterate through them and call OnAck on each.
- AckNotifierSet& ack_notifier_set = map_it->second;
- for (QuicAckNotifier* ack_notifier : ack_notifier_set) {
+ AckNotifierList& ack_notifier_list = map_it->second;
+ for (QuicAckNotifier* ack_notifier : ack_notifier_list) {
ack_notifier->OnAck(sequence_number, delta_largest_observed);
// If this has resulted in an empty AckNotifer, erase it.
@@ -50,9 +50,10 @@
ack_notifier_map_.erase(map_it);
}
-void AckNotifierManager::UpdateSequenceNumber(
+void AckNotifierManager::OnPacketRetransmitted(
QuicPacketSequenceNumber old_sequence_number,
- QuicPacketSequenceNumber new_sequence_number) {
+ QuicPacketSequenceNumber new_sequence_number,
+ int packet_payload_size) {
auto map_it = ack_notifier_map_.find(old_sequence_number);
if (map_it == ack_notifier_map_.end()) {
// No AckNotifiers are interested in the old sequence number.
@@ -60,15 +61,14 @@
}
// Update the existing QuicAckNotifiers to the new sequence number.
- AckNotifierSet& ack_notifier_set = map_it->second;
- for (QuicAckNotifier* ack_notifier : ack_notifier_set) {
- ack_notifier->UpdateSequenceNumber(old_sequence_number,
- new_sequence_number);
+ AckNotifierList& ack_notifier_list = map_it->second;
+ for (QuicAckNotifier* ack_notifier : ack_notifier_list) {
+ ack_notifier->OnPacketRetransmitted(packet_payload_size);
}
// The old sequence number is no longer of interest, copy the updated
// AckNotifiers to the new sequence number before deleting the old.
- ack_notifier_map_[new_sequence_number] = ack_notifier_set;
+ ack_notifier_map_[new_sequence_number] = ack_notifier_list;
ack_notifier_map_.erase(map_it);
}
@@ -86,7 +86,7 @@
// Update the mapping in the other direction, from sequence number to
// AckNotifier.
- ack_notifier_map_[serialized_packet.sequence_number].insert(notifier);
+ ack_notifier_map_[serialized_packet.sequence_number].push_back(notifier);
// Take ownership of the AckNotifier.
ack_notifiers_.insert(notifier);
@@ -112,7 +112,7 @@
// Update the mapping in the other direction, from sequence number to
// AckNotifier.
- ack_notifier_map_[serialized_packet.sequence_number].insert(notifier);
+ ack_notifier_map_[serialized_packet.sequence_number].push_back(notifier);
// Take ownership of the AckNotifier.
ack_notifiers_.insert(notifier);
diff --git a/net/quic/quic_ack_notifier_manager.h b/net/quic/quic_ack_notifier_manager.h
index 122bda1..bf4d574 100644
--- a/net/quic/quic_ack_notifier_manager.h
+++ b/net/quic/quic_ack_notifier_manager.h
@@ -5,6 +5,7 @@
#ifndef NET_QUIC_QUIC_ACK_NOTIFIER_MANAGER_H_
#define NET_QUIC_QUIC_ACK_NOTIFIER_MANAGER_H_
+#include <list>
#include <map>
#include "base/containers/hash_tables.h"
@@ -34,8 +35,9 @@
// If a packet has been retransmitted with a new sequence number, then this
// will be called. It updates the mapping in ack_notifier_map_, and also
// updates the internal set of sequence numbers in each matching AckNotifier.
- void UpdateSequenceNumber(QuicPacketSequenceNumber old_sequence_number,
- QuicPacketSequenceNumber new_sequence_number);
+ void OnPacketRetransmitted(QuicPacketSequenceNumber old_sequence_number,
+ QuicPacketSequenceNumber new_sequence_number,
+ int packet_payload_size);
// This is called after a packet has been serialized, is ready to be sent, and
// contains retransmittable frames (which may have associated AckNotifiers).
@@ -45,8 +47,11 @@
void OnSerializedPacket(const SerializedPacket& serialized_packet);
private:
+ typedef std::list<QuicAckNotifier*> AckNotifierList;
typedef base::hash_set<QuicAckNotifier*> AckNotifierSet;
- typedef std::map<QuicPacketSequenceNumber, AckNotifierSet> AckNotifierMap;
+ // TODO(ianswett): Further improvement may come from changing this to a deque.
+ typedef base::hash_map<QuicPacketSequenceNumber, AckNotifierList>
+ AckNotifierMap;
// On every ACK frame received by the connection, all the ack_notifiers_ will
// be told which sequeunce numbers were ACKed.
diff --git a/net/quic/quic_ack_notifier_test.cc b/net/quic/quic_ack_notifier_test.cc
index 4e15b98..21c876665 100644
--- a/net/quic/quic_ack_notifier_test.cc
+++ b/net/quic/quic_ack_notifier_test.cc
@@ -52,8 +52,8 @@
// new sequeunce numbers.
TEST_F(QuicAckNotifierTest, UpdateSeqNums) {
// Update a couple of the sequence numbers (i.e. retransmitted packets)
- notifier_->UpdateSequenceNumber(99, 3000);
- notifier_->UpdateSequenceNumber(1234, 3001);
+ notifier_->OnPacketRetransmitted(20);
+ notifier_->OnPacketRetransmitted(3);
EXPECT_CALL(*delegate_, OnAckNotification(2, 20 + 3, _)).Times(1);
EXPECT_FALSE(notifier_->OnAck(26, zero_)); // original
diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc
index 7622f04a..091dc9ec 100644
--- a/net/quic/quic_connection_test.cc
+++ b/net/quic/quic_connection_test.cc
@@ -144,22 +144,6 @@
bool SetNoncePrefix(StringPiece nonce_prefix) override { return true; }
- bool Decrypt(StringPiece nonce,
- StringPiece associated_data,
- StringPiece ciphertext,
- unsigned char* output,
- size_t* output_length) override {
- if (ciphertext.size() < kTagSize) {
- return false;
- }
- if (!CheckTag(ciphertext, GetTag(ciphertext))) {
- return false;
- }
- *output_length = ciphertext.size() - kTagSize;
- memcpy(output, ciphertext.data(), *output_length);
- return true;
- }
-
QuicData* DecryptPacket(QuicPacketSequenceNumber sequence_number,
StringPiece associated_data,
StringPiece ciphertext) override {
diff --git a/net/quic/quic_crypto_client_stream.cc b/net/quic/quic_crypto_client_stream.cc
index b820746..26bd1717 100644
--- a/net/quic/quic_crypto_client_stream.cc
+++ b/net/quic/quic_crypto_client_stream.cc
@@ -445,7 +445,7 @@
if (!verify_ok_) {
next_state_ = STATE_NONE;
- if (verify_details_) {
+ if (verify_details_.get()) {
client_session()->OnProofVerifyDetailsAvailable(*verify_details_);
}
UMA_HISTOGRAM_BOOLEAN("Net.QuicVerifyProofFailed.HandshakeConfirmed",
diff --git a/net/quic/quic_framer_test.cc b/net/quic/quic_framer_test.cc
index bb852a0..0fa4ce9 100644
--- a/net/quic/quic_framer_test.cc
+++ b/net/quic/quic_framer_test.cc
@@ -141,14 +141,6 @@
~TestDecrypter() override {}
bool SetKey(StringPiece key) override { return true; }
bool SetNoncePrefix(StringPiece nonce_prefix) override { return true; }
- bool Decrypt(StringPiece nonce,
- StringPiece associated_data,
- StringPiece ciphertext,
- unsigned char* output,
- size_t* output_length) override {
- CHECK(false) << "Not implemented";
- return false;
- }
QuicData* DecryptPacket(QuicPacketSequenceNumber sequence_number,
StringPiece associated_data,
StringPiece ciphertext) override {
diff --git a/net/quic/quic_packet_generator.cc b/net/quic/quic_packet_generator.cc
index 22bf530..bfecf5d 100644
--- a/net/quic/quic_packet_generator.cc
+++ b/net/quic/quic_packet_generator.cc
@@ -177,7 +177,7 @@
// We want to track which packet this stream frame ends up in.
if (FLAGS_quic_attach_ack_notifiers_to_packets) {
if (notifier != nullptr) {
- ack_notifiers_.insert(notifier);
+ ack_notifiers_.push_back(notifier);
}
} else {
frame.stream_frame->notifier = notifier;
@@ -227,7 +227,7 @@
// Try to close FEC group since we've either run out of data to send or we're
// blocked. If not in batch mode, force close the group.
- MaybeSendFecPacketAndCloseGroup(/*flush=*/false);
+ MaybeSendFecPacketAndCloseGroup(/*force=*/false);
DCHECK(InBatchMode() || !packet_creator_.HasPendingFrames());
return QuicConsumedData(total_bytes_consumed, fin_consumed);
@@ -317,7 +317,7 @@
// Flush out any pending frames in the generator and the creator, and then
// send out FEC packet.
SendQueuedFrames(true);
- MaybeSendFecPacketAndCloseGroup(/*flush=*/true);
+ MaybeSendFecPacketAndCloseGroup(/*force=*/true);
}
QuicTime::Delta QuicPacketGenerator::GetFecTimeout(
@@ -407,7 +407,7 @@
}
delegate_->OnSerializedPacket(serialized_packet);
- MaybeSendFecPacketAndCloseGroup(/*flush=*/false);
+ MaybeSendFecPacketAndCloseGroup(/*force=*/false);
// The packet has now been serialized, safe to delete pending frames.
pending_ack_frame_.reset();
diff --git a/net/quic/quic_packet_generator.h b/net/quic/quic_packet_generator.h
index a86a746..0da94f0 100644
--- a/net/quic/quic_packet_generator.h
+++ b/net/quic/quic_packet_generator.h
@@ -53,6 +53,8 @@
#ifndef NET_QUIC_QUIC_PACKET_GENERATOR_H_
#define NET_QUIC_QUIC_PACKET_GENERATOR_H_
+#include <list>
+
#include "base/containers/hash_tables.h"
#include "net/quic/quic_ack_notifier.h"
#include "net/quic/quic_packet_creator.h"
@@ -256,7 +258,7 @@
scoped_ptr<QuicStopWaitingFrame> pending_stop_waiting_frame_;
// Stores notifiers that should be attached to the next serialized packet.
- base::hash_set<QuicAckNotifier*> ack_notifiers_;
+ std::list<QuicAckNotifier*> ack_notifiers_;
DISALLOW_COPY_AND_ASSIGN(QuicPacketGenerator);
};
diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h
index d87cb7ed..3daf9174 100644
--- a/net/quic/quic_protocol.h
+++ b/net/quic/quic_protocol.h
@@ -1033,7 +1033,7 @@
RetransmittableFrames* retransmittable_frames;
// Optional notifiers which will be informed when this packet has been ACKed.
- base::hash_set<QuicAckNotifier*> notifiers;
+ std::list<QuicAckNotifier*> notifiers;
};
struct NET_EXPORT_PRIVATE TransmissionInfo {
diff --git a/net/quic/quic_sent_packet_manager.cc b/net/quic/quic_sent_packet_manager.cc
index 91775523..34bb972 100644
--- a/net/quic/quic_sent_packet_manager.cc
+++ b/net/quic/quic_sent_packet_manager.cc
@@ -100,6 +100,7 @@
pending_timer_transmission_count_(0),
max_tail_loss_probes_(kDefaultMaxTailLossProbes),
using_pacing_(false),
+ use_new_rto_(false),
handshake_confirmed_(false) {
}
@@ -154,6 +155,9 @@
if (HasClientSentConnectionOption(config, kNTLP)) {
max_tail_loss_probes_ = 0;
}
+ if (HasClientSentConnectionOption(config, kNRTO)) {
+ use_new_rto_ = true;
+ }
if (config.HasReceivedConnectionOptions() &&
ContainsQuicTag(config.ReceivedConnectionOptions(), kTIME)) {
loss_algorithm_.reset(LossDetectionInterface::Create(kTime));
@@ -215,6 +219,10 @@
HandleAckForSentPackets(ack_frame);
InvokeLossDetection(ack_receive_time);
+ // Ignore losses in RTO mode.
+ if (FLAGS_quic_use_new_rto && consecutive_rto_count_ > 0 && !use_new_rto_) {
+ packets_lost_.clear();
+ }
MaybeInvokeCongestionEvent(rtt_updated, bytes_in_flight);
unacked_packets_.RemoveObsoletePackets();
@@ -243,7 +251,9 @@
// a spurious RTO from happening again.
rtt_stats_.ExpireSmoothedMetrics();
} else {
- send_algorithm_->OnRetransmissionTimeout(true);
+ if (!use_new_rto_) {
+ send_algorithm_->OnRetransmissionTimeout(true);
+ }
}
}
// Reset all retransmit counters any time a new packet is acked.
@@ -566,10 +576,10 @@
<< "pending_retransmissions_. sequence_number: "
<< original_sequence_number;
}
- // A notifier may be waiting to hear about ACKs for the original sequence
- // number. Inform them that the sequence number has changed.
- ack_notifier_manager_.UpdateSequenceNumber(original_sequence_number,
- sequence_number);
+ // Inform the ack notifier of retransmissions so it can calculate the
+ // retransmit rate.
+ ack_notifier_manager_.OnPacketRetransmitted(original_sequence_number,
+ sequence_number, bytes);
}
if (pending_timer_transmission_count_ > 0) {
diff --git a/net/quic/quic_sent_packet_manager.h b/net/quic/quic_sent_packet_manager.h
index 6bb2c778..c2a8ef6 100644
--- a/net/quic/quic_sent_packet_manager.h
+++ b/net/quic/quic_sent_packet_manager.h
@@ -397,6 +397,9 @@
// Maximum number of tail loss probes to send before firing an RTO.
size_t max_tail_loss_probes_;
bool using_pacing_;
+ // If true, use the new RTO with loss based CWND reduction instead of the send
+ // algorithms's OnRetransmissionTimeout to reduce the congestion window.
+ bool use_new_rto_;
// Vectors packets acked and lost as a result of the last congestion event.
SendAlgorithmInterface::CongestionVector packets_acked_;
diff --git a/net/quic/quic_sent_packet_manager_test.cc b/net/quic/quic_sent_packet_manager_test.cc
index 6275094..e9b169b 100644
--- a/net/quic/quic_sent_packet_manager_test.cc
+++ b/net/quic/quic_sent_packet_manager_test.cc
@@ -16,6 +16,7 @@
using testing::AnyNumber;
using testing::ElementsAre;
using testing::IsEmpty;
+using testing::Not;
using testing::Pair;
using testing::Pointwise;
using testing::Return;
@@ -1127,17 +1128,63 @@
}
// Ack a retransmission.
- if (FLAGS_quic_use_new_rto) {
- EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true));
- }
QuicAckFrame ack_frame;
ack_frame.delta_time_largest_observed = QuicTime::Delta::Zero();
ack_frame.largest_observed = 102;
for (int i = 0; i < 102; ++i) {
ack_frame.missing_packets.insert(i);
}
+ // Ensure no packets are lost.
EXPECT_CALL(*send_algorithm_,
- OnCongestionEvent(true, _, ElementsAre(Pair(102, _)), _));
+ OnCongestionEvent(true, _, ElementsAre(Pair(102, _)),
+ /*lost_packets=*/IsEmpty()));
+ EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
+ EXPECT_CALL(*network_change_visitor_, OnRttChange());
+ if (FLAGS_quic_use_new_rto) {
+ EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true));
+ }
+ manager_.OnIncomingAck(ack_frame, clock_.Now());
+}
+
+TEST_F(QuicSentPacketManagerTest, NewRetransmissionTimeout) {
+ ValueRestore<bool> old_flag(&FLAGS_quic_use_new_rto, true);
+ QuicConfig client_config;
+ QuicTagVector options;
+ options.push_back(kNRTO);
+ QuicSentPacketManagerPeer::SetIsServer(&manager_, false);
+ client_config.SetConnectionOptionsToSend(options);
+ EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
+ EXPECT_CALL(*network_change_visitor_, OnRttChange());
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _));
+ manager_.SetFromConfig(client_config);
+ EXPECT_TRUE(QuicSentPacketManagerPeer::GetUseNewRto(&manager_));
+
+ // Send 100 packets.
+ const size_t kNumSentPackets = 100;
+ for (size_t i = 1; i <= kNumSentPackets; ++i) {
+ SendDataPacket(i);
+ }
+
+ EXPECT_FALSE(manager_.MaybeRetransmitTailLossProbe());
+ manager_.OnRetransmissionTimeout();
+ EXPECT_TRUE(manager_.HasPendingRetransmissions());
+ EXPECT_EQ(100 * kDefaultLength,
+ QuicSentPacketManagerPeer::GetBytesInFlight(&manager_));
+ RetransmitNextPacket(101);
+ RetransmitNextPacket(102);
+ EXPECT_FALSE(manager_.HasPendingRetransmissions());
+
+ // Ack a retransmission and expect no call to OnRetransmissionTimeout.
+ QuicAckFrame ack_frame;
+ ack_frame.delta_time_largest_observed = QuicTime::Delta::Zero();
+ ack_frame.largest_observed = 102;
+ for (int i = 0; i < 102; ++i) {
+ ack_frame.missing_packets.insert(i);
+ }
+ // This will include packets in the lost packet map.
+ EXPECT_CALL(*send_algorithm_,
+ OnCongestionEvent(true, _, ElementsAre(Pair(102, _)),
+ /*lost_packets=*/Not(IsEmpty())));
EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
EXPECT_CALL(*network_change_visitor_, OnRttChange());
manager_.OnIncomingAck(ack_frame, clock_.Now());
@@ -1609,6 +1656,35 @@
EXPECT_EQ(0u, QuicSentPacketManagerPeer::GetMaxTailLossProbes(&manager_));
}
+TEST_F(QuicSentPacketManagerTest, NegotiateNewRTOFromOptionsAtServer) {
+ EXPECT_FALSE(QuicSentPacketManagerPeer::GetUseNewRto(&manager_));
+ QuicConfig config;
+ QuicTagVector options;
+
+ options.push_back(kNRTO);
+ QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
+ EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
+ EXPECT_CALL(*network_change_visitor_, OnRttChange());
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _));
+ manager_.SetFromConfig(config);
+ EXPECT_TRUE(QuicSentPacketManagerPeer::GetUseNewRto(&manager_));
+}
+
+TEST_F(QuicSentPacketManagerTest, NegotiateNewRTOFromOptionsAtClient) {
+ EXPECT_FALSE(QuicSentPacketManagerPeer::GetUseNewRto(&manager_));
+ QuicConfig client_config;
+ QuicTagVector options;
+
+ options.push_back(kNRTO);
+ QuicSentPacketManagerPeer::SetIsServer(&manager_, false);
+ client_config.SetConnectionOptionsToSend(options);
+ EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
+ EXPECT_CALL(*network_change_visitor_, OnRttChange());
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _));
+ manager_.SetFromConfig(client_config);
+ EXPECT_TRUE(QuicSentPacketManagerPeer::GetUseNewRto(&manager_));
+}
+
TEST_F(QuicSentPacketManagerTest, NegotiatePacingFromOptions) {
EXPECT_FALSE(manager_.using_pacing());
diff --git a/net/quic/quic_stream_sequencer.h b/net/quic/quic_stream_sequencer.h
index 025dca4..f34d735 100644
--- a/net/quic/quic_stream_sequencer.h
+++ b/net/quic/quic_stream_sequencer.h
@@ -23,7 +23,6 @@
// Buffers frames until we have something which can be passed
// up to the next layer.
-// TOOD(alyssar) add some checks for overflow attempts [1, 256,] [2, 256]
class NET_EXPORT_PRIVATE QuicStreamSequencer {
public:
explicit QuicStreamSequencer(ReliableQuicStream* quic_stream);
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 311b688..4e182ab 100644
--- a/net/quic/test_tools/quic_sent_packet_manager_peer.cc
+++ b/net/quic/test_tools/quic_sent_packet_manager_peer.cc
@@ -26,6 +26,12 @@
}
// static
+bool QuicSentPacketManagerPeer::GetUseNewRto(
+ QuicSentPacketManager* sent_packet_manager) {
+ return sent_packet_manager->use_new_rto_;
+}
+
+// static
QuicByteCount QuicSentPacketManagerPeer::GetReceiveWindow(
QuicSentPacketManager* sent_packet_manager) {
return sent_packet_manager->receive_buffer_bytes_;
diff --git a/net/quic/test_tools/quic_sent_packet_manager_peer.h b/net/quic/test_tools/quic_sent_packet_manager_peer.h
index 2d850d3..6ac34ffc 100644
--- a/net/quic/test_tools/quic_sent_packet_manager_peer.h
+++ b/net/quic/test_tools/quic_sent_packet_manager_peer.h
@@ -22,6 +22,8 @@
static void SetMaxTailLossProbes(
QuicSentPacketManager* sent_packet_manager, size_t max_tail_loss_probes);
+ static bool GetUseNewRto(QuicSentPacketManager* sent_packet_manager);
+
static QuicByteCount GetReceiveWindow(
QuicSentPacketManager* sent_packet_manager);
diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc
index 0a5010d..fa9a8e7 100644
--- a/net/tools/quic/end_to_end_test.cc
+++ b/net/tools/quic/end_to_end_test.cc
@@ -142,12 +142,9 @@
use_fec != 0, congestion_control_tag));
// Test client supporting all versions and server supporting 1
- // version.
- // Simulate an old server and exercise version downgrade in the
- // client.
- // Protocol negotiation should occur. Skip the i = 0 case because it
- // is
- // essentially the same as the default case.
+ // version. Simulate an old server and exercise version downgrade in
+ // the client. Protocol negotiation should occur. Skip the i = 0 case
+ // because it is essentially the same as the default case.
for (QuicVersion version : *client_versions) {
QuicVersionVector server_supported_versions;
server_supported_versions.push_back(version);
diff --git a/net/tools/quic/test_tools/quic_test_client.cc b/net/tools/quic/test_tools/quic_test_client.cc
index 97a0674..94d55b4 100644
--- a/net/tools/quic/test_tools/quic_test_client.cc
+++ b/net/tools/quic/test_tools/quic_test_client.cc
@@ -255,9 +255,8 @@
scoped_ptr<BalsaHeaders> munged_headers(MungeHeaders(message.headers(),
secure_));
ssize_t ret = GetOrCreateStream()->SendRequest(
- munged_headers.get() ? *munged_headers.get() : *message.headers(),
- message.body(),
- message.has_complete_message());
+ munged_headers.get() ? *munged_headers : *message.headers(),
+ message.body(), message.has_complete_message());
WaitForWriteToFlush();
return ret;
}