summaryrefslogtreecommitdiff
path: root/chromium/net/quic/quic_connection.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/net/quic/quic_connection.cc')
-rw-r--r--chromium/net/quic/quic_connection.cc1661
1 files changed, 1661 insertions, 0 deletions
diff --git a/chromium/net/quic/quic_connection.cc b/chromium/net/quic/quic_connection.cc
new file mode 100644
index 00000000000..718b78864c9
--- /dev/null
+++ b/chromium/net/quic/quic_connection.cc
@@ -0,0 +1,1661 @@
+// 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 <algorithm>
+
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "net/quic/crypto/quic_decrypter.h"
+#include "net/quic/crypto/quic_encrypter.h"
+#include "net/quic/quic_utils.h"
+
+using base::hash_map;
+using base::hash_set;
+using base::StringPiece;
+using std::list;
+using std::make_pair;
+using std::min;
+using std::max;
+using std::vector;
+using std::set;
+using std::string;
+
+namespace net {
+namespace {
+
+// The largest gap in packets we'll accept without closing the connection.
+// This will likely have to be tuned.
+const QuicPacketSequenceNumber kMaxPacketGap = 5000;
+
+// We want to make sure if we get a large nack packet, we don't queue up too
+// many packets at once. 10 is arbitrary.
+const int kMaxRetransmissionsPerAck = 10;
+
+// TCP retransmits after 2 nacks. We allow for a third in case of out-of-order
+// delivery.
+// TODO(ianswett): Change to match TCP's rule of retransmitting once an ack
+// at least 3 sequence numbers larger arrives.
+const size_t kNumberOfNacksBeforeRetransmission = 3;
+
+// The maxiumum number of packets we'd like to queue. We may end up queueing
+// more in the case of many control frames.
+// 6 is arbitrary.
+const int kMaxPacketsToSerializeAtOnce = 6;
+
+// Limit the number of packets we send per retransmission-alarm so we
+// eventually cede. 10 is arbitrary.
+const size_t kMaxPacketsPerRetransmissionAlarm = 10;
+
+// 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;
+
+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_;
+};
+
+// 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 {
+ return connection_->OnRetransmissionTimeout();
+ }
+
+ private:
+ QuicConnection* connection_;
+};
+
+// 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_->OnCanWrite();
+ // Never reschedule the alarm, since OnCanWrite does that.
+ return QuicTime::Zero();
+ }
+
+ private:
+ QuicConnection* connection_;
+};
+
+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_;
+};
+
+} // namespace
+
+#define ENDPOINT (is_server_ ? "Server: " : " Client: ")
+
+QuicConnection::QuicConnection(QuicGuid guid,
+ IPEndPoint address,
+ QuicConnectionHelperInterface* helper,
+ bool is_server,
+ QuicVersion version)
+ : framer_(version,
+ helper->GetClock()->ApproximateNow(),
+ is_server),
+ helper_(helper),
+ encryption_level_(ENCRYPTION_NONE),
+ clock_(helper->GetClock()),
+ random_generator_(helper->GetRandomGenerator()),
+ guid_(guid),
+ peer_address_(address),
+ largest_seen_packet_with_ack_(0),
+ handling_retransmission_timeout_(false),
+ write_blocked_(false),
+ ack_alarm_(helper->CreateAlarm(new AckAlarm(this))),
+ retransmission_alarm_(helper->CreateAlarm(new RetransmissionAlarm(this))),
+ send_alarm_(helper->CreateAlarm(new SendAlarm(this))),
+ timeout_alarm_(helper->CreateAlarm(new TimeoutAlarm(this))),
+ debug_visitor_(NULL),
+ packet_creator_(guid_, &framer_, random_generator_, is_server),
+ packet_generator_(this, NULL, &packet_creator_),
+ idle_network_timeout_(
+ QuicTime::Delta::FromSeconds(kDefaultInitialTimeoutSecs)),
+ overall_connection_timeout_(QuicTime::Delta::Infinite()),
+ creation_time_(clock_->ApproximateNow()),
+ time_of_last_received_packet_(clock_->ApproximateNow()),
+ time_of_last_sent_packet_(clock_->ApproximateNow()),
+ congestion_manager_(clock_, kTCP),
+ version_negotiation_state_(START_NEGOTIATION),
+ max_packets_per_retransmission_alarm_(kMaxPacketsPerRetransmissionAlarm),
+ is_server_(is_server),
+ connected_(true),
+ received_truncated_ack_(false),
+ send_ack_in_response_to_packet_(false),
+ address_migrating_(false) {
+ helper_->SetConnection(this);
+ timeout_alarm_->Set(clock_->ApproximateNow().Add(idle_network_timeout_));
+ framer_.set_visitor(this);
+ framer_.set_received_entropy_calculator(&received_packet_manager_);
+
+ /*
+ if (FLAGS_fake_packet_loss_percentage > 0) {
+ int32 seed = RandomBase::WeakSeed32();
+ LOG(INFO) << ENDPOINT << "Seeding packet loss with " << seed;
+ random_.reset(new MTRandom(seed));
+ }
+ */
+}
+
+QuicConnection::~QuicConnection() {
+ STLDeleteElements(&undecryptable_packets_);
+ STLDeleteValues(&unacked_packets_);
+ STLDeleteValues(&group_map_);
+ for (QueuedPacketList::iterator it = queued_packets_.begin();
+ it != queued_packets_.end(); ++it) {
+ delete it->packet;
+ }
+}
+
+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.
+ for (size_t i = 0; i < arraysize(kSupportedQuicVersions); ++i) {
+ const QuicVersion& version = kSupportedQuicVersions[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;
+ }
+ SendConnectionClose(framer->error());
+}
+
+void QuicConnection::OnPacket() {
+ DCHECK(last_stream_frames_.empty() &&
+ last_goaway_frames_.empty() &&
+ last_rst_frames_.empty() &&
+ last_ack_frames_.empty() &&
+ last_congestion_frames_.empty());
+}
+
+void QuicConnection::OnPublicResetPacket(
+ const QuicPublicResetPacket& packet) {
+ if (debug_visitor_) {
+ debug_visitor_->OnPublicResetPacket(packet);
+ }
+ CloseConnection(QUIC_PUBLIC_RESET, true);
+}
+
+bool QuicConnection::OnProtocolVersionMismatch(QuicVersion 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_) {
+ 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)) {
+ // Drop packets which can't be parsed due to version mismatch.
+ 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;
+
+ // 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_) {
+ 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;
+ }
+
+ version_negotiation_state_ = NEGOTIATION_IN_PROGRESS;
+ RetransmitUnackedPackets(ALL_PACKETS);
+}
+
+void QuicConnection::OnRevivedPacket() {
+}
+
+bool QuicConnection::OnPacketHeader(const QuicPacketHeader& header) {
+ if (debug_visitor_) {
+ 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.guid != guid_) {
+ DLOG(INFO) << ENDPOINT << "Ignoring packet from unexpected GUID: "
+ << header.public_header.guid << " instead of " << guid_;
+ return false;
+ }
+
+ if (!Near(header.packet_sequence_number,
+ last_header_.packet_sequence_number)) {
+ DLOG(INFO) << 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)) {
+ return false;
+ }
+
+ if (version_negotiation_state_ != NEGOTIATED_VERSION) {
+ if (is_server_) {
+ if (!header.public_header.version_flag) {
+ DLOG(WARNING) << ENDPOINT << "Got packet 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;
+ }
+ } 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_creator_.StopSendingVersion();
+ version_negotiation_state_ = NEGOTIATED_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 != NULL) {
+ group->Update(last_header_, payload);
+ }
+}
+
+bool QuicConnection::OnStreamFrame(const QuicStreamFrame& frame) {
+ DCHECK(connected_);
+ if (debug_visitor_) {
+ debug_visitor_->OnStreamFrame(frame);
+ }
+ last_stream_frames_.push_back(frame);
+ return true;
+}
+
+bool QuicConnection::OnAckFrame(const QuicAckFrame& incoming_ack) {
+ DCHECK(connected_);
+ if (debug_visitor_) {
+ debug_visitor_->OnAckFrame(incoming_ack);
+ }
+ DVLOG(1) << ENDPOINT << "OnAckFrame: " << incoming_ack;
+
+ if (last_header_.packet_sequence_number <= largest_seen_packet_with_ack_) {
+ DLOG(INFO) << 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;
+
+ received_truncated_ack_ =
+ incoming_ack.received_info.missing_packets.size() >=
+ QuicFramer::GetMaxUnackedPackets(last_header_);
+
+ received_packet_manager_.UpdatePacketInformationReceivedByPeer(incoming_ack);
+ received_packet_manager_.UpdatePacketInformationSentByPeer(incoming_ack);
+ // Possibly close any FecGroups which are now irrelevant.
+ CloseFecGroupsBefore(incoming_ack.sent_info.least_unacked + 1);
+
+ sent_entropy_manager_.ClearEntropyBefore(
+ received_packet_manager_.least_packet_awaited_by_peer() - 1);
+
+ SequenceNumberSet acked_packets;
+ HandleAckForSentPackets(incoming_ack, &acked_packets);
+ HandleAckForSentFecPackets(incoming_ack, &acked_packets);
+ if (acked_packets.size() > 0) {
+ visitor_->OnAck(acked_packets);
+ }
+ congestion_manager_.OnIncomingAckFrame(incoming_ack,
+ time_of_last_received_packet_);
+}
+
+bool QuicConnection::OnCongestionFeedbackFrame(
+ const QuicCongestionFeedbackFrame& feedback) {
+ DCHECK(connected_);
+ if (debug_visitor_) {
+ debug_visitor_->OnCongestionFeedbackFrame(feedback);
+ }
+ last_congestion_frames_.push_back(feedback);
+ return connected_;
+}
+
+bool QuicConnection::ValidateAckFrame(const QuicAckFrame& incoming_ack) {
+ if (incoming_ack.received_info.largest_observed >
+ packet_creator_.sequence_number()) {
+ DLOG(ERROR) << ENDPOINT << "Peer's observed unsent packet:"
+ << incoming_ack.received_info.largest_observed << " vs "
+ << packet_creator_.sequence_number();
+ // We got an error for data we have not sent. Error out.
+ return false;
+ }
+
+ if (incoming_ack.received_info.largest_observed <
+ received_packet_manager_.peer_largest_observed_packet()) {
+ DLOG(ERROR) << ENDPOINT << "Peer's largest_observed packet decreased:"
+ << incoming_ack.received_info.largest_observed << " vs "
+ << received_packet_manager_.peer_largest_observed_packet();
+ // 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;
+ }
+
+ // We can't have too many unacked packets, or our ack frames go over
+ // kMaxPacketSize.
+ DCHECK_LE(incoming_ack.received_info.missing_packets.size(),
+ QuicFramer::GetMaxUnackedPackets(last_header_));
+
+ if (incoming_ack.sent_info.least_unacked <
+ received_packet_manager_.peer_least_packet_awaiting_ack()) {
+ DLOG(ERROR) << ENDPOINT << "Peer's sent low least_unacked: "
+ << incoming_ack.sent_info.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 (incoming_ack.sent_info.least_unacked >
+ last_header_.packet_sequence_number) {
+ DLOG(ERROR) << ENDPOINT << "Peer sent least_unacked:"
+ << incoming_ack.sent_info.least_unacked
+ << " greater than the enclosing packet sequence number:"
+ << last_header_.packet_sequence_number;
+ return false;
+ }
+
+ if (!incoming_ack.received_info.missing_packets.empty() &&
+ *incoming_ack.received_info.missing_packets.rbegin() >
+ incoming_ack.received_info.largest_observed) {
+ DLOG(ERROR) << ENDPOINT << "Peer sent missing packet: "
+ << *incoming_ack.received_info.missing_packets.rbegin()
+ << " greater than largest observed: "
+ << incoming_ack.received_info.largest_observed;
+ return false;
+ }
+
+ if (!incoming_ack.received_info.missing_packets.empty() &&
+ *incoming_ack.received_info.missing_packets.begin() <
+ received_packet_manager_.least_packet_awaited_by_peer()) {
+ DLOG(ERROR) << ENDPOINT << "Peer sent missing packet: "
+ << *incoming_ack.received_info.missing_packets.begin()
+ << "smaller than least_packet_awaited_by_peer_: "
+ << received_packet_manager_.least_packet_awaited_by_peer();
+ return false;
+ }
+
+ if (!sent_entropy_manager_.IsValidEntropy(
+ incoming_ack.received_info.largest_observed,
+ incoming_ack.received_info.missing_packets,
+ incoming_ack.received_info.entropy_hash)) {
+ DLOG(ERROR) << ENDPOINT << "Peer sent invalid entropy.";
+ return false;
+ }
+
+ return true;
+}
+
+void QuicConnection::HandleAckForSentPackets(const QuicAckFrame& incoming_ack,
+ SequenceNumberSet* acked_packets) {
+ int retransmitted_packets = 0;
+ // Go through the packets we have not received an ack for and see if this
+ // incoming_ack shows they've been seen by the peer.
+ UnackedPacketMap::iterator it = unacked_packets_.begin();
+ while (it != unacked_packets_.end()) {
+ QuicPacketSequenceNumber sequence_number = it->first;
+ if (sequence_number >
+ received_packet_manager_.peer_largest_observed_packet()) {
+ // These are very new sequence_numbers.
+ break;
+ }
+ RetransmittableFrames* unacked = it->second;
+ if (!IsAwaitingPacket(incoming_ack.received_info, sequence_number)) {
+ // Packet was acked, so remove it from our unacked packet list.
+ DVLOG(1) << ENDPOINT <<"Got an ack for packet " << sequence_number;
+ acked_packets->insert(sequence_number);
+ delete unacked;
+ unacked_packets_.erase(it++);
+ retransmission_map_.erase(sequence_number);
+ } else {
+ // This is a packet which we planned on retransmitting and has not been
+ // seen at the time of this ack being sent out. See if it's our new
+ // lowest unacked packet.
+ DVLOG(1) << ENDPOINT << "still missing packet " << sequence_number;
+ ++it;
+ // The peer got packets after this sequence number. This is an explicit
+ // nack.
+ RetransmissionMap::iterator retransmission_it =
+ retransmission_map_.find(sequence_number);
+ ++(retransmission_it->second.number_nacks);
+ if (retransmission_it->second.number_nacks >=
+ kNumberOfNacksBeforeRetransmission &&
+ retransmitted_packets < kMaxRetransmissionsPerAck) {
+ ++retransmitted_packets;
+ DVLOG(1) << ENDPOINT << "Trying to retransmit packet "
+ << sequence_number
+ << " as it has been nacked 3 or more times.";
+ // RetransmitPacket will retransmit with a new sequence_number.
+ RetransmitPacket(sequence_number);
+ }
+ }
+ }
+}
+
+void QuicConnection::HandleAckForSentFecPackets(
+ const QuicAckFrame& incoming_ack, SequenceNumberSet* acked_packets) {
+ UnackedPacketMap::iterator it = unacked_fec_packets_.begin();
+ while (it != unacked_fec_packets_.end()) {
+ QuicPacketSequenceNumber sequence_number = it->first;
+ if (sequence_number >
+ received_packet_manager_.peer_largest_observed_packet()) {
+ break;
+ }
+ if (!IsAwaitingPacket(incoming_ack.received_info, sequence_number)) {
+ DVLOG(1) << ENDPOINT << "Got an ack for fec packet: " << sequence_number;
+ acked_packets->insert(sequence_number);
+ unacked_fec_packets_.erase(it++);
+ } else {
+ DVLOG(1) << ENDPOINT << "Still missing ack for fec packet: "
+ << sequence_number;
+ ++it;
+ }
+ }
+}
+
+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 != NULL) {
+ group->UpdateFec(last_header_.packet_sequence_number,
+ last_header_.entropy_flag, fec);
+ }
+}
+
+bool QuicConnection::OnRstStreamFrame(const QuicRstStreamFrame& frame) {
+ DCHECK(connected_);
+ if (debug_visitor_) {
+ debug_visitor_->OnRstStreamFrame(frame);
+ }
+ DLOG(INFO) << 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_) {
+ debug_visitor_->OnConnectionCloseFrame(frame);
+ }
+ DLOG(INFO) << ENDPOINT << "Connection closed with error "
+ << QuicUtils::ErrorToString(frame.error_code)
+ << " " << frame.error_details;
+ CloseConnection(frame.error_code, true);
+ DCHECK(!connected_);
+ return false;
+}
+
+bool QuicConnection::OnGoAwayFrame(const QuicGoAwayFrame& frame) {
+ DCHECK(connected_);
+ DLOG(INFO) << ENDPOINT << "Go away received with error "
+ << QuicUtils::ErrorToString(frame.error_code)
+ << " and reason:" << frame.reason_phrase;
+ last_goaway_frames_.push_back(frame);
+ return connected_;
+}
+
+void QuicConnection::OnPacketComplete() {
+ // Don't do anything if this packet closed the connection.
+ if (!connected_) {
+ ClearLastFrames();
+ return;
+ }
+
+ DLOG(INFO) << ENDPOINT << (last_packet_revived_ ? "Revived" : "Got")
+ << " packet " << last_header_.packet_sequence_number
+ << " with " << last_ack_frames_.size() << " acks, "
+ << last_congestion_frames_.size() << " congestions, "
+ << last_goaway_frames_.size() << " goaways, "
+ << last_rst_frames_.size() << " rsts, "
+ << last_stream_frames_.size()
+ << " stream frames for " << last_header_.public_header.guid;
+ if (!last_packet_revived_) {
+ congestion_manager_.RecordIncomingPacket(
+ last_size_, last_header_.packet_sequence_number,
+ time_of_last_received_packet_, last_packet_revived_);
+ }
+
+ // Must called before ack processing, because processing acks removes entries
+ // from unacket_packets_, increasing the least_unacked.
+ const bool last_packet_should_instigate_ack = ShouldLastPacketInstigateAck();
+
+ if ((last_stream_frames_.empty() ||
+ visitor_->OnPacket(self_address_, peer_address_,
+ last_header_, last_stream_frames_))) {
+ received_packet_manager_.RecordPacketReceived(
+ last_header_, time_of_last_received_packet_);
+ }
+
+ // Process stream resets, then acks, then congestion feedback.
+ 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) {
+ congestion_manager_.OnIncomingQuicCongestionFeedbackFrame(
+ last_congestion_frames_[i], time_of_last_received_packet_);
+ }
+
+ MaybeSendInResponseToPacket(last_packet_should_instigate_ack);
+
+ ClearLastFrames();
+}
+
+void QuicConnection::ClearLastFrames() {
+ last_stream_frames_.clear();
+ last_goaway_frames_.clear();
+ last_rst_frames_.clear();
+ last_ack_frames_.clear();
+ last_congestion_frames_.clear();
+}
+
+QuicAckFrame* QuicConnection::CreateAckFrame() {
+ QuicAckFrame* outgoing_ack = new QuicAckFrame();
+ received_packet_manager_.UpdateReceivedPacketInfo(
+ &(outgoing_ack->received_info), clock_->ApproximateNow());
+ UpdateSentPacketInfo(&(outgoing_ack->sent_info));
+ DVLOG(1) << ENDPOINT << "Creating ack frame: " << *outgoing_ack;
+ return outgoing_ack;
+}
+
+QuicCongestionFeedbackFrame* QuicConnection::CreateFeedbackFrame() {
+ return new QuicCongestionFeedbackFrame(outgoing_congestion_feedback_);
+}
+
+bool QuicConnection::ShouldLastPacketInstigateAck() {
+ if (!last_stream_frames_.empty() ||
+ !last_goaway_frames_.empty() ||
+ !last_rst_frames_.empty()) {
+ return true;
+ }
+
+ // If the peer is still waiting for a packet that we are no
+ // longer planning to send, we should send an ack to raise
+ // the high water mark.
+ if (!last_ack_frames_.empty() &&
+ !last_ack_frames_.back().received_info.missing_packets.empty() &&
+ !unacked_packets_.empty()) {
+ if (unacked_packets_.begin()->first >
+ *last_ack_frames_.back().received_info.missing_packets.begin()) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void QuicConnection::MaybeSendInResponseToPacket(
+ bool last_packet_should_instigate_ack) {
+ // TODO(ianswett): Better merge these two blocks to queue up an ack if
+ // necessary, then either only send the ack or bundle it with other data.
+ if (!last_ack_frames_.empty()) {
+ // Now the we have received an ack, we might be able to send packets which
+ // are queued locally, or drain streams which are blocked.
+ QuicTime::Delta delay = congestion_manager_.TimeUntilSend(
+ time_of_last_received_packet_, NOT_RETRANSMISSION,
+ HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE);
+ if (delay.IsZero()) {
+ send_alarm_->Cancel();
+ WriteIfNotBlocked();
+ } else if (!delay.IsInfinite()) {
+ send_alarm_->Cancel();
+ send_alarm_->Set(time_of_last_received_packet_.Add(delay));
+ }
+ }
+
+ if (!last_packet_should_instigate_ack) {
+ return;
+ }
+
+ if (send_ack_in_response_to_packet_) {
+ SendAck();
+ } else if (!last_stream_frames_.empty()) {
+ // TODO(alyssar) this case should really be "if the packet contained any
+ // non-ack frame", rather than "if the packet contained a stream frame"
+ if (!ack_alarm_->IsSet()) {
+ ack_alarm_->Set(clock_->ApproximateNow().Add(
+ congestion_manager_.DefaultRetransmissionTime()));
+ }
+ }
+ send_ack_in_response_to_packet_ = !send_ack_in_response_to_packet_;
+}
+
+void QuicConnection::SendVersionNegotiationPacket() {
+ QuicVersionVector supported_versions;
+ for (size_t i = 0; i < arraysize(kSupportedQuicVersions); ++i) {
+ supported_versions.push_back(kSupportedQuicVersions[i]);
+ }
+ QuicEncryptedPacket* encrypted =
+ packet_creator_.SerializeVersionNegotiationPacket(supported_versions);
+ // TODO(satyamshekhar): implement zero server state negotiation.
+ int error;
+ helper_->WritePacketToWire(*encrypted, &error);
+ delete encrypted;
+}
+
+QuicConsumedData QuicConnection::SendStreamData(QuicStreamId id,
+ StringPiece data,
+ QuicStreamOffset offset,
+ bool fin) {
+ return packet_generator_.ConsumeData(id, data, offset, fin);
+}
+
+void QuicConnection::SendRstStream(QuicStreamId id,
+ QuicRstStreamErrorCode error) {
+ packet_generator_.AddControlFrame(
+ QuicFrame(new QuicRstStreamFrame(id, error)));
+}
+
+const QuicConnectionStats& QuicConnection::GetStats() {
+ // Update rtt and estimated bandwidth.
+ stats_.rtt = congestion_manager_.SmoothedRtt().ToMicroseconds();
+ stats_.estimated_bandwidth =
+ congestion_manager_.BandwidthEstimate().ToBytesPerSecond();
+ return stats_;
+}
+
+void QuicConnection::ProcessUdpPacket(const IPEndPoint& self_address,
+ const IPEndPoint& peer_address,
+ const QuicEncryptedPacket& packet) {
+ if (!connected_) {
+ return;
+ }
+ if (debug_visitor_) {
+ debug_visitor_->OnPacketReceived(self_address, peer_address, packet);
+ }
+ last_packet_revived_ = false;
+ last_size_ = packet.length();
+
+ address_migrating_ = false;
+
+ if (peer_address_.address().empty()) {
+ peer_address_ = peer_address;
+ }
+ if (self_address_.address().empty()) {
+ self_address_ = self_address;
+ }
+
+ if (!(peer_address == peer_address_ && self_address == self_address_)) {
+ address_migrating_ = true;
+ }
+
+ 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 (encryption_level_ != ENCRYPTION_FORWARD_SECURE &&
+ framer_.error() == QUIC_DECRYPTION_FAILURE &&
+ undecryptable_packets_.size() < kMaxUndecryptablePackets) {
+ QueueUndecryptablePacket(packet);
+ }
+ DVLOG(1) << ENDPOINT << "Unable to process packet. Last packet processed: "
+ << last_header_.packet_sequence_number;
+ return;
+ }
+ MaybeProcessUndecryptablePackets();
+ MaybeProcessRevivedPacket();
+}
+
+bool QuicConnection::OnCanWrite() {
+ write_blocked_ = false;
+ return DoWrite();
+}
+
+bool QuicConnection::WriteIfNotBlocked() {
+ if (write_blocked_) {
+ return false;
+ }
+ return DoWrite();
+}
+
+bool QuicConnection::DoWrite() {
+ DCHECK(!write_blocked_);
+ WriteQueuedPackets();
+
+ // 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(NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA,
+ NOT_HANDSHAKE)) {
+ packet_generator_.StartBatchOperations();
+ bool all_bytes_written = visitor_->OnCanWrite();
+ packet_generator_.FinishBatchOperations();
+
+ // 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 (!write_blocked_ && !all_bytes_written &&
+ CanWrite(NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA,
+ NOT_HANDSHAKE)) {
+ // 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 quic connections have had a chance to use the socket.
+ send_alarm_->Cancel();
+ send_alarm_->Set(clock_->ApproximateNow());
+ }
+ }
+
+ return !write_blocked_;
+}
+
+bool QuicConnection::ProcessValidatedPacket() {
+ if (address_migrating_) {
+ SendConnectionCloseWithDetails(
+ QUIC_ERROR_MIGRATING_ADDRESS,
+ "Address migration is not yet a supported feature");
+ return false;
+ }
+ time_of_last_received_packet_ = clock_->Now();
+ DVLOG(1) << ENDPOINT << "time of last received packet: "
+ << time_of_last_received_packet_.ToDebuggingValue();
+ return true;
+}
+
+bool QuicConnection::WriteQueuedPackets() {
+ DCHECK(!write_blocked_);
+
+ size_t num_queued_packets = queued_packets_.size() + 1;
+ QueuedPacketList::iterator packet_iterator = queued_packets_.begin();
+ while (!write_blocked_ && packet_iterator != queued_packets_.end()) {
+ // Ensure that from one iteration of this loop to the next we
+ // succeeded in sending a packet so we don't infinitely loop.
+ // TODO(rch): clean up and close the connection if we really hit this.
+ DCHECK_LT(queued_packets_.size(), num_queued_packets);
+ num_queued_packets = queued_packets_.size();
+ if (WritePacket(packet_iterator->encryption_level,
+ packet_iterator->sequence_number,
+ packet_iterator->packet,
+ packet_iterator->retransmittable,
+ NO_FORCE)) {
+ packet_iterator = queued_packets_.erase(packet_iterator);
+ } else {
+ // Continue, because some queued packets may still be writable.
+ // This can happen if a retransmit send fail.
+ ++packet_iterator;
+ }
+ }
+
+ return !write_blocked_;
+}
+
+bool QuicConnection::MaybeRetransmitPacketForRTO(
+ QuicPacketSequenceNumber sequence_number) {
+ DCHECK_EQ(ContainsKey(unacked_packets_, sequence_number),
+ ContainsKey(retransmission_map_, sequence_number));
+
+ if (!ContainsKey(unacked_packets_, sequence_number)) {
+ DVLOG(2) << ENDPOINT << "alarm fired for " << sequence_number
+ << " but it has been acked or already retransmitted with"
+ << " different sequence number.";
+ // So no extra delay is added for this packet.
+ return true;
+ }
+
+ RetransmissionMap::iterator retransmission_it =
+ retransmission_map_.find(sequence_number);
+ // If the packet hasn't been acked and we're getting truncated acks, ignore
+ // any RTO for packets larger than the peer's largest observed packet; it may
+ // have been received by the peer and just wasn't acked due to the ack frame
+ // running out of space.
+ if (received_truncated_ack_ && sequence_number >
+ received_packet_manager_.peer_largest_observed_packet() &&
+ // We allow retransmission of already retransmitted packets so that we
+ // retransmit packets that were retransmissions of the packet with
+ // sequence number < the largest observed field of the truncated ack.
+ retransmission_it->second.number_retransmissions == 0) {
+ return false;
+ } else {
+ ++stats_.rto_count;
+ RetransmitPacket(sequence_number);
+ return true;
+ }
+}
+
+void QuicConnection::RetransmitUnackedPackets(
+ RetransmissionType retransmission_type) {
+ if (unacked_packets_.empty()) {
+ return;
+ }
+ UnackedPacketMap::iterator next_it = unacked_packets_.begin();
+ QuicPacketSequenceNumber end_sequence_number =
+ unacked_packets_.rbegin()->first;
+ do {
+ UnackedPacketMap::iterator current_it = next_it;
+ ++next_it;
+
+ if (retransmission_type == ALL_PACKETS ||
+ current_it->second->encryption_level() == ENCRYPTION_INITIAL) {
+ // TODO(satyamshekhar): Think about congestion control here.
+ // Specifically, about the retransmission count of packets being sent
+ // proactively to achieve 0 (minimal) RTT.
+ RetransmitPacket(current_it->first);
+ }
+ } while (next_it != unacked_packets_.end() &&
+ next_it->first <= end_sequence_number);
+}
+
+void QuicConnection::RetransmitPacket(
+ QuicPacketSequenceNumber sequence_number) {
+ UnackedPacketMap::iterator unacked_it =
+ unacked_packets_.find(sequence_number);
+ RetransmissionMap::iterator retransmission_it =
+ retransmission_map_.find(sequence_number);
+ // There should always be an entry corresponding to |sequence_number| in
+ // both |retransmission_map_| and |unacked_packets_|. Retransmissions due to
+ // RTO for sequence numbers that are already acked or retransmitted are
+ // ignored by MaybeRetransmitPacketForRTO.
+ DCHECK(unacked_it != unacked_packets_.end());
+ DCHECK(retransmission_it != retransmission_map_.end());
+ RetransmittableFrames* unacked = unacked_it->second;
+ // TODO(pwestin): Need to fix potential issue with FEC and a 1 packet
+ // congestion window see b/8331807 for details.
+ congestion_manager_.AbandoningPacket(sequence_number);
+
+ // Re-packetize the frames with a new sequence number for retransmission.
+ // Retransmitted data packets do not use FEC, even when it's enabled.
+ SerializedPacket serialized_packet =
+ packet_creator_.SerializeAllFrames(unacked->frames());
+ RetransmissionInfo retransmission_info(serialized_packet.sequence_number);
+ retransmission_info.number_retransmissions =
+ retransmission_it->second.number_retransmissions + 1;
+ // Remove info with old sequence number.
+ unacked_packets_.erase(unacked_it);
+ retransmission_map_.erase(retransmission_it);
+ DVLOG(1) << ENDPOINT << "Retransmitting unacked packet " << sequence_number
+ << " as " << serialized_packet.sequence_number;
+ DCHECK(unacked_packets_.empty() ||
+ unacked_packets_.rbegin()->first < serialized_packet.sequence_number);
+ unacked_packets_.insert(make_pair(serialized_packet.sequence_number,
+ unacked));
+ retransmission_map_.insert(make_pair(serialized_packet.sequence_number,
+ retransmission_info));
+ if (debug_visitor_) {
+ debug_visitor_->OnPacketRetransmitted(sequence_number,
+ serialized_packet.sequence_number);
+ }
+ SendOrQueuePacket(unacked->encryption_level(),
+ serialized_packet.sequence_number,
+ serialized_packet.packet,
+ serialized_packet.entropy_hash,
+ HAS_RETRANSMITTABLE_DATA);
+}
+
+bool QuicConnection::CanWrite(Retransmission retransmission,
+ HasRetransmittableData retransmittable,
+ IsHandshake handshake) {
+ // TODO(ianswett): If the packet is a retransmit, the current send alarm may
+ // be too long.
+ if (write_blocked_ || send_alarm_->IsSet()) {
+ return false;
+ }
+
+ QuicTime now = clock_->Now();
+ QuicTime::Delta delay = congestion_manager_.TimeUntilSend(
+ now, retransmission, retransmittable, handshake);
+ if (delay.IsInfinite()) {
+ return false;
+ }
+
+ // If the scheduler requires a delay, then we can not send this packet now.
+ if (!delay.IsZero()) {
+ send_alarm_->Cancel();
+ send_alarm_->Set(now.Add(delay));
+ return false;
+ }
+ return true;
+}
+
+bool QuicConnection::IsRetransmission(
+ QuicPacketSequenceNumber sequence_number) {
+ RetransmissionMap::iterator it = retransmission_map_.find(sequence_number);
+ return it != retransmission_map_.end() &&
+ it->second.number_retransmissions > 0;
+}
+
+void QuicConnection::SetupRetransmission(
+ QuicPacketSequenceNumber sequence_number,
+ EncryptionLevel level) {
+ RetransmissionMap::iterator it = retransmission_map_.find(sequence_number);
+ if (it == retransmission_map_.end()) {
+ DVLOG(1) << ENDPOINT << "Will not retransmit packet " << sequence_number;
+ return;
+ }
+
+ RetransmissionInfo retransmission_info = it->second;
+ // TODO(rch): consider using a much smaller retransmisison_delay
+ // for the ENCRYPTION_NONE packets.
+ size_t effective_retransmission_count =
+ level == ENCRYPTION_NONE ? 0 : retransmission_info.number_retransmissions;
+ QuicTime::Delta retransmission_delay =
+ congestion_manager_.GetRetransmissionDelay(
+ unacked_packets_.size(),
+ effective_retransmission_count);
+
+ retransmission_timeouts_.push(RetransmissionTime(
+ sequence_number,
+ clock_->ApproximateNow().Add(retransmission_delay),
+ false));
+
+ // Do not set the retransmisson alarm if we're already handling the
+ // retransmission alarm because the retransmission alarm will be reset when
+ // OnRetransmissionTimeout completes.
+ if (!handling_retransmission_timeout_ && !retransmission_alarm_->IsSet()) {
+ retransmission_alarm_->Set(
+ clock_->ApproximateNow().Add(retransmission_delay));
+ }
+ // TODO(satyamshekhar): restore packet reordering with Ian's TODO in
+ // SendStreamData().
+}
+
+void QuicConnection::SetupAbandonFecTimer(
+ QuicPacketSequenceNumber sequence_number) {
+ DCHECK(ContainsKey(unacked_fec_packets_, sequence_number));
+ QuicTime::Delta retransmission_delay =
+ QuicTime::Delta::FromMilliseconds(
+ congestion_manager_.DefaultRetransmissionTime().ToMilliseconds() * 3);
+ retransmission_timeouts_.push(RetransmissionTime(
+ sequence_number,
+ clock_->ApproximateNow().Add(retransmission_delay),
+ true));
+}
+
+void QuicConnection::DropPacket(QuicPacketSequenceNumber sequence_number) {
+ UnackedPacketMap::iterator unacked_it =
+ unacked_packets_.find(sequence_number);
+ // Packet was not meant to be retransmitted.
+ if (unacked_it == unacked_packets_.end()) {
+ DCHECK(!ContainsKey(retransmission_map_, sequence_number));
+ return;
+ }
+ // Delete the unacked packet.
+ delete unacked_it->second;
+ unacked_packets_.erase(unacked_it);
+ retransmission_map_.erase(sequence_number);
+ return;
+}
+
+bool QuicConnection::WritePacket(EncryptionLevel level,
+ QuicPacketSequenceNumber sequence_number,
+ QuicPacket* packet,
+ HasRetransmittableData retransmittable,
+ Force forced) {
+ if (!connected_) {
+ DLOG(INFO) << ENDPOINT
+ << "Not sending packet as connection is disconnected.";
+ delete packet;
+ // Returning true because we deleted the packet and the caller shouldn't
+ // delete it again.
+ return true;
+ }
+
+ if (encryption_level_ == ENCRYPTION_FORWARD_SECURE &&
+ level == ENCRYPTION_NONE) {
+ // Drop packets that are NULL encrypted since the peer won't accept them
+ // anymore.
+ DLOG(INFO) << ENDPOINT << "Dropped packet: " << sequence_number
+ << " since the packet is NULL encrypted.";
+ DropPacket(sequence_number);
+ delete packet;
+ return true;
+ }
+
+ Retransmission retransmission = IsRetransmission(sequence_number) ?
+ IS_RETRANSMISSION : NOT_RETRANSMISSION;
+ IsHandshake handshake = level == ENCRYPTION_NONE ? IS_HANDSHAKE
+ : NOT_HANDSHAKE;
+
+ // If we are not forced and we can't write, then simply return false;
+ if (forced == NO_FORCE &&
+ !CanWrite(retransmission, retransmittable, handshake)) {
+ return false;
+ }
+
+ scoped_ptr<QuicEncryptedPacket> encrypted(
+ framer_.EncryptPacket(level, sequence_number, *packet));
+ DLOG(INFO) << ENDPOINT << "Sending packet number " << sequence_number
+ << " : " << (packet->is_fec_packet() ? "FEC " :
+ (retransmittable == HAS_RETRANSMITTABLE_DATA
+ ? "data bearing " : " ack only "))
+ << ", encryption level: "
+ << QuicUtils::EncryptionLevelToString(level)
+ << ", length:" << packet->length();
+ DVLOG(2) << ENDPOINT << "packet(" << sequence_number << "): " << std::endl
+ << QuicUtils::StringToHexASCIIDump(packet->AsStringPiece());
+
+ DCHECK(encrypted->length() <= kMaxPacketSize)
+ << "Packet " << sequence_number << " will not be read; too large: "
+ << packet->length() << " " << encrypted->length() << " "
+ << " forced: " << (forced == FORCE ? "yes" : "no");
+
+ int error;
+ QuicTime now = clock_->Now();
+ if (!retransmission) {
+ time_of_last_sent_packet_ = now;
+ }
+ DVLOG(1) << ENDPOINT << "time of last sent packet: "
+ << now.ToDebuggingValue();
+ if (WritePacketToWire(sequence_number, level, *encrypted, &error) == -1) {
+ if (helper_->IsWriteBlocked(error)) {
+ // TODO(satyashekhar): It might be more efficient (fewer system calls), if
+ // all connections share this variable i.e this becomes a part of
+ // PacketWriterInterface.
+ write_blocked_ = true;
+ // 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.
+ return helper_->IsWriteBlockedDataBuffered();
+ }
+ // We can't send an error as the socket is presumably borked.
+ CloseConnection(QUIC_PACKET_WRITE_ERROR, false);
+ return false;
+ }
+
+ // Set the retransmit alarm only when we have sent the packet to the client
+ // and not when it goes to the pending queue, otherwise we will end up adding
+ // an entry to retransmission_timeout_ every time we attempt a write.
+ if (retransmittable == HAS_RETRANSMITTABLE_DATA) {
+ SetupRetransmission(sequence_number, level);
+ } else if (packet->is_fec_packet()) {
+ SetupAbandonFecTimer(sequence_number);
+ }
+
+ congestion_manager_.SentPacket(sequence_number, now, packet->length(),
+ retransmission);
+
+ stats_.bytes_sent += encrypted->length();
+ ++stats_.packets_sent;
+
+ if (retransmission == IS_RETRANSMISSION) {
+ stats_.bytes_retransmitted += encrypted->length();
+ ++stats_.packets_retransmitted;
+ }
+
+ delete packet;
+ return true;
+}
+
+int QuicConnection::WritePacketToWire(QuicPacketSequenceNumber sequence_number,
+ EncryptionLevel level,
+ const QuicEncryptedPacket& packet,
+ int* error) {
+ int bytes_written = helper_->WritePacketToWire(packet, error);
+ if (debug_visitor_) {
+ // WritePacketToWire returned -1, then |error| will be populated with
+ // an error code, which we want to pass along to the visitor.
+ debug_visitor_->OnPacketSent(sequence_number, level, packet,
+ bytes_written == -1 ? *error : bytes_written);
+ }
+ return bytes_written;
+}
+
+bool QuicConnection::OnSerializedPacket(
+ const SerializedPacket& serialized_packet) {
+ if (serialized_packet.retransmittable_frames != NULL) {
+ DCHECK(unacked_packets_.empty() ||
+ unacked_packets_.rbegin()->first <
+ serialized_packet.sequence_number);
+ // Retransmitted frames will be sent with the same encryption level as the
+ // original.
+ serialized_packet.retransmittable_frames->set_encryption_level(
+ encryption_level_);
+ unacked_packets_.insert(
+ make_pair(serialized_packet.sequence_number,
+ serialized_packet.retransmittable_frames));
+ // All unacked packets might be retransmitted.
+ retransmission_map_.insert(
+ make_pair(serialized_packet.sequence_number,
+ RetransmissionInfo(serialized_packet.sequence_number)));
+ } else if (serialized_packet.packet->is_fec_packet()) {
+ unacked_fec_packets_.insert(make_pair(
+ serialized_packet.sequence_number,
+ serialized_packet.retransmittable_frames));
+ }
+ return SendOrQueuePacket(encryption_level_,
+ serialized_packet.sequence_number,
+ serialized_packet.packet,
+ serialized_packet.entropy_hash,
+ serialized_packet.retransmittable_frames != NULL ?
+ HAS_RETRANSMITTABLE_DATA :
+ NO_RETRANSMITTABLE_DATA);
+}
+
+bool QuicConnection::SendOrQueuePacket(EncryptionLevel level,
+ QuicPacketSequenceNumber sequence_number,
+ QuicPacket* packet,
+ QuicPacketEntropyHash entropy_hash,
+ HasRetransmittableData retransmittable) {
+ sent_entropy_manager_.RecordPacketEntropyHash(sequence_number, entropy_hash);
+ if (!WritePacket(level, sequence_number, packet, retransmittable, NO_FORCE)) {
+ queued_packets_.push_back(QueuedPacket(sequence_number, packet, level,
+ retransmittable));
+ return false;
+ }
+ return true;
+}
+
+bool QuicConnection::ShouldSimulateLostPacket() {
+ // TODO(rch): enable this
+ return false;
+ /*
+ return FLAGS_fake_packet_loss_percentage > 0 &&
+ random_->Rand32() % 100 < FLAGS_fake_packet_loss_percentage;
+ */
+}
+
+void QuicConnection::UpdateSentPacketInfo(SentPacketInfo* sent_info) {
+ if (!unacked_packets_.empty()) {
+ sent_info->least_unacked = unacked_packets_.begin()->first;
+ } else {
+ // If there are no unacked packets, set the least unacked packet to
+ // sequence_number() + 1 since that will be the sequence number of this
+ // ack packet whenever it is sent.
+ sent_info->least_unacked = packet_creator_.sequence_number() + 1;
+ }
+ sent_info->entropy_hash = sent_entropy_manager_.EntropyHash(
+ sent_info->least_unacked - 1);
+}
+
+void QuicConnection::SendAck() {
+ ack_alarm_->Cancel();
+
+ // TODO(rch): delay this until the CreateFeedbackFrame
+ // method is invoked. This requires changes SetShouldSendAck
+ // to be a no-arg method, and re-jiggering its implementation.
+ bool send_feedback = false;
+ if (congestion_manager_.GenerateCongestionFeedback(
+ &outgoing_congestion_feedback_)) {
+ DVLOG(1) << ENDPOINT << "Sending feedback "
+ << outgoing_congestion_feedback_;
+ send_feedback = true;
+ }
+
+ packet_generator_.SetShouldSendAck(send_feedback);
+}
+
+void QuicConnection::MaybeAbandonFecPacket(
+ QuicPacketSequenceNumber sequence_number) {
+ if (!ContainsKey(unacked_fec_packets_, sequence_number)) {
+ DVLOG(2) << ENDPOINT << "no need to abandon fec packet: "
+ << sequence_number << "; it's already acked'";
+ return;
+ }
+ congestion_manager_.AbandoningPacket(sequence_number);
+ // TODO(satyashekhar): Should this decrease the congestion window?
+}
+
+QuicTime QuicConnection::OnRetransmissionTimeout() {
+ // This guards against registering the alarm later than we should.
+ //
+ // If we have packet A and B in the list and we call
+ // MaybeRetransmitPacketForRTO on A, that may trigger a call to
+ // SetRetransmissionAlarm if A is retransmitted as C. In that case we
+ // don't want to register the alarm under SetRetransmissionAlarm; we
+ // want to set it to the RTO of B when we return from this function.
+ handling_retransmission_timeout_ = true;
+
+ for (size_t i = 0; i < max_packets_per_retransmission_alarm_ &&
+ !retransmission_timeouts_.empty(); ++i) {
+ RetransmissionTime retransmission_time = retransmission_timeouts_.top();
+ DCHECK(retransmission_time.scheduled_time.IsInitialized());
+ if (retransmission_time.scheduled_time > clock_->ApproximateNow()) {
+ break;
+ }
+ retransmission_timeouts_.pop();
+
+ if (retransmission_time.for_fec) {
+ MaybeAbandonFecPacket(retransmission_time.sequence_number);
+ continue;
+ } else if (
+ !MaybeRetransmitPacketForRTO(retransmission_time.sequence_number)) {
+ DLOG(INFO) << ENDPOINT << "MaybeRetransmitPacketForRTO failed: "
+ << "adding an extra delay for "
+ << retransmission_time.sequence_number;
+ retransmission_time.scheduled_time = clock_->ApproximateNow().Add(
+ congestion_manager_.DefaultRetransmissionTime());
+ retransmission_timeouts_.push(retransmission_time);
+ }
+ }
+
+ handling_retransmission_timeout_ = false;
+
+ if (retransmission_timeouts_.empty()) {
+ return QuicTime::Zero();
+ }
+
+ // We have packets remaining. Return the absolute RTO of the oldest packet
+ // on the list.
+ return retransmission_timeouts_.top().scheduled_time;
+}
+
+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;
+}
+
+void QuicConnection::SetDecrypter(QuicDecrypter* decrypter) {
+ framer_.SetDecrypter(decrypter);
+}
+
+void QuicConnection::SetAlternativeDecrypter(QuicDecrypter* decrypter,
+ bool latch_once_used) {
+ framer_.SetAlternativeDecrypter(decrypter, 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.";
+ char* data = new char[packet.length()];
+ memcpy(data, packet.data(), packet.length());
+ undecryptable_packets_.push_back(
+ new QuicEncryptedPacket(data, packet.length(), true));
+}
+
+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!";
+ 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) {
+ STLDeleteElements(&undecryptable_packets_);
+ }
+}
+
+void QuicConnection::MaybeProcessRevivedPacket() {
+ QuicFecGroup* group = GetFecGroup();
+ if (!connected_ || group == NULL || !group->CanRevive()) {
+ return;
+ }
+ QuicPacketHeader revived_header;
+ char revived_payload[kMaxPacketSize];
+ size_t len = group->Revive(&revived_header, revived_payload, kMaxPacketSize);
+ revived_header.public_header.guid = guid_;
+ revived_header.public_header.version_flag = false;
+ revived_header.public_header.reset_flag = false;
+ 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);
+ delete group;
+
+ last_packet_revived_ = true;
+ if (debug_visitor_) {
+ 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 NULL;
+ }
+ 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 NULL;
+ }
+ // 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::SendConnectionClosePacket(QuicErrorCode error,
+ const string& details) {
+ DLOG(INFO) << ENDPOINT << "Force closing with error "
+ << QuicUtils::ErrorToString(error) << " (" << error << ") "
+ << details;
+ QuicConnectionCloseFrame frame;
+ frame.error_code = error;
+ frame.error_details = details;
+ UpdateSentPacketInfo(&frame.ack_frame.sent_info);
+ received_packet_manager_.UpdateReceivedPacketInfo(
+ &frame.ack_frame.received_info, clock_->ApproximateNow());
+
+ SerializedPacket serialized_packet =
+ packet_creator_.SerializeConnectionClose(&frame);
+
+ // We need to update the sent entropy hash for all sent packets.
+ sent_entropy_manager_.RecordPacketEntropyHash(
+ serialized_packet.sequence_number,
+ serialized_packet.entropy_hash);
+
+ if (!WritePacket(encryption_level_,
+ serialized_packet.sequence_number,
+ serialized_packet.packet,
+ serialized_packet.retransmittable_frames != NULL ?
+ HAS_RETRANSMITTABLE_DATA : NO_RETRANSMITTABLE_DATA,
+ FORCE)) {
+ delete serialized_packet.packet;
+ }
+}
+
+void QuicConnection::SendConnectionCloseWithDetails(QuicErrorCode error,
+ const string& details) {
+ if (!write_blocked_) {
+ SendConnectionClosePacket(error, details);
+ }
+ CloseConnection(error, false);
+}
+
+void QuicConnection::CloseConnection(QuicErrorCode error, bool from_peer) {
+ DCHECK(connected_);
+ connected_ = false;
+ visitor_->ConnectionClose(error, from_peer);
+}
+
+void QuicConnection::SendGoAway(QuicErrorCode error,
+ QuicStreamId last_good_stream_id,
+ const string& reason) {
+ DLOG(INFO) << ENDPOINT << "Going away with error "
+ << QuicUtils::ErrorToString(error)
+ << " (" << error << ")";
+ 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;
+ }
+}
+
+bool QuicConnection::HasQueuedData() const {
+ return !queued_packets_.empty() || packet_generator_.HasQueuedFrames();
+}
+
+void QuicConnection::SetIdleNetworkTimeout(QuicTime::Delta timeout) {
+ if (timeout < idle_network_timeout_) {
+ idle_network_timeout_ = timeout;
+ CheckForTimeout();
+ } else {
+ idle_network_timeout_ = timeout;
+ }
+}
+
+void QuicConnection::SetOverallConnectionTimeout(QuicTime::Delta timeout) {
+ if (timeout < overall_connection_timeout_) {
+ overall_connection_timeout_ = timeout;
+ CheckForTimeout();
+ } else {
+ overall_connection_timeout_ = timeout;
+ }
+}
+
+bool QuicConnection::CheckForTimeout() {
+ QuicTime now = clock_->ApproximateNow();
+ QuicTime time_of_last_packet = std::max(time_of_last_received_packet_,
+ time_of_last_sent_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 delta = now.Subtract(time_of_last_packet);
+ DVLOG(1) << ENDPOINT << "last packet "
+ << time_of_last_packet.ToDebuggingValue()
+ << " now:" << now.ToDebuggingValue()
+ << " delta:" << delta.ToMicroseconds()
+ << " network_timeout: " << idle_network_timeout_.ToMicroseconds();
+ if (delta >= idle_network_timeout_) {
+ DVLOG(1) << ENDPOINT << "Connection timedout due to no network activity.";
+ SendConnectionClose(QUIC_CONNECTION_TIMED_OUT);
+ return true;
+ }
+
+ // Next timeout delta.
+ QuicTime::Delta timeout = idle_network_timeout_.Subtract(delta);
+
+ if (!overall_connection_timeout_.IsInfinite()) {
+ QuicTime::Delta connected_time = now.Subtract(creation_time_);
+ DVLOG(1) << ENDPOINT << "connection time: "
+ << connected_time.ToMilliseconds() << " overall timeout: "
+ << overall_connection_timeout_.ToMilliseconds();
+ if (connected_time >= overall_connection_timeout_) {
+ DVLOG(1) << ENDPOINT <<
+ "Connection timedout due to overall connection timeout.";
+ SendConnectionClose(QUIC_CONNECTION_TIMED_OUT);
+ return true;
+ }
+
+ // Take the min timeout.
+ QuicTime::Delta connection_timeout =
+ overall_connection_timeout_.Subtract(connected_time);
+ if (connection_timeout < timeout) {
+ timeout = connection_timeout;
+ }
+ }
+
+ timeout_alarm_->Cancel();
+ timeout_alarm_->Set(clock_->ApproximateNow().Add(timeout));
+ return false;
+}
+
+} // namespace net