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;
 }