blob: 30f822ca8814cbfe032f8d564832b419fe99f3d4 [file] [log] [blame]
// 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;
}
} // 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),
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);
helper_->SetTimeoutAlarm(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() {
}
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_ = SENT_NEGOTIATION_PACKET;
return false;
}
break;
case SENT_NEGOTIATION_PACKET:
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_ == NEGOTIATED_VERSION) {
// 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_ = NEGOTIATED_VERSION;
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;
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;
}
largest_seen_packet_with_ack_ = last_header_.packet_sequence_number;
if (!ValidateAckFrame(incoming_ack)) {
SendConnectionClose(QUIC_INVALID_ACK_DATA);
return false;
}
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_);
// 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()) {
helper_->UnregisterSendAlarmIfRegistered();
WriteIfNotBlocked();
} else if (!delay.IsInfinite()) {
helper_->SetSendAlarm(time_of_last_received_packet_.Add(delay));
}
return connected_;
}
bool QuicConnection::OnCongestionFeedbackFrame(
const QuicCongestionFeedbackFrame& feedback) {
DCHECK(connected_);
if (debug_visitor_) {
debug_visitor_->OnCongestionFeedbackFrame(feedback);
}
congestion_manager_.OnIncomingQuicCongestionFeedbackFrame(
feedback, time_of_last_received_packet_);
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);
visitor_->OnRstStream(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);
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;
visitor_->OnGoAway(frame);
return connected_;
}
void QuicConnection::OnPacketComplete() {
// Don't do anything if this packet closed the connection.
if (!connected_) {
last_stream_frames_.clear();
return;
}
if (!last_packet_revived_) {
DLOG(INFO) << ENDPOINT << "Got packet "
<< last_header_.packet_sequence_number
<< " with " << last_stream_frames_.size()
<< " stream frames for " << last_header_.public_header.guid;
congestion_manager_.RecordIncomingPacket(
last_size_, last_header_.packet_sequence_number,
time_of_last_received_packet_, last_packet_revived_);
} else {
DLOG(INFO) << ENDPOINT << "Got revived packet with "
<< last_stream_frames_.size() << " frames.";
}
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_);
}
MaybeSendAckInResponseToPacket();
last_stream_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_);
}
void QuicConnection::MaybeSendAckInResponseToPacket() {
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"
helper_->SetAckAlarm(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.
helper_->SetSendAlarm(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));
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_ || helper_->IsSendAlarmSet()) {
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()) {
helper_->SetSendAlarm(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_) {
helper_->SetRetransmissionAlarm(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() {
helper_->ClearAckAlarm();
// 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 (!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 (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) {
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;
}
}
helper_->SetTimeoutAlarm(timeout);
return false;
}
} // namespace net