Clone of chromium aad1ce808763f59c7a3753e08f1500a104ecc6fd refs/remotes/origin/HEAD
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc
new file mode 100644
index 0000000..8d49010
--- /dev/null
+++ b/net/quic/quic_connection.cc
@@ -0,0 +1,2041 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/quic_connection.h"
+
+#include <string.h>
+#include <sys/types.h>
+#include <algorithm>
+#include <iterator>
+#include <limits>
+#include <memory>
+#include <set>
+#include <utility>
+
+#include "base/debug/stack_trace.h"
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "net/base/net_errors.h"
+#include "net/quic/crypto/quic_decrypter.h"
+#include "net/quic/crypto/quic_encrypter.h"
+#include "net/quic/iovector.h"
+#include "net/quic/quic_bandwidth.h"
+#include "net/quic/quic_config.h"
+#include "net/quic/quic_fec_group.h"
+#include "net/quic/quic_flags.h"
+#include "net/quic/quic_utils.h"
+
+using base::StringPiece;
+using base::hash_map;
+using base::hash_set;
+using std::list;
+using std::make_pair;
+using std::max;
+using std::min;
+using std::numeric_limits;
+using std::set;
+using std::string;
+using std::vector;
+
+namespace net {
+
+class QuicDecrypter;
+class QuicEncrypter;
+
+namespace {
+
+// The largest gap in packets we'll accept without closing the connection.
+// This will likely have to be tuned.
+const QuicPacketSequenceNumber kMaxPacketGap = 5000;
+
+// Limit the number of FEC groups to two.  If we get enough out of order packets
+// that this becomes limiting, we can revisit.
+const size_t kMaxFecGroups = 2;
+
+// Limit the number of undecryptable packets we buffer in
+// expectation of the CHLO/SHLO arriving.
+const size_t kMaxUndecryptablePackets = 10;
+
+// Maximum number of acks received before sending an ack in response.
+const size_t kMaxPacketsReceivedBeforeAckSend = 20;
+
+bool Near(QuicPacketSequenceNumber a, QuicPacketSequenceNumber b) {
+  QuicPacketSequenceNumber delta = (a > b) ? a - b : b - a;
+  return delta <= kMaxPacketGap;
+}
+
+// An alarm that is scheduled to send an ack if a timeout occurs.
+class AckAlarm : public QuicAlarm::Delegate {
+ public:
+  explicit AckAlarm(QuicConnection* connection)
+      : connection_(connection) {
+  }
+
+  virtual QuicTime OnAlarm() OVERRIDE {
+    connection_->SendAck();
+    return QuicTime::Zero();
+  }
+
+ private:
+  QuicConnection* connection_;
+
+  DISALLOW_COPY_AND_ASSIGN(AckAlarm);
+};
+
+// This alarm will be scheduled any time a data-bearing packet is sent out.
+// When the alarm goes off, the connection checks to see if the oldest packets
+// have been acked, and retransmit them if they have not.
+class RetransmissionAlarm : public QuicAlarm::Delegate {
+ public:
+  explicit RetransmissionAlarm(QuicConnection* connection)
+      : connection_(connection) {
+  }
+
+  virtual QuicTime OnAlarm() OVERRIDE {
+    connection_->OnRetransmissionTimeout();
+    return QuicTime::Zero();
+  }
+
+ private:
+  QuicConnection* connection_;
+
+  DISALLOW_COPY_AND_ASSIGN(RetransmissionAlarm);
+};
+
+// An alarm that is scheduled when the sent scheduler requires a
+// a delay before sending packets and fires when the packet may be sent.
+class SendAlarm : public QuicAlarm::Delegate {
+ public:
+  explicit SendAlarm(QuicConnection* connection)
+      : connection_(connection) {
+  }
+
+  virtual QuicTime OnAlarm() OVERRIDE {
+    connection_->WriteIfNotBlocked();
+    // Never reschedule the alarm, since CanWrite does that.
+    return QuicTime::Zero();
+  }
+
+ private:
+  QuicConnection* connection_;
+
+  DISALLOW_COPY_AND_ASSIGN(SendAlarm);
+};
+
+class TimeoutAlarm : public QuicAlarm::Delegate {
+ public:
+  explicit TimeoutAlarm(QuicConnection* connection)
+      : connection_(connection) {
+  }
+
+  virtual QuicTime OnAlarm() OVERRIDE {
+    connection_->CheckForTimeout();
+    // Never reschedule the alarm, since CheckForTimeout does that.
+    return QuicTime::Zero();
+  }
+
+ private:
+  QuicConnection* connection_;
+
+  DISALLOW_COPY_AND_ASSIGN(TimeoutAlarm);
+};
+
+class PingAlarm : public QuicAlarm::Delegate {
+ public:
+  explicit PingAlarm(QuicConnection* connection)
+      : connection_(connection) {
+  }
+
+  virtual QuicTime OnAlarm() OVERRIDE {
+    connection_->SendPing();
+    return QuicTime::Zero();
+  }
+
+ private:
+  QuicConnection* connection_;
+
+  DISALLOW_COPY_AND_ASSIGN(PingAlarm);
+};
+
+}  // namespace
+
+QuicConnection::QueuedPacket::QueuedPacket(SerializedPacket packet,
+                                           EncryptionLevel level)
+  : serialized_packet(packet),
+    encryption_level(level),
+    transmission_type(NOT_RETRANSMISSION),
+    original_sequence_number(0) {
+}
+
+QuicConnection::QueuedPacket::QueuedPacket(
+    SerializedPacket packet,
+    EncryptionLevel level,
+    TransmissionType transmission_type,
+    QuicPacketSequenceNumber original_sequence_number)
+    : serialized_packet(packet),
+      encryption_level(level),
+      transmission_type(transmission_type),
+      original_sequence_number(original_sequence_number) {
+}
+
+#define ENDPOINT (is_server_ ? "Server: " : " Client: ")
+
+QuicConnection::QuicConnection(QuicConnectionId connection_id,
+                               IPEndPoint address,
+                               QuicConnectionHelperInterface* helper,
+                               const PacketWriterFactory& writer_factory,
+                               bool owns_writer,
+                               bool is_server,
+                               const QuicVersionVector& supported_versions)
+    : framer_(supported_versions, helper->GetClock()->ApproximateNow(),
+              is_server),
+      helper_(helper),
+      writer_(writer_factory.Create(this)),
+      owns_writer_(owns_writer),
+      encryption_level_(ENCRYPTION_NONE),
+      clock_(helper->GetClock()),
+      random_generator_(helper->GetRandomGenerator()),
+      connection_id_(connection_id),
+      peer_address_(address),
+      migrating_peer_port_(0),
+      last_packet_revived_(false),
+      last_size_(0),
+      last_decrypted_packet_level_(ENCRYPTION_NONE),
+      largest_seen_packet_with_ack_(0),
+      largest_seen_packet_with_stop_waiting_(0),
+      pending_version_negotiation_packet_(false),
+      received_packet_manager_(&stats_),
+      ack_queued_(false),
+      num_packets_received_since_last_ack_sent_(0),
+      stop_waiting_count_(0),
+      ack_alarm_(helper->CreateAlarm(new AckAlarm(this))),
+      retransmission_alarm_(helper->CreateAlarm(new RetransmissionAlarm(this))),
+      send_alarm_(helper->CreateAlarm(new SendAlarm(this))),
+      resume_writes_alarm_(helper->CreateAlarm(new SendAlarm(this))),
+      timeout_alarm_(helper->CreateAlarm(new TimeoutAlarm(this))),
+      ping_alarm_(helper->CreateAlarm(new PingAlarm(this))),
+      packet_generator_(connection_id_, &framer_, random_generator_, this),
+      idle_network_timeout_(FLAGS_quic_unified_timeouts ?
+          QuicTime::Delta::Infinite() :
+          QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs)),
+      overall_connection_timeout_(QuicTime::Delta::Infinite()),
+      time_of_last_received_packet_(clock_->ApproximateNow()),
+      time_of_last_sent_new_packet_(clock_->ApproximateNow()),
+      sequence_number_of_last_sent_packet_(0),
+      sent_packet_manager_(
+          is_server, clock_, &stats_,
+          FLAGS_quic_use_bbr_congestion_control ? kBBR : kCubic,
+          FLAGS_quic_use_time_loss_detection ? kTime : kNack),
+      version_negotiation_state_(START_NEGOTIATION),
+      is_server_(is_server),
+      connected_(true),
+      peer_ip_changed_(false),
+      peer_port_changed_(false),
+      self_ip_changed_(false),
+      self_port_changed_(false) {
+  DVLOG(1) << ENDPOINT << "Created connection with connection_id: "
+           << connection_id;
+  if (!FLAGS_quic_unified_timeouts) {
+    timeout_alarm_->Set(clock_->ApproximateNow().Add(idle_network_timeout_));
+  }
+  framer_.set_visitor(this);
+  framer_.set_received_entropy_calculator(&received_packet_manager_);
+  stats_.connection_creation_time = clock_->ApproximateNow();
+  sent_packet_manager_.set_network_change_visitor(this);
+}
+
+QuicConnection::~QuicConnection() {
+  if (owns_writer_) {
+    delete writer_;
+  }
+  STLDeleteElements(&undecryptable_packets_);
+  STLDeleteValues(&group_map_);
+  for (QueuedPacketList::iterator it = queued_packets_.begin();
+       it != queued_packets_.end(); ++it) {
+    delete it->serialized_packet.retransmittable_frames;
+    delete it->serialized_packet.packet;
+  }
+}
+
+void QuicConnection::SetFromConfig(const QuicConfig& config) {
+  if (FLAGS_quic_unified_timeouts) {
+    if (config.negotiated()) {
+      SetNetworkTimeouts(QuicTime::Delta::Infinite(),
+                         config.IdleConnectionStateLifetime());
+    } else {
+      SetNetworkTimeouts(config.max_time_before_crypto_handshake(),
+                         config.max_idle_time_before_crypto_handshake());
+    }
+  } else {
+    SetIdleNetworkTimeout(config.IdleConnectionStateLifetime());
+  }
+  sent_packet_manager_.SetFromConfig(config);
+}
+
+bool QuicConnection::SelectMutualVersion(
+    const QuicVersionVector& available_versions) {
+  // Try to find the highest mutual version by iterating over supported
+  // versions, starting with the highest, and breaking out of the loop once we
+  // find a matching version in the provided available_versions vector.
+  const QuicVersionVector& supported_versions = framer_.supported_versions();
+  for (size_t i = 0; i < supported_versions.size(); ++i) {
+    const QuicVersion& version = supported_versions[i];
+    if (std::find(available_versions.begin(), available_versions.end(),
+                  version) != available_versions.end()) {
+      framer_.set_version(version);
+      return true;
+    }
+  }
+
+  return false;
+}
+
+void QuicConnection::OnError(QuicFramer* framer) {
+  // Packets that we cannot decrypt are dropped.
+  // TODO(rch): add stats to measure this.
+  if (!connected_ || framer->error() == QUIC_DECRYPTION_FAILURE) {
+    return;
+  }
+  SendConnectionCloseWithDetails(framer->error(), framer->detailed_error());
+}
+
+void QuicConnection::OnPacket() {
+  DCHECK(last_stream_frames_.empty() &&
+         last_ack_frames_.empty() &&
+         last_congestion_frames_.empty() &&
+         last_stop_waiting_frames_.empty() &&
+         last_rst_frames_.empty() &&
+         last_goaway_frames_.empty() &&
+         last_window_update_frames_.empty() &&
+         last_blocked_frames_.empty() &&
+         last_ping_frames_.empty() &&
+         last_close_frames_.empty());
+}
+
+void QuicConnection::OnPublicResetPacket(
+    const QuicPublicResetPacket& packet) {
+  if (debug_visitor_.get() != nullptr) {
+    debug_visitor_->OnPublicResetPacket(packet);
+  }
+  CloseConnection(QUIC_PUBLIC_RESET, true);
+
+  DVLOG(1) << ENDPOINT << "Connection " << connection_id()
+           << " closed via QUIC_PUBLIC_RESET from peer.";
+}
+
+bool QuicConnection::OnProtocolVersionMismatch(QuicVersion received_version) {
+  DVLOG(1) << ENDPOINT << "Received packet with mismatched version "
+           << received_version;
+  // TODO(satyamshekhar): Implement no server state in this mode.
+  if (!is_server_) {
+    LOG(DFATAL) << ENDPOINT << "Framer called OnProtocolVersionMismatch. "
+                << "Closing connection.";
+    CloseConnection(QUIC_INTERNAL_ERROR, false);
+    return false;
+  }
+  DCHECK_NE(version(), received_version);
+
+  if (debug_visitor_.get() != nullptr) {
+    debug_visitor_->OnProtocolVersionMismatch(received_version);
+  }
+
+  switch (version_negotiation_state_) {
+    case START_NEGOTIATION:
+      if (!framer_.IsSupportedVersion(received_version)) {
+        SendVersionNegotiationPacket();
+        version_negotiation_state_ = NEGOTIATION_IN_PROGRESS;
+        return false;
+      }
+      break;
+
+    case NEGOTIATION_IN_PROGRESS:
+      if (!framer_.IsSupportedVersion(received_version)) {
+        SendVersionNegotiationPacket();
+        return false;
+      }
+      break;
+
+    case NEGOTIATED_VERSION:
+      // Might be old packets that were sent by the client before the version
+      // was negotiated. Drop these.
+      return false;
+
+    default:
+      DCHECK(false);
+  }
+
+  version_negotiation_state_ = NEGOTIATED_VERSION;
+  visitor_->OnSuccessfulVersionNegotiation(received_version);
+  if (debug_visitor_.get() != nullptr) {
+    debug_visitor_->OnSuccessfulVersionNegotiation(received_version);
+  }
+  DVLOG(1) << ENDPOINT << "version negotiated " << received_version;
+
+  // Store the new version.
+  framer_.set_version(received_version);
+
+  // TODO(satyamshekhar): Store the sequence number of this packet and close the
+  // connection if we ever received a packet with incorrect version and whose
+  // sequence number is greater.
+  return true;
+}
+
+// Handles version negotiation for client connection.
+void QuicConnection::OnVersionNegotiationPacket(
+    const QuicVersionNegotiationPacket& packet) {
+  if (is_server_) {
+    LOG(DFATAL) << ENDPOINT << "Framer parsed VersionNegotiationPacket."
+                << " Closing connection.";
+    CloseConnection(QUIC_INTERNAL_ERROR, false);
+    return;
+  }
+  if (debug_visitor_.get() != nullptr) {
+    debug_visitor_->OnVersionNegotiationPacket(packet);
+  }
+
+  if (version_negotiation_state_ != START_NEGOTIATION) {
+    // Possibly a duplicate version negotiation packet.
+    return;
+  }
+
+  if (std::find(packet.versions.begin(),
+                packet.versions.end(), version()) !=
+      packet.versions.end()) {
+    DLOG(WARNING) << ENDPOINT << "The server already supports our version. "
+                  << "It should have accepted our connection.";
+    // Just drop the connection.
+    CloseConnection(QUIC_INVALID_VERSION_NEGOTIATION_PACKET, false);
+    return;
+  }
+
+  if (!SelectMutualVersion(packet.versions)) {
+    SendConnectionCloseWithDetails(QUIC_INVALID_VERSION,
+                                   "no common version found");
+    return;
+  }
+
+  DVLOG(1) << ENDPOINT
+           << "Negotiated version: " << QuicVersionToString(version());
+  server_supported_versions_ = packet.versions;
+  version_negotiation_state_ = NEGOTIATION_IN_PROGRESS;
+  RetransmitUnackedPackets(ALL_UNACKED_RETRANSMISSION);
+}
+
+void QuicConnection::OnRevivedPacket() {
+}
+
+bool QuicConnection::OnUnauthenticatedPublicHeader(
+    const QuicPacketPublicHeader& header) {
+  return true;
+}
+
+bool QuicConnection::OnUnauthenticatedHeader(const QuicPacketHeader& header) {
+  return true;
+}
+
+void QuicConnection::OnDecryptedPacket(EncryptionLevel level) {
+  last_decrypted_packet_level_ = level;
+}
+
+bool QuicConnection::OnPacketHeader(const QuicPacketHeader& header) {
+  if (debug_visitor_.get() != nullptr) {
+    debug_visitor_->OnPacketHeader(header);
+  }
+
+  if (!ProcessValidatedPacket()) {
+    return false;
+  }
+
+  // Will be decrement below if we fall through to return true;
+  ++stats_.packets_dropped;
+
+  if (header.public_header.connection_id != connection_id_) {
+    DVLOG(1) << ENDPOINT << "Ignoring packet from unexpected ConnectionId: "
+             << header.public_header.connection_id << " instead of "
+             << connection_id_;
+    if (debug_visitor_.get() != nullptr) {
+      debug_visitor_->OnIncorrectConnectionId(
+          header.public_header.connection_id);
+    }
+    return false;
+  }
+
+  if (!Near(header.packet_sequence_number,
+            last_header_.packet_sequence_number)) {
+    DVLOG(1) << ENDPOINT << "Packet " << header.packet_sequence_number
+             << " out of bounds.  Discarding";
+    SendConnectionCloseWithDetails(QUIC_INVALID_PACKET_HEADER,
+                                   "Packet sequence number out of bounds");
+    return false;
+  }
+
+  // If this packet has already been seen, or that the sender
+  // has told us will not be retransmitted, then stop processing the packet.
+  if (!received_packet_manager_.IsAwaitingPacket(
+          header.packet_sequence_number)) {
+    DVLOG(1) << ENDPOINT << "Packet " << header.packet_sequence_number
+             << " no longer being waited for.  Discarding.";
+    if (debug_visitor_.get() != nullptr) {
+      debug_visitor_->OnDuplicatePacket(header.packet_sequence_number);
+    }
+    return false;
+  }
+
+  if (version_negotiation_state_ != NEGOTIATED_VERSION) {
+    if (is_server_) {
+      if (!header.public_header.version_flag) {
+        DLOG(WARNING) << ENDPOINT << "Packet " << header.packet_sequence_number
+                      << " without version flag before version negotiated.";
+        // Packets should have the version flag till version negotiation is
+        // done.
+        CloseConnection(QUIC_INVALID_VERSION, false);
+        return false;
+      } else {
+        DCHECK_EQ(1u, header.public_header.versions.size());
+        DCHECK_EQ(header.public_header.versions[0], version());
+        version_negotiation_state_ = NEGOTIATED_VERSION;
+        visitor_->OnSuccessfulVersionNegotiation(version());
+        if (debug_visitor_.get() != nullptr) {
+          debug_visitor_->OnSuccessfulVersionNegotiation(version());
+        }
+      }
+    } else {
+      DCHECK(!header.public_header.version_flag);
+      // If the client gets a packet without the version flag from the server
+      // it should stop sending version since the version negotiation is done.
+      packet_generator_.StopSendingVersion();
+      version_negotiation_state_ = NEGOTIATED_VERSION;
+      visitor_->OnSuccessfulVersionNegotiation(version());
+      if (debug_visitor_.get() != nullptr) {
+        debug_visitor_->OnSuccessfulVersionNegotiation(version());
+      }
+    }
+  }
+
+  DCHECK_EQ(NEGOTIATED_VERSION, version_negotiation_state_);
+
+  --stats_.packets_dropped;
+  DVLOG(1) << ENDPOINT << "Received packet header: " << header;
+  last_header_ = header;
+  DCHECK(connected_);
+  return true;
+}
+
+void QuicConnection::OnFecProtectedPayload(StringPiece payload) {
+  DCHECK_EQ(IN_FEC_GROUP, last_header_.is_in_fec_group);
+  DCHECK_NE(0u, last_header_.fec_group);
+  QuicFecGroup* group = GetFecGroup();
+  if (group != nullptr) {
+    group->Update(last_decrypted_packet_level_, last_header_, payload);
+  }
+}
+
+bool QuicConnection::OnStreamFrame(const QuicStreamFrame& frame) {
+  DCHECK(connected_);
+  if (debug_visitor_.get() != nullptr) {
+    debug_visitor_->OnStreamFrame(frame);
+  }
+  if (frame.stream_id != kCryptoStreamId &&
+      last_decrypted_packet_level_ == ENCRYPTION_NONE) {
+    DLOG(WARNING) << ENDPOINT
+                  << "Received an unencrypted data frame: closing connection";
+    SendConnectionClose(QUIC_UNENCRYPTED_STREAM_DATA);
+    return false;
+  }
+  last_stream_frames_.push_back(frame);
+  return true;
+}
+
+bool QuicConnection::OnAckFrame(const QuicAckFrame& incoming_ack) {
+  DCHECK(connected_);
+  if (debug_visitor_.get() != nullptr) {
+    debug_visitor_->OnAckFrame(incoming_ack);
+  }
+  DVLOG(1) << ENDPOINT << "OnAckFrame: " << incoming_ack;
+
+  if (last_header_.packet_sequence_number <= largest_seen_packet_with_ack_) {
+    DVLOG(1) << ENDPOINT << "Received an old ack frame: ignoring";
+    return true;
+  }
+
+  if (!ValidateAckFrame(incoming_ack)) {
+    SendConnectionClose(QUIC_INVALID_ACK_DATA);
+    return false;
+  }
+
+  last_ack_frames_.push_back(incoming_ack);
+  return connected_;
+}
+
+void QuicConnection::ProcessAckFrame(const QuicAckFrame& incoming_ack) {
+  largest_seen_packet_with_ack_ = last_header_.packet_sequence_number;
+  sent_packet_manager_.OnIncomingAck(incoming_ack,
+                                     time_of_last_received_packet_);
+  sent_entropy_manager_.ClearEntropyBefore(
+      sent_packet_manager_.least_packet_awaited_by_peer() - 1);
+  if (sent_packet_manager_.HasPendingRetransmissions()) {
+    WriteIfNotBlocked();
+  }
+
+  // Always reset the retransmission alarm when an ack comes in, since we now
+  // have a better estimate of the current rtt than when it was set.
+  QuicTime retransmission_time = sent_packet_manager_.GetRetransmissionTime();
+  retransmission_alarm_->Update(retransmission_time,
+                                QuicTime::Delta::FromMilliseconds(1));
+}
+
+void QuicConnection::ProcessStopWaitingFrame(
+    const QuicStopWaitingFrame& stop_waiting) {
+  largest_seen_packet_with_stop_waiting_ = last_header_.packet_sequence_number;
+  received_packet_manager_.UpdatePacketInformationSentByPeer(stop_waiting);
+  // Possibly close any FecGroups which are now irrelevant.
+  CloseFecGroupsBefore(stop_waiting.least_unacked + 1);
+}
+
+bool QuicConnection::OnCongestionFeedbackFrame(
+    const QuicCongestionFeedbackFrame& feedback) {
+  DCHECK(connected_);
+  if (debug_visitor_.get() != nullptr) {
+    debug_visitor_->OnCongestionFeedbackFrame(feedback);
+  }
+  last_congestion_frames_.push_back(feedback);
+  return connected_;
+}
+
+bool QuicConnection::OnStopWaitingFrame(const QuicStopWaitingFrame& frame) {
+  DCHECK(connected_);
+
+  if (last_header_.packet_sequence_number <=
+      largest_seen_packet_with_stop_waiting_) {
+    DVLOG(1) << ENDPOINT << "Received an old stop waiting frame: ignoring";
+    return true;
+  }
+
+  if (!ValidateStopWaitingFrame(frame)) {
+    SendConnectionClose(QUIC_INVALID_STOP_WAITING_DATA);
+    return false;
+  }
+
+  if (debug_visitor_.get() != nullptr) {
+    debug_visitor_->OnStopWaitingFrame(frame);
+  }
+
+  last_stop_waiting_frames_.push_back(frame);
+  return connected_;
+}
+
+bool QuicConnection::OnPingFrame(const QuicPingFrame& frame) {
+  DCHECK(connected_);
+  if (debug_visitor_.get() != nullptr) {
+    debug_visitor_->OnPingFrame(frame);
+  }
+  last_ping_frames_.push_back(frame);
+  return true;
+}
+
+bool QuicConnection::ValidateAckFrame(const QuicAckFrame& incoming_ack) {
+  if (incoming_ack.largest_observed > packet_generator_.sequence_number()) {
+    DLOG(ERROR) << ENDPOINT << "Peer's observed unsent packet:"
+                << incoming_ack.largest_observed << " vs "
+                << packet_generator_.sequence_number();
+    // We got an error for data we have not sent.  Error out.
+    return false;
+  }
+
+  if (incoming_ack.largest_observed < sent_packet_manager_.largest_observed()) {
+    DLOG(ERROR) << ENDPOINT << "Peer's largest_observed packet decreased:"
+                << incoming_ack.largest_observed << " vs "
+                << sent_packet_manager_.largest_observed();
+    // A new ack has a diminished largest_observed value.  Error out.
+    // If this was an old packet, we wouldn't even have checked.
+    return false;
+  }
+
+  if (!incoming_ack.missing_packets.empty() &&
+      *incoming_ack.missing_packets.rbegin() > incoming_ack.largest_observed) {
+    DLOG(ERROR) << ENDPOINT << "Peer sent missing packet: "
+                << *incoming_ack.missing_packets.rbegin()
+                << " which is greater than largest observed: "
+                << incoming_ack.largest_observed;
+    return false;
+  }
+
+  if (!incoming_ack.missing_packets.empty() &&
+      *incoming_ack.missing_packets.begin() <
+      sent_packet_manager_.least_packet_awaited_by_peer()) {
+    DLOG(ERROR) << ENDPOINT << "Peer sent missing packet: "
+                << *incoming_ack.missing_packets.begin()
+                << " which is smaller than least_packet_awaited_by_peer_: "
+                << sent_packet_manager_.least_packet_awaited_by_peer();
+    return false;
+  }
+
+  if (!sent_entropy_manager_.IsValidEntropy(
+          incoming_ack.largest_observed,
+          incoming_ack.missing_packets,
+          incoming_ack.entropy_hash)) {
+    DLOG(ERROR) << ENDPOINT << "Peer sent invalid entropy.";
+    return false;
+  }
+
+  for (SequenceNumberSet::const_iterator iter =
+           incoming_ack.revived_packets.begin();
+       iter != incoming_ack.revived_packets.end(); ++iter) {
+    if (!ContainsKey(incoming_ack.missing_packets, *iter)) {
+      DLOG(ERROR) << ENDPOINT
+                  << "Peer specified revived packet which was not missing.";
+      return false;
+    }
+  }
+  return true;
+}
+
+bool QuicConnection::ValidateStopWaitingFrame(
+    const QuicStopWaitingFrame& stop_waiting) {
+  if (stop_waiting.least_unacked <
+      received_packet_manager_.peer_least_packet_awaiting_ack()) {
+    DLOG(ERROR) << ENDPOINT << "Peer's sent low least_unacked: "
+                << stop_waiting.least_unacked << " vs "
+                << received_packet_manager_.peer_least_packet_awaiting_ack();
+    // We never process old ack frames, so this number should only increase.
+    return false;
+  }
+
+  if (stop_waiting.least_unacked >
+      last_header_.packet_sequence_number) {
+    DLOG(ERROR) << ENDPOINT << "Peer sent least_unacked:"
+                << stop_waiting.least_unacked
+                << " greater than the enclosing packet sequence number:"
+                << last_header_.packet_sequence_number;
+    return false;
+  }
+
+  return true;
+}
+
+void QuicConnection::OnFecData(const QuicFecData& fec) {
+  DCHECK_EQ(IN_FEC_GROUP, last_header_.is_in_fec_group);
+  DCHECK_NE(0u, last_header_.fec_group);
+  QuicFecGroup* group = GetFecGroup();
+  if (group != nullptr) {
+    group->UpdateFec(last_decrypted_packet_level_,
+                     last_header_.packet_sequence_number, fec);
+  }
+}
+
+bool QuicConnection::OnRstStreamFrame(const QuicRstStreamFrame& frame) {
+  DCHECK(connected_);
+  if (debug_visitor_.get() != nullptr) {
+    debug_visitor_->OnRstStreamFrame(frame);
+  }
+  DVLOG(1) << ENDPOINT << "Stream reset with error "
+           << QuicUtils::StreamErrorToString(frame.error_code);
+  last_rst_frames_.push_back(frame);
+  return connected_;
+}
+
+bool QuicConnection::OnConnectionCloseFrame(
+    const QuicConnectionCloseFrame& frame) {
+  DCHECK(connected_);
+  if (debug_visitor_.get() != nullptr) {
+    debug_visitor_->OnConnectionCloseFrame(frame);
+  }
+  DVLOG(1) << ENDPOINT << "Connection " << connection_id()
+           << " closed with error "
+           << QuicUtils::ErrorToString(frame.error_code)
+           << " " << frame.error_details;
+  last_close_frames_.push_back(frame);
+  return connected_;
+}
+
+bool QuicConnection::OnGoAwayFrame(const QuicGoAwayFrame& frame) {
+  DCHECK(connected_);
+  if (debug_visitor_.get() != nullptr) {
+    debug_visitor_->OnGoAwayFrame(frame);
+  }
+  DVLOG(1) << ENDPOINT << "Go away received with error "
+           << QuicUtils::ErrorToString(frame.error_code)
+           << " and reason:" << frame.reason_phrase;
+  last_goaway_frames_.push_back(frame);
+  return connected_;
+}
+
+bool QuicConnection::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) {
+  DCHECK(connected_);
+  if (debug_visitor_.get() != nullptr) {
+    debug_visitor_->OnWindowUpdateFrame(frame);
+  }
+  DVLOG(1) << ENDPOINT << "WindowUpdate received for stream: "
+           << frame.stream_id << " with byte offset: " << frame.byte_offset;
+  last_window_update_frames_.push_back(frame);
+  return connected_;
+}
+
+bool QuicConnection::OnBlockedFrame(const QuicBlockedFrame& frame) {
+  DCHECK(connected_);
+  if (debug_visitor_.get() != nullptr) {
+    debug_visitor_->OnBlockedFrame(frame);
+  }
+  DVLOG(1) << ENDPOINT << "Blocked frame received for stream: "
+           << frame.stream_id;
+  last_blocked_frames_.push_back(frame);
+  return connected_;
+}
+
+void QuicConnection::OnPacketComplete() {
+  // Don't do anything if this packet closed the connection.
+  if (!connected_) {
+    ClearLastFrames();
+    return;
+  }
+
+  DVLOG(1) << ENDPOINT << (last_packet_revived_ ? "Revived" : "Got")
+           << " packet " << last_header_.packet_sequence_number
+           << " with " << last_stream_frames_.size()<< " stream frames "
+           << last_ack_frames_.size() << " acks, "
+           << last_congestion_frames_.size() << " congestions, "
+           << last_stop_waiting_frames_.size() << " stop_waiting, "
+           << last_rst_frames_.size() << " rsts, "
+           << last_goaway_frames_.size() << " goaways, "
+           << last_window_update_frames_.size() << " window updates, "
+           << last_blocked_frames_.size() << " blocked, "
+           << last_ping_frames_.size() << " pings, "
+           << last_close_frames_.size() << " closes, "
+           << "for " << last_header_.public_header.connection_id;
+
+  ++num_packets_received_since_last_ack_sent_;
+
+  // Call MaybeQueueAck() before recording the received packet, since we want
+  // to trigger an ack if the newly received packet was previously missing.
+  MaybeQueueAck();
+
+  // Record received or revived packet to populate ack info correctly before
+  // processing stream frames, since the processing may result in a response
+  // packet with a bundled ack.
+  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_);
+  }
+
+  if (!last_stream_frames_.empty()) {
+    visitor_->OnStreamFrames(last_stream_frames_);
+  }
+
+  for (size_t i = 0; i < last_stream_frames_.size(); ++i) {
+    stats_.stream_bytes_received +=
+        last_stream_frames_[i].data.TotalBufferSize();
+  }
+
+  // Process window updates, blocked, stream resets, acks, then congestion
+  // feedback.
+  if (!last_window_update_frames_.empty()) {
+    visitor_->OnWindowUpdateFrames(last_window_update_frames_);
+  }
+  if (!last_blocked_frames_.empty()) {
+    visitor_->OnBlockedFrames(last_blocked_frames_);
+  }
+  for (size_t i = 0; i < last_goaway_frames_.size(); ++i) {
+    visitor_->OnGoAway(last_goaway_frames_[i]);
+  }
+  for (size_t i = 0; i < last_rst_frames_.size(); ++i) {
+    visitor_->OnRstStream(last_rst_frames_[i]);
+  }
+  for (size_t i = 0; i < last_ack_frames_.size(); ++i) {
+    ProcessAckFrame(last_ack_frames_[i]);
+  }
+  for (size_t i = 0; i < last_congestion_frames_.size(); ++i) {
+    sent_packet_manager_.OnIncomingQuicCongestionFeedbackFrame(
+        last_congestion_frames_[i], time_of_last_received_packet_);
+  }
+  for (size_t i = 0; i < last_stop_waiting_frames_.size(); ++i) {
+    ProcessStopWaitingFrame(last_stop_waiting_frames_[i]);
+  }
+  if (!last_close_frames_.empty()) {
+    CloseConnection(last_close_frames_[0].error_code, true);
+    DCHECK(!connected_);
+  }
+
+  // If there are new missing packets to report, send an ack immediately.
+  if (received_packet_manager_.HasNewMissingPackets()) {
+    ack_queued_ = true;
+    ack_alarm_->Cancel();
+  }
+
+  UpdateStopWaitingCount();
+
+  ClearLastFrames();
+}
+
+void QuicConnection::MaybeQueueAck() {
+  // If the incoming packet was missing, send an ack immediately.
+  ack_queued_ = received_packet_manager_.IsMissing(
+      last_header_.packet_sequence_number);
+
+  if (!ack_queued_ && ShouldLastPacketInstigateAck()) {
+    if (ack_alarm_->IsSet()) {
+      ack_queued_ = true;
+    } else {
+      // Send an ack much more quickly for crypto handshake packets.
+      QuicTime::Delta delayed_ack_time = sent_packet_manager_.DelayedAckTime();
+      if (last_stream_frames_.size() == 1 &&
+          last_stream_frames_[0].stream_id == kCryptoStreamId) {
+        delayed_ack_time = QuicTime::Delta::Zero();
+      }
+      ack_alarm_->Set(clock_->ApproximateNow().Add(delayed_ack_time));
+      DVLOG(1) << "Ack timer set; next packet or timer will trigger ACK.";
+    }
+  }
+
+  if (ack_queued_) {
+    ack_alarm_->Cancel();
+  }
+}
+
+void QuicConnection::ClearLastFrames() {
+  last_stream_frames_.clear();
+  last_ack_frames_.clear();
+  last_congestion_frames_.clear();
+  last_stop_waiting_frames_.clear();
+  last_rst_frames_.clear();
+  last_goaway_frames_.clear();
+  last_window_update_frames_.clear();
+  last_blocked_frames_.clear();
+  last_ping_frames_.clear();
+  last_close_frames_.clear();
+}
+
+QuicAckFrame* QuicConnection::CreateAckFrame() {
+  QuicAckFrame* outgoing_ack = new QuicAckFrame();
+  received_packet_manager_.UpdateReceivedPacketInfo(
+      outgoing_ack, clock_->ApproximateNow());
+  DVLOG(1) << ENDPOINT << "Creating ack frame: " << *outgoing_ack;
+  return outgoing_ack;
+}
+
+QuicCongestionFeedbackFrame* QuicConnection::CreateFeedbackFrame() {
+  return new QuicCongestionFeedbackFrame(outgoing_congestion_feedback_);
+}
+
+QuicStopWaitingFrame* QuicConnection::CreateStopWaitingFrame() {
+  QuicStopWaitingFrame stop_waiting;
+  UpdateStopWaiting(&stop_waiting);
+  return new QuicStopWaitingFrame(stop_waiting);
+}
+
+bool QuicConnection::ShouldLastPacketInstigateAck() const {
+  if (!last_stream_frames_.empty() ||
+      !last_goaway_frames_.empty() ||
+      !last_rst_frames_.empty() ||
+      !last_window_update_frames_.empty() ||
+      !last_blocked_frames_.empty() ||
+      !last_ping_frames_.empty()) {
+    return true;
+  }
+
+  if (!last_ack_frames_.empty() && last_ack_frames_.back().is_truncated) {
+    return true;
+  }
+  // Always send an ack every 20 packets in order to allow the peer to discard
+  // information from the SentPacketManager and provide an RTT measurement.
+  if (num_packets_received_since_last_ack_sent_ >=
+          kMaxPacketsReceivedBeforeAckSend) {
+    return true;
+  }
+  return false;
+}
+
+void QuicConnection::UpdateStopWaitingCount() {
+  if (last_ack_frames_.empty()) {
+    return;
+  }
+
+  // If the peer is still waiting for a packet that we are no longer planning to
+  // send, send an ack to raise the high water mark.
+  if (!last_ack_frames_.back().missing_packets.empty() &&
+      GetLeastUnacked() > *last_ack_frames_.back().missing_packets.begin()) {
+    ++stop_waiting_count_;
+  } else {
+    stop_waiting_count_ = 0;
+  }
+}
+
+QuicPacketSequenceNumber QuicConnection::GetLeastUnacked() const {
+  return sent_packet_manager_.GetLeastUnacked();
+}
+
+void QuicConnection::MaybeSendInResponseToPacket() {
+  if (!connected_) {
+    return;
+  }
+  ScopedPacketBundler bundler(this, ack_queued_ ? SEND_ACK : NO_ACK);
+
+  // Now that we have received an ack, we might be able to send packets which
+  // are queued locally, or drain streams which are blocked.
+  if (CanWrite(HAS_RETRANSMITTABLE_DATA)) {
+    OnCanWrite();
+  }
+}
+
+void QuicConnection::SendVersionNegotiationPacket() {
+  // TODO(alyssar): implement zero server state negotiation.
+  pending_version_negotiation_packet_ = true;
+  if (writer_->IsWriteBlocked()) {
+    visitor_->OnWriteBlocked();
+    return;
+  }
+  DVLOG(1) << ENDPOINT << "Sending version negotiation packet: {"
+           << QuicVersionVectorToString(framer_.supported_versions()) << "}";
+  scoped_ptr<QuicEncryptedPacket> version_packet(
+      packet_generator_.SerializeVersionNegotiationPacket(
+          framer_.supported_versions()));
+  WriteResult result = writer_->WritePacket(
+      version_packet->data(), version_packet->length(),
+      self_address().address(), peer_address());
+
+  if (result.status == WRITE_STATUS_ERROR) {
+    // We can't send an error as the socket is presumably borked.
+    CloseConnection(QUIC_PACKET_WRITE_ERROR, false);
+    return;
+  }
+  if (result.status == WRITE_STATUS_BLOCKED) {
+    visitor_->OnWriteBlocked();
+    if (writer_->IsWriteBlockedDataBuffered()) {
+      pending_version_negotiation_packet_ = false;
+    }
+    return;
+  }
+
+  pending_version_negotiation_packet_ = false;
+}
+
+QuicConsumedData QuicConnection::SendStreamData(
+    QuicStreamId id,
+    const IOVector& data,
+    QuicStreamOffset offset,
+    bool fin,
+    FecProtection fec_protection,
+    QuicAckNotifier::DelegateInterface* delegate) {
+  if (!fin && data.Empty()) {
+    LOG(DFATAL) << "Attempt to send empty stream frame";
+  }
+
+  // This notifier will be owned by the AckNotifierManager (or deleted below if
+  // no data or FIN was consumed).
+  QuicAckNotifier* notifier = nullptr;
+  if (delegate) {
+    notifier = new QuicAckNotifier(delegate);
+  }
+
+  // Opportunistically bundle an ack with every outgoing packet.
+  // Particularly, we want to bundle with handshake packets since we don't know
+  // which decrypter will be used on an ack packet following a handshake
+  // packet (a handshake packet from client to server could result in a REJ or a
+  // SHLO from the server, leading to two different decrypters at the server.)
+  //
+  // TODO(jri): Note that ConsumeData may cause a response packet to be sent.
+  // We may end up sending stale ack information if there are undecryptable
+  // packets hanging around and/or there are revivable packets which may get
+  // handled after this packet is sent. Change ScopedPacketBundler to do the
+  // right thing: check ack_queued_, and then check undecryptable packets and
+  // also if there is possibility of revival. Only bundle an ack if there's no
+  // processing left that may cause received_info_ to change.
+  ScopedPacketBundler ack_bundler(this, BUNDLE_PENDING_ACK);
+  QuicConsumedData consumed_data =
+      packet_generator_.ConsumeData(id, data, offset, fin, fec_protection,
+                                    notifier);
+
+  if (notifier &&
+      (consumed_data.bytes_consumed == 0 && !consumed_data.fin_consumed)) {
+    // No data was consumed, nor was a fin consumed, so delete the notifier.
+    delete notifier;
+  }
+
+  return consumed_data;
+}
+
+void QuicConnection::SendRstStream(QuicStreamId id,
+                                   QuicRstStreamErrorCode error,
+                                   QuicStreamOffset bytes_written) {
+  // Opportunistically bundle an ack with this outgoing packet.
+  ScopedPacketBundler ack_bundler(this, BUNDLE_PENDING_ACK);
+  packet_generator_.AddControlFrame(QuicFrame(new QuicRstStreamFrame(
+      id, AdjustErrorForVersion(error, version()), bytes_written)));
+}
+
+void QuicConnection::SendWindowUpdate(QuicStreamId id,
+                                      QuicStreamOffset byte_offset) {
+  // Opportunistically bundle an ack with this outgoing packet.
+  ScopedPacketBundler ack_bundler(this, BUNDLE_PENDING_ACK);
+  packet_generator_.AddControlFrame(
+      QuicFrame(new QuicWindowUpdateFrame(id, byte_offset)));
+}
+
+void QuicConnection::SendBlocked(QuicStreamId id) {
+  // Opportunistically bundle an ack with this outgoing packet.
+  ScopedPacketBundler ack_bundler(this, BUNDLE_PENDING_ACK);
+  packet_generator_.AddControlFrame(QuicFrame(new QuicBlockedFrame(id)));
+}
+
+const QuicConnectionStats& QuicConnection::GetStats() {
+  // Update rtt and estimated bandwidth.
+  stats_.min_rtt_us =
+      sent_packet_manager_.GetRttStats()->min_rtt().ToMicroseconds();
+  stats_.srtt_us =
+      sent_packet_manager_.GetRttStats()->SmoothedRtt().ToMicroseconds();
+  stats_.estimated_bandwidth =
+      sent_packet_manager_.BandwidthEstimate().ToBytesPerSecond();
+  stats_.congestion_window = sent_packet_manager_.GetCongestionWindow();
+  stats_.slow_start_threshold = sent_packet_manager_.GetSlowStartThreshold();
+  stats_.max_packet_size = packet_generator_.max_packet_length();
+  return stats_;
+}
+
+void QuicConnection::ProcessUdpPacket(const IPEndPoint& self_address,
+                                      const IPEndPoint& peer_address,
+                                      const QuicEncryptedPacket& packet) {
+  if (!connected_) {
+    return;
+  }
+  if (debug_visitor_.get() != nullptr) {
+    debug_visitor_->OnPacketReceived(self_address, peer_address, packet);
+  }
+  last_packet_revived_ = false;
+  last_size_ = packet.length();
+
+  CheckForAddressMigration(self_address, peer_address);
+
+  stats_.bytes_received += packet.length();
+  ++stats_.packets_received;
+
+  if (!framer_.ProcessPacket(packet)) {
+    // If we are unable to decrypt this packet, it might be
+    // because the CHLO or SHLO packet was lost.
+    if (framer_.error() == QUIC_DECRYPTION_FAILURE) {
+      if (encryption_level_ != ENCRYPTION_FORWARD_SECURE &&
+          undecryptable_packets_.size() < kMaxUndecryptablePackets) {
+        QueueUndecryptablePacket(packet);
+      } else if (debug_visitor_.get() != nullptr) {
+        debug_visitor_->OnUndecryptablePacket();
+      }
+    }
+    DVLOG(1) << ENDPOINT << "Unable to process packet.  Last packet processed: "
+             << last_header_.packet_sequence_number;
+    return;
+  }
+
+  ++stats_.packets_processed;
+  MaybeProcessUndecryptablePackets();
+  MaybeProcessRevivedPacket();
+  MaybeSendInResponseToPacket();
+  SetPingAlarm();
+}
+
+void QuicConnection::CheckForAddressMigration(
+    const IPEndPoint& self_address, const IPEndPoint& peer_address) {
+  peer_ip_changed_ = false;
+  peer_port_changed_ = false;
+  self_ip_changed_ = false;
+  self_port_changed_ = false;
+
+  if (peer_address_.address().empty()) {
+    peer_address_ = peer_address;
+  }
+  if (self_address_.address().empty()) {
+    self_address_ = self_address;
+  }
+
+  if (!peer_address.address().empty() && !peer_address_.address().empty()) {
+    peer_ip_changed_ = (peer_address.address() != peer_address_.address());
+    peer_port_changed_ = (peer_address.port() != peer_address_.port());
+
+    // Store in case we want to migrate connection in ProcessValidatedPacket.
+    migrating_peer_port_ = peer_address.port();
+  }
+
+  if (!self_address.address().empty() && !self_address_.address().empty()) {
+    self_ip_changed_ = (self_address.address() != self_address_.address());
+    self_port_changed_ = (self_address.port() != self_address_.port());
+  }
+}
+
+void QuicConnection::OnCanWrite() {
+  DCHECK(!writer_->IsWriteBlocked());
+
+  WriteQueuedPackets();
+  WritePendingRetransmissions();
+
+  // Sending queued packets may have caused the socket to become write blocked,
+  // or the congestion manager to prohibit sending.  If we've sent everything
+  // we had queued and we're still not blocked, let the visitor know it can
+  // write more.
+  if (!CanWrite(HAS_RETRANSMITTABLE_DATA)) {
+    return;
+  }
+
+  {  // Limit the scope of the bundler.
+    // Set |include_ack| to false in bundler; ack inclusion happens elsewhere.
+    ScopedPacketBundler bundler(this, NO_ACK);
+    visitor_->OnCanWrite();
+  }
+
+  // After the visitor writes, it may have caused the socket to become write
+  // blocked or the congestion manager to prohibit sending, so check again.
+  if (visitor_->WillingAndAbleToWrite() &&
+      !resume_writes_alarm_->IsSet() &&
+      CanWrite(HAS_RETRANSMITTABLE_DATA)) {
+    // We're not write blocked, but some stream didn't write out all of its
+    // bytes. Register for 'immediate' resumption so we'll keep writing after
+    // other connections and events have had a chance to use the thread.
+    resume_writes_alarm_->Set(clock_->ApproximateNow());
+  }
+}
+
+void QuicConnection::WriteIfNotBlocked() {
+  if (!writer_->IsWriteBlocked()) {
+    OnCanWrite();
+  }
+}
+
+bool QuicConnection::ProcessValidatedPacket() {
+  if (peer_ip_changed_ || self_ip_changed_ || self_port_changed_) {
+    SendConnectionCloseWithDetails(
+        QUIC_ERROR_MIGRATING_ADDRESS,
+        "Neither IP address migration, nor self port migration are supported.");
+    return false;
+  }
+
+  // Peer port migration is supported, do it now if port has changed.
+  if (peer_port_changed_) {
+    DVLOG(1) << ENDPOINT << "Peer's port changed from "
+             << peer_address_.port() << " to " << migrating_peer_port_
+             << ", migrating connection.";
+    peer_address_ = IPEndPoint(peer_address_.address(), migrating_peer_port_);
+  }
+
+  time_of_last_received_packet_ = clock_->Now();
+  DVLOG(1) << ENDPOINT << "time of last received packet: "
+           << time_of_last_received_packet_.ToDebuggingValue();
+
+  if (is_server_ && encryption_level_ == ENCRYPTION_NONE &&
+      last_size_ > packet_generator_.max_packet_length()) {
+    packet_generator_.set_max_packet_length(last_size_);
+  }
+  return true;
+}
+
+void QuicConnection::WriteQueuedPackets() {
+  DCHECK(!writer_->IsWriteBlocked());
+
+  if (pending_version_negotiation_packet_) {
+    SendVersionNegotiationPacket();
+  }
+
+  QueuedPacketList::iterator packet_iterator = queued_packets_.begin();
+  while (packet_iterator != queued_packets_.end() &&
+         WritePacket(&(*packet_iterator))) {
+    packet_iterator = queued_packets_.erase(packet_iterator);
+  }
+}
+
+void QuicConnection::WritePendingRetransmissions() {
+  // Keep writing as long as there's a pending retransmission which can be
+  // written.
+  while (sent_packet_manager_.HasPendingRetransmissions()) {
+    const QuicSentPacketManager::PendingRetransmission pending =
+        sent_packet_manager_.NextPendingRetransmission();
+    if (!CanWrite(HAS_RETRANSMITTABLE_DATA)) {
+      break;
+    }
+
+    // Re-packetize the frames with a new sequence number for retransmission.
+    // Retransmitted data packets do not use FEC, even when it's enabled.
+    // Retransmitted packets use the same sequence number length as the
+    // original.
+    // Flush the packet generator before making a new packet.
+    // TODO(ianswett): Implement ReserializeAllFrames as a separate path that
+    // does not require the creator to be flushed.
+    packet_generator_.FlushAllQueuedFrames();
+    SerializedPacket serialized_packet = packet_generator_.ReserializeAllFrames(
+        pending.retransmittable_frames.frames(),
+        pending.sequence_number_length);
+
+    DVLOG(1) << ENDPOINT << "Retransmitting " << pending.sequence_number
+             << " as " << serialized_packet.sequence_number;
+    SendOrQueuePacket(
+        QueuedPacket(serialized_packet,
+                     pending.retransmittable_frames.encryption_level(),
+                     pending.transmission_type,
+                     pending.sequence_number));
+  }
+}
+
+void QuicConnection::RetransmitUnackedPackets(
+    TransmissionType retransmission_type) {
+  sent_packet_manager_.RetransmitUnackedPackets(retransmission_type);
+
+  WriteIfNotBlocked();
+}
+
+void QuicConnection::NeuterUnencryptedPackets() {
+  sent_packet_manager_.NeuterUnencryptedPackets();
+  // This may have changed the retransmission timer, so re-arm it.
+  QuicTime retransmission_time = sent_packet_manager_.GetRetransmissionTime();
+  retransmission_alarm_->Update(retransmission_time,
+                                QuicTime::Delta::FromMilliseconds(1));
+}
+
+bool QuicConnection::ShouldGeneratePacket(
+    TransmissionType transmission_type,
+    HasRetransmittableData retransmittable,
+    IsHandshake handshake) {
+  // We should serialize handshake packets immediately to ensure that they
+  // end up sent at the right encryption level.
+  if (handshake == IS_HANDSHAKE) {
+    return true;
+  }
+
+  return CanWrite(retransmittable);
+}
+
+bool QuicConnection::CanWrite(HasRetransmittableData retransmittable) {
+  if (!connected_) {
+    return false;
+  }
+
+  if (writer_->IsWriteBlocked()) {
+    visitor_->OnWriteBlocked();
+    return false;
+  }
+
+  QuicTime now = clock_->Now();
+  QuicTime::Delta delay = sent_packet_manager_.TimeUntilSend(
+      now, retransmittable);
+  if (delay.IsInfinite()) {
+    send_alarm_->Cancel();
+    return false;
+  }
+
+  // If the scheduler requires a delay, then we can not send this packet now.
+  if (!delay.IsZero()) {
+    send_alarm_->Update(now.Add(delay), QuicTime::Delta::FromMilliseconds(1));
+    DVLOG(1) << "Delaying sending.";
+    return false;
+  }
+  send_alarm_->Cancel();
+  return true;
+}
+
+bool QuicConnection::WritePacket(QueuedPacket* packet) {
+  if (!WritePacketInner(packet)) {
+    return false;
+  }
+  delete packet->serialized_packet.retransmittable_frames;
+  delete packet->serialized_packet.packet;
+  packet->serialized_packet.retransmittable_frames = nullptr;
+  packet->serialized_packet.packet = nullptr;
+  return true;
+}
+
+bool QuicConnection::WritePacketInner(QueuedPacket* packet) {
+  if (ShouldDiscardPacket(*packet)) {
+    ++stats_.packets_discarded;
+    return true;
+  }
+  // Connection close packets are encrypted and saved, so don't exit early.
+  if (writer_->IsWriteBlocked() && !IsConnectionClose(*packet)) {
+    return false;
+  }
+
+  QuicPacketSequenceNumber sequence_number =
+      packet->serialized_packet.sequence_number;
+  DCHECK_LE(sequence_number_of_last_sent_packet_, sequence_number);
+  sequence_number_of_last_sent_packet_ = sequence_number;
+
+  QuicEncryptedPacket* encrypted = framer_.EncryptPacket(
+      packet->encryption_level,
+      sequence_number,
+      *packet->serialized_packet.packet);
+  if (encrypted == nullptr) {
+    LOG(DFATAL) << ENDPOINT << "Failed to encrypt packet number "
+                << sequence_number;
+    // CloseConnection does not send close packet, so no infinite loop here.
+    CloseConnection(QUIC_ENCRYPTION_FAILURE, false);
+    return false;
+  }
+
+  // Connection close packets are eventually owned by TimeWaitListManager.
+  // Others are deleted at the end of this call.
+  scoped_ptr<QuicEncryptedPacket> encrypted_deleter;
+  if (IsConnectionClose(*packet)) {
+    DCHECK(connection_close_packet_.get() == nullptr);
+    connection_close_packet_.reset(encrypted);
+    // This assures we won't try to write *forced* packets when blocked.
+    // Return true to stop processing.
+    if (writer_->IsWriteBlocked()) {
+      visitor_->OnWriteBlocked();
+      return true;
+    }
+  } else {
+    encrypted_deleter.reset(encrypted);
+  }
+
+  if (!FLAGS_quic_allow_oversized_packets_for_test) {
+    DCHECK_LE(encrypted->length(), kMaxPacketSize);
+  }
+  DCHECK_LE(encrypted->length(), packet_generator_.max_packet_length());
+  DVLOG(1) << ENDPOINT << "Sending packet " << sequence_number << " : "
+           << (packet->serialized_packet.packet->is_fec_packet() ? "FEC " :
+               (IsRetransmittable(*packet) == HAS_RETRANSMITTABLE_DATA
+                ? "data bearing " : " ack only "))
+           << ", encryption level: "
+           << QuicUtils::EncryptionLevelToString(packet->encryption_level)
+           << ", length:"
+           << packet->serialized_packet.packet->length()
+           << ", encrypted length:"
+           << encrypted->length();
+  DVLOG(2) << ENDPOINT << "packet(" << sequence_number << "): " << std::endl
+           << QuicUtils::StringToHexASCIIDump(
+               packet->serialized_packet.packet->AsStringPiece());
+
+  WriteResult result = writer_->WritePacket(encrypted->data(),
+                                            encrypted->length(),
+                                            self_address().address(),
+                                            peer_address());
+  if (result.error_code == ERR_IO_PENDING) {
+    DCHECK_EQ(WRITE_STATUS_BLOCKED, result.status);
+  }
+  if (debug_visitor_.get() != nullptr) {
+    // Pass the write result to the visitor.
+    debug_visitor_->OnPacketSent(sequence_number,
+                                 packet->original_sequence_number,
+                                 packet->encryption_level,
+                                 packet->transmission_type,
+                                 *encrypted,
+                                 result);
+  }
+
+  if (result.status == WRITE_STATUS_BLOCKED) {
+    visitor_->OnWriteBlocked();
+    // If the socket buffers the the data, then the packet should not
+    // be queued and sent again, which would result in an unnecessary
+    // duplicate packet being sent.  The helper must call OnCanWrite
+    // when the write completes, and OnWriteError if an error occurs.
+    if (!writer_->IsWriteBlockedDataBuffered()) {
+      return false;
+    }
+  }
+  QuicTime now = clock_->Now();
+  if (packet->transmission_type == NOT_RETRANSMISSION) {
+    time_of_last_sent_new_packet_ = now;
+  }
+  SetPingAlarm();
+  DVLOG(1) << ENDPOINT << "time of last sent packet: "
+           << now.ToDebuggingValue();
+
+  // TODO(ianswett): Change the sequence number length and other packet creator
+  // options by a more explicit API than setting a struct value directly,
+  // perhaps via the NetworkChangeVisitor.
+  packet_generator_.UpdateSequenceNumberLength(
+      sent_packet_manager_.least_packet_awaited_by_peer(),
+      sent_packet_manager_.GetCongestionWindow());
+
+  bool reset_retransmission_alarm = sent_packet_manager_.OnPacketSent(
+      &packet->serialized_packet,
+      packet->original_sequence_number,
+      now,
+      encrypted->length(),
+      packet->transmission_type,
+      IsRetransmittable(*packet));
+
+  if (reset_retransmission_alarm || !retransmission_alarm_->IsSet()) {
+    retransmission_alarm_->Update(sent_packet_manager_.GetRetransmissionTime(),
+                                  QuicTime::Delta::FromMilliseconds(1));
+  }
+
+  stats_.bytes_sent += result.bytes_written;
+  ++stats_.packets_sent;
+  if (packet->transmission_type != NOT_RETRANSMISSION) {
+    stats_.bytes_retransmitted += result.bytes_written;
+    ++stats_.packets_retransmitted;
+  }
+
+  if (result.status == WRITE_STATUS_ERROR) {
+    OnWriteError(result.error_code);
+    return false;
+  }
+
+  return true;
+}
+
+bool QuicConnection::ShouldDiscardPacket(const QueuedPacket& packet) {
+  if (!connected_) {
+    DVLOG(1) << ENDPOINT
+             << "Not sending packet as connection is disconnected.";
+    return true;
+  }
+
+  QuicPacketSequenceNumber sequence_number =
+      packet.serialized_packet.sequence_number;
+  if (encryption_level_ == ENCRYPTION_FORWARD_SECURE &&
+      packet.encryption_level == ENCRYPTION_NONE) {
+    // Drop packets that are NULL encrypted since the peer won't accept them
+    // anymore.
+    DVLOG(1) << ENDPOINT << "Dropping NULL encrypted packet: "
+             << sequence_number << " since the connection is forward secure.";
+    return true;
+  }
+
+  // If a retransmission has been acked before sending, don't send it.
+  // This occurs if a packet gets serialized, queued, then discarded.
+  if (packet.transmission_type != NOT_RETRANSMISSION &&
+      (!sent_packet_manager_.IsUnacked(packet.original_sequence_number) ||
+       !sent_packet_manager_.HasRetransmittableFrames(
+           packet.original_sequence_number))) {
+    DVLOG(1) << ENDPOINT << "Dropping unacked packet: " << sequence_number
+             << " A previous transmission was acked while write blocked.";
+    return true;
+  }
+
+  return false;
+}
+
+void QuicConnection::OnWriteError(int error_code) {
+  DVLOG(1) << ENDPOINT << "Write failed with error: " << error_code
+           << " (" << ErrorToString(error_code) << ")";
+  // We can't send an error as the socket is presumably borked.
+  CloseConnection(QUIC_PACKET_WRITE_ERROR, false);
+}
+
+void QuicConnection::OnSerializedPacket(
+    const SerializedPacket& serialized_packet) {
+  if (serialized_packet.retransmittable_frames) {
+    serialized_packet.retransmittable_frames->
+        set_encryption_level(encryption_level_);
+  }
+  SendOrQueuePacket(QueuedPacket(serialized_packet, encryption_level_));
+}
+
+void QuicConnection::OnCongestionWindowChange(QuicByteCount congestion_window) {
+  packet_generator_.OnCongestionWindowChange(congestion_window);
+  visitor_->OnCongestionWindowChange(clock_->ApproximateNow());
+}
+
+void QuicConnection::OnHandshakeComplete() {
+  sent_packet_manager_.SetHandshakeConfirmed();
+}
+
+void QuicConnection::SendOrQueuePacket(QueuedPacket packet) {
+  // The caller of this function is responsible for checking CanWrite().
+  if (packet.serialized_packet.packet == nullptr) {
+    LOG(DFATAL)
+        << "packet.serialized_packet.packet == nullptr in to SendOrQueuePacket";
+    return;
+  }
+
+  sent_entropy_manager_.RecordPacketEntropyHash(
+      packet.serialized_packet.sequence_number,
+      packet.serialized_packet.entropy_hash);
+  LOG_IF(DFATAL, !queued_packets_.empty() && !writer_->IsWriteBlocked())
+      << "Packets should only be left queued if we're write blocked.";
+  if (!WritePacket(&packet)) {
+    queued_packets_.push_back(packet);
+  }
+}
+
+void QuicConnection::UpdateStopWaiting(QuicStopWaitingFrame* stop_waiting) {
+  stop_waiting->least_unacked = GetLeastUnacked();
+  stop_waiting->entropy_hash = sent_entropy_manager_.GetCumulativeEntropy(
+      stop_waiting->least_unacked - 1);
+}
+
+void QuicConnection::SendPing() {
+  if (retransmission_alarm_->IsSet()) {
+    return;
+  }
+  packet_generator_.AddControlFrame(QuicFrame(new QuicPingFrame));
+}
+
+void QuicConnection::SendAck() {
+  ack_alarm_->Cancel();
+  stop_waiting_count_ = 0;
+  num_packets_received_since_last_ack_sent_ = 0;
+  bool send_feedback = false;
+
+  // Deprecating the Congestion Feedback Frame after QUIC_VERSION_22.
+  if (version() <= QUIC_VERSION_22) {
+    if (received_packet_manager_.GenerateCongestionFeedback(
+            &outgoing_congestion_feedback_)) {
+      DVLOG(1) << ENDPOINT << "Sending feedback: "
+               << outgoing_congestion_feedback_;
+      send_feedback = true;
+    }
+  }
+
+  packet_generator_.SetShouldSendAck(send_feedback, true);
+}
+
+void QuicConnection::OnRetransmissionTimeout() {
+  if (!sent_packet_manager_.HasUnackedPackets()) {
+    return;
+  }
+
+  sent_packet_manager_.OnRetransmissionTimeout();
+  WriteIfNotBlocked();
+
+  // A write failure can result in the connection being closed, don't attempt to
+  // write further packets, or to set alarms.
+  if (!connected_) {
+    return;
+  }
+
+  // In the TLP case, the SentPacketManager gives the connection the opportunity
+  // to send new data before retransmitting.
+  if (sent_packet_manager_.MaybeRetransmitTailLossProbe()) {
+    // Send the pending retransmission now that it's been queued.
+    WriteIfNotBlocked();
+  }
+
+  // Ensure the retransmission alarm is always set if there are unacked packets
+  // and nothing waiting to be sent.
+  if (!HasQueuedData() && !retransmission_alarm_->IsSet()) {
+    QuicTime rto_timeout = sent_packet_manager_.GetRetransmissionTime();
+    if (rto_timeout.IsInitialized()) {
+      retransmission_alarm_->Set(rto_timeout);
+    }
+  }
+}
+
+void QuicConnection::SetEncrypter(EncryptionLevel level,
+                                  QuicEncrypter* encrypter) {
+  framer_.SetEncrypter(level, encrypter);
+}
+
+const QuicEncrypter* QuicConnection::encrypter(EncryptionLevel level) const {
+  return framer_.encrypter(level);
+}
+
+void QuicConnection::SetDefaultEncryptionLevel(EncryptionLevel level) {
+  encryption_level_ = level;
+  packet_generator_.set_encryption_level(level);
+}
+
+void QuicConnection::SetDecrypter(QuicDecrypter* decrypter,
+                                  EncryptionLevel level) {
+  framer_.SetDecrypter(decrypter, level);
+}
+
+void QuicConnection::SetAlternativeDecrypter(QuicDecrypter* decrypter,
+                                             EncryptionLevel level,
+                                             bool latch_once_used) {
+  framer_.SetAlternativeDecrypter(decrypter, level, latch_once_used);
+}
+
+const QuicDecrypter* QuicConnection::decrypter() const {
+  return framer_.decrypter();
+}
+
+const QuicDecrypter* QuicConnection::alternative_decrypter() const {
+  return framer_.alternative_decrypter();
+}
+
+void QuicConnection::QueueUndecryptablePacket(
+    const QuicEncryptedPacket& packet) {
+  DVLOG(1) << ENDPOINT << "Queueing undecryptable packet.";
+  undecryptable_packets_.push_back(packet.Clone());
+}
+
+void QuicConnection::MaybeProcessUndecryptablePackets() {
+  if (undecryptable_packets_.empty() || encryption_level_ == ENCRYPTION_NONE) {
+    return;
+  }
+
+  while (connected_ && !undecryptable_packets_.empty()) {
+    DVLOG(1) << ENDPOINT << "Attempting to process undecryptable packet";
+    QuicEncryptedPacket* packet = undecryptable_packets_.front();
+    if (!framer_.ProcessPacket(*packet) &&
+        framer_.error() == QUIC_DECRYPTION_FAILURE) {
+      DVLOG(1) << ENDPOINT << "Unable to process undecryptable packet...";
+      break;
+    }
+    DVLOG(1) << ENDPOINT << "Processed undecryptable packet!";
+    ++stats_.packets_processed;
+    delete packet;
+    undecryptable_packets_.pop_front();
+  }
+
+  // Once forward secure encryption is in use, there will be no
+  // new keys installed and hence any undecryptable packets will
+  // never be able to be decrypted.
+  if (encryption_level_ == ENCRYPTION_FORWARD_SECURE) {
+    if (debug_visitor_.get() != nullptr) {
+      // TODO(rtenneti): perhaps more efficient to pass the number of
+      // undecryptable packets as the argument to OnUndecryptablePacket so that
+      // we just need to call OnUndecryptablePacket once?
+      for (size_t i = 0; i < undecryptable_packets_.size(); ++i) {
+        debug_visitor_->OnUndecryptablePacket();
+      }
+    }
+    STLDeleteElements(&undecryptable_packets_);
+  }
+}
+
+void QuicConnection::MaybeProcessRevivedPacket() {
+  QuicFecGroup* group = GetFecGroup();
+  if (!connected_ || group == nullptr || !group->CanRevive()) {
+    return;
+  }
+  QuicPacketHeader revived_header;
+  char revived_payload[kMaxPacketSize];
+  size_t len = group->Revive(&revived_header, revived_payload, kMaxPacketSize);
+  revived_header.public_header.connection_id = connection_id_;
+  revived_header.public_header.connection_id_length =
+      last_header_.public_header.connection_id_length;
+  revived_header.public_header.version_flag = false;
+  revived_header.public_header.reset_flag = false;
+  revived_header.public_header.sequence_number_length =
+      last_header_.public_header.sequence_number_length;
+  revived_header.fec_flag = false;
+  revived_header.is_in_fec_group = NOT_IN_FEC_GROUP;
+  revived_header.fec_group = 0;
+  group_map_.erase(last_header_.fec_group);
+  last_decrypted_packet_level_ = group->effective_encryption_level();
+  DCHECK_LT(last_decrypted_packet_level_, NUM_ENCRYPTION_LEVELS);
+  delete group;
+
+  last_packet_revived_ = true;
+  if (debug_visitor_.get() != nullptr) {
+    debug_visitor_->OnRevivedPacket(revived_header,
+                                    StringPiece(revived_payload, len));
+  }
+
+  ++stats_.packets_revived;
+  framer_.ProcessRevivedPacket(&revived_header,
+                               StringPiece(revived_payload, len));
+}
+
+QuicFecGroup* QuicConnection::GetFecGroup() {
+  QuicFecGroupNumber fec_group_num = last_header_.fec_group;
+  if (fec_group_num == 0) {
+    return nullptr;
+  }
+  if (group_map_.count(fec_group_num) == 0) {
+    if (group_map_.size() >= kMaxFecGroups) {  // Too many groups
+      if (fec_group_num < group_map_.begin()->first) {
+        // The group being requested is a group we've seen before and deleted.
+        // Don't recreate it.
+        return nullptr;
+      }
+      // Clear the lowest group number.
+      delete group_map_.begin()->second;
+      group_map_.erase(group_map_.begin());
+    }
+    group_map_[fec_group_num] = new QuicFecGroup();
+  }
+  return group_map_[fec_group_num];
+}
+
+void QuicConnection::SendConnectionClose(QuicErrorCode error) {
+  SendConnectionCloseWithDetails(error, string());
+}
+
+void QuicConnection::SendConnectionCloseWithDetails(QuicErrorCode error,
+                                                    const string& details) {
+  // If we're write blocked, WritePacket() will not send, but will capture the
+  // serialized packet.
+  SendConnectionClosePacket(error, details);
+  if (connected_) {
+    // It's possible that while sending the connection close packet, we get a
+    // socket error and disconnect right then and there.  Avoid a double
+    // disconnect in that case.
+    CloseConnection(error, false);
+  }
+}
+
+void QuicConnection::SendConnectionClosePacket(QuicErrorCode error,
+                                               const string& details) {
+  DVLOG(1) << ENDPOINT << "Force closing " << connection_id()
+           << " with error " << QuicUtils::ErrorToString(error)
+           << " (" << error << ") " << details;
+  ScopedPacketBundler ack_bundler(this, SEND_ACK);
+  QuicConnectionCloseFrame* frame = new QuicConnectionCloseFrame();
+  frame->error_code = error;
+  frame->error_details = details;
+  packet_generator_.AddControlFrame(QuicFrame(frame));
+  packet_generator_.FlushAllQueuedFrames();
+}
+
+void QuicConnection::CloseConnection(QuicErrorCode error, bool from_peer) {
+  if (!connected_) {
+    DLOG(DFATAL) << "Error: attempt to close an already closed connection"
+                 << base::debug::StackTrace().ToString();
+    return;
+  }
+  connected_ = false;
+  if (debug_visitor_.get() != nullptr) {
+    debug_visitor_->OnConnectionClosed(error, from_peer);
+  }
+  visitor_->OnConnectionClosed(error, from_peer);
+  // Cancel the alarms so they don't trigger any action now that the
+  // connection is closed.
+  ack_alarm_->Cancel();
+  ping_alarm_->Cancel();
+  resume_writes_alarm_->Cancel();
+  retransmission_alarm_->Cancel();
+  send_alarm_->Cancel();
+  timeout_alarm_->Cancel();
+}
+
+void QuicConnection::SendGoAway(QuicErrorCode error,
+                                QuicStreamId last_good_stream_id,
+                                const string& reason) {
+  DVLOG(1) << ENDPOINT << "Going away with error "
+           << QuicUtils::ErrorToString(error)
+           << " (" << error << ")";
+
+  // Opportunistically bundle an ack with this outgoing packet.
+  ScopedPacketBundler ack_bundler(this, BUNDLE_PENDING_ACK);
+  packet_generator_.AddControlFrame(
+      QuicFrame(new QuicGoAwayFrame(error, last_good_stream_id, reason)));
+}
+
+void QuicConnection::CloseFecGroupsBefore(
+    QuicPacketSequenceNumber sequence_number) {
+  FecGroupMap::iterator it = group_map_.begin();
+  while (it != group_map_.end()) {
+    // If this is the current group or the group doesn't protect this packet
+    // we can ignore it.
+    if (last_header_.fec_group == it->first ||
+        !it->second->ProtectsPacketsBefore(sequence_number)) {
+      ++it;
+      continue;
+    }
+    QuicFecGroup* fec_group = it->second;
+    DCHECK(!fec_group->CanRevive());
+    FecGroupMap::iterator next = it;
+    ++next;
+    group_map_.erase(it);
+    delete fec_group;
+    it = next;
+  }
+}
+
+size_t QuicConnection::max_packet_length() const {
+  return packet_generator_.max_packet_length();
+}
+
+void QuicConnection::set_max_packet_length(size_t length) {
+  return packet_generator_.set_max_packet_length(length);
+}
+
+bool QuicConnection::HasQueuedData() const {
+  return pending_version_negotiation_packet_ ||
+      !queued_packets_.empty() || packet_generator_.HasQueuedFrames();
+}
+
+bool QuicConnection::CanWriteStreamData() {
+  // Don't write stream data if there are negotiation or queued data packets
+  // to send. Otherwise, continue and bundle as many frames as possible.
+  if (pending_version_negotiation_packet_ || !queued_packets_.empty()) {
+    return false;
+  }
+
+  IsHandshake pending_handshake = visitor_->HasPendingHandshake() ?
+      IS_HANDSHAKE : NOT_HANDSHAKE;
+  // Sending queued packets may have caused the socket to become write blocked,
+  // or the congestion manager to prohibit sending.  If we've sent everything
+  // we had queued and we're still not blocked, let the visitor know it can
+  // write more.
+  return ShouldGeneratePacket(NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA,
+                              pending_handshake);
+}
+
+void QuicConnection::SetIdleNetworkTimeout(QuicTime::Delta timeout) {
+  // Adjust the idle timeout on client and server to prevent clients from
+  // sending requests to servers which have already closed the connection.
+  if (is_server_) {
+    timeout = timeout.Add(QuicTime::Delta::FromSeconds(1));
+  } else if (timeout > QuicTime::Delta::FromSeconds(1)) {
+    timeout = timeout.Subtract(QuicTime::Delta::FromSeconds(1));
+  }
+
+  if (timeout < idle_network_timeout_) {
+    idle_network_timeout_ = timeout;
+    if (FLAGS_quic_timeouts_only_from_alarms) {
+      SetTimeoutAlarm();
+    } else {
+      CheckForTimeout();
+    }
+  } else {
+    idle_network_timeout_ = timeout;
+  }
+}
+
+void QuicConnection::SetOverallConnectionTimeout(QuicTime::Delta timeout) {
+  if (timeout < overall_connection_timeout_) {
+    overall_connection_timeout_ = timeout;
+    if (FLAGS_quic_timeouts_only_from_alarms) {
+      SetTimeoutAlarm();
+    } else {
+      CheckForTimeout();
+    }
+  } else {
+    overall_connection_timeout_ = timeout;
+  }
+}
+
+void QuicConnection::SetNetworkTimeouts(QuicTime::Delta overall_timeout,
+                                        QuicTime::Delta idle_timeout) {
+  LOG_IF(DFATAL, idle_timeout > overall_timeout)
+      << "idle_timeout:" << idle_timeout.ToMilliseconds()
+      << " overall_timeout:" << overall_timeout.ToMilliseconds();
+  // Adjust the idle timeout on client and server to prevent clients from
+  // sending requests to servers which have already closed the connection.
+  if (is_server_) {
+    idle_timeout = idle_timeout.Add(QuicTime::Delta::FromSeconds(1));
+  } else if (idle_timeout > QuicTime::Delta::FromSeconds(1)) {
+    idle_timeout = idle_timeout.Subtract(QuicTime::Delta::FromSeconds(1));
+  }
+  overall_connection_timeout_ = overall_timeout;
+  idle_network_timeout_ = idle_timeout;
+
+  SetTimeoutAlarm();
+}
+
+void QuicConnection::CheckForTimeout() {
+  QuicTime now = clock_->ApproximateNow();
+  QuicTime time_of_last_packet = max(time_of_last_received_packet_,
+                                     time_of_last_sent_new_packet_);
+
+  // |delta| can be < 0 as |now| is approximate time but |time_of_last_packet|
+  // is accurate time. However, this should not change the behavior of
+  // timeout handling.
+  QuicTime::Delta idle_duration = now.Subtract(time_of_last_packet);
+  DVLOG(1) << ENDPOINT << "last packet "
+           << time_of_last_packet.ToDebuggingValue()
+           << " now:" << now.ToDebuggingValue()
+           << " idle_duration:" << idle_duration.ToMicroseconds()
+           << " idle_network_timeout: "
+           << idle_network_timeout_.ToMicroseconds();
+  if (idle_duration >= idle_network_timeout_) {
+    DVLOG(1) << ENDPOINT << "Connection timedout due to no network activity.";
+    SendConnectionClose(QUIC_CONNECTION_TIMED_OUT);
+    return;
+  }
+
+  if (!overall_connection_timeout_.IsInfinite()) {
+    QuicTime::Delta connected_duration =
+        now.Subtract(stats_.connection_creation_time);
+    DVLOG(1) << ENDPOINT << "connection time: "
+             << connected_duration.ToMicroseconds() << " overall timeout: "
+             << overall_connection_timeout_.ToMicroseconds();
+    if (connected_duration >= overall_connection_timeout_) {
+      DVLOG(1) << ENDPOINT <<
+          "Connection timedout due to overall connection timeout.";
+      SendConnectionClose(QUIC_CONNECTION_OVERALL_TIMED_OUT);
+      return;
+    }
+  }
+
+  SetTimeoutAlarm();
+}
+
+void QuicConnection::SetTimeoutAlarm() {
+  QuicTime time_of_last_packet = max(time_of_last_received_packet_,
+                                     time_of_last_sent_new_packet_);
+
+  QuicTime deadline = time_of_last_packet.Add(idle_network_timeout_);
+  if (!overall_connection_timeout_.IsInfinite()) {
+    deadline = min(deadline,
+                   stats_.connection_creation_time.Add(
+                       overall_connection_timeout_));
+  }
+
+  timeout_alarm_->Cancel();
+  timeout_alarm_->Set(deadline);
+}
+
+void QuicConnection::SetPingAlarm() {
+  if (is_server_) {
+    // Only clients send pings.
+    return;
+  }
+  if (!visitor_->HasOpenDataStreams()) {
+    ping_alarm_->Cancel();
+    // Don't send a ping unless there are open streams.
+    return;
+  }
+  QuicTime::Delta ping_timeout = QuicTime::Delta::FromSeconds(kPingTimeoutSecs);
+  ping_alarm_->Update(clock_->ApproximateNow().Add(ping_timeout),
+                      QuicTime::Delta::FromSeconds(1));
+}
+
+QuicConnection::ScopedPacketBundler::ScopedPacketBundler(
+    QuicConnection* connection,
+    AckBundling send_ack)
+    : connection_(connection),
+      already_in_batch_mode_(connection != nullptr &&
+                             connection->packet_generator_.InBatchMode()) {
+  if (connection_ == nullptr) {
+    return;
+  }
+  // Move generator into batch mode. If caller wants us to include an ack,
+  // check the delayed-ack timer to see if there's ack info to be sent.
+  if (!already_in_batch_mode_) {
+    DVLOG(1) << "Entering Batch Mode.";
+    connection_->packet_generator_.StartBatchOperations();
+  }
+  // Bundle an ack if the alarm is set or with every second packet if we need to
+  // raise the peer's least unacked.
+  bool ack_pending =
+      connection_->ack_alarm_->IsSet() || connection_->stop_waiting_count_ > 1;
+  if (send_ack == SEND_ACK || (send_ack == BUNDLE_PENDING_ACK && ack_pending)) {
+    DVLOG(1) << "Bundling ack with outgoing packet.";
+    connection_->SendAck();
+  }
+}
+
+QuicConnection::ScopedPacketBundler::~ScopedPacketBundler() {
+  if (connection_ == nullptr) {
+    return;
+  }
+  // If we changed the generator's batch state, restore original batch state.
+  if (!already_in_batch_mode_) {
+    DVLOG(1) << "Leaving Batch Mode.";
+    connection_->packet_generator_.FinishBatchOperations();
+  }
+  DCHECK_EQ(already_in_batch_mode_,
+            connection_->packet_generator_.InBatchMode());
+}
+
+HasRetransmittableData QuicConnection::IsRetransmittable(
+    const QueuedPacket& packet) {
+  // Retransmitted packets retransmittable frames are owned by the unacked
+  // packet map, but are not present in the serialized packet.
+  if (packet.transmission_type != NOT_RETRANSMISSION ||
+      packet.serialized_packet.retransmittable_frames != nullptr) {
+    return HAS_RETRANSMITTABLE_DATA;
+  } else {
+    return NO_RETRANSMITTABLE_DATA;
+  }
+}
+
+bool QuicConnection::IsConnectionClose(
+    QueuedPacket packet) {
+  RetransmittableFrames* retransmittable_frames =
+      packet.serialized_packet.retransmittable_frames;
+  if (!retransmittable_frames) {
+    return false;
+  }
+  for (size_t i = 0; i < retransmittable_frames->frames().size(); ++i) {
+    if (retransmittable_frames->frames()[i].type == CONNECTION_CLOSE_FRAME) {
+      return true;
+    }
+  }
+  return false;
+}
+
+}  // namespace net