| Index: net/quic/quic_connection.cc
|
| diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc
|
| index 74bc9e3aaad9c97b7f8ca048a65b9cf814861f29..7dea3eedffa23d28cccf7aa8b1aa223801ab68ff 100644
|
| --- a/net/quic/quic_connection.cc
|
| +++ b/net/quic/quic_connection.cc
|
| @@ -223,7 +223,6 @@ QuicConnection::QuicConnection(QuicConnectionId connection_id,
|
| random_generator_(helper->GetRandomGenerator()),
|
| connection_id_(connection_id),
|
| peer_address_(address),
|
| - migrating_peer_port_(0),
|
| last_packet_decrypted_(false),
|
| last_size_(0),
|
| current_packet_data_(nullptr),
|
| @@ -235,6 +234,7 @@ QuicConnection::QuicConnection(QuicConnectionId connection_id,
|
| pending_version_negotiation_packet_(false),
|
| save_crypto_packets_as_termination_packets_(false),
|
| silent_close_enabled_(false),
|
| + close_connection_after_five_rtos_(false),
|
| received_packet_manager_(&stats_),
|
| ack_queued_(false),
|
| num_retransmittable_packets_received_since_last_ack_sent_(0),
|
| @@ -281,10 +281,6 @@ QuicConnection::QuicConnection(QuicConnectionId connection_id,
|
| version_negotiation_state_(START_NEGOTIATION),
|
| perspective_(perspective),
|
| connected_(true),
|
| - peer_ip_changed_(false),
|
| - peer_port_changed_(false),
|
| - self_ip_changed_(false),
|
| - self_port_changed_(false),
|
| can_truncate_connection_ids_(true),
|
| mtu_discovery_target_(0),
|
| mtu_probe_count_(0),
|
| @@ -370,6 +366,10 @@ void QuicConnection::SetFromConfig(const QuicConfig& config) {
|
| config.HasClientSentConnectionOption(kAKD2, perspective_)) {
|
| ack_mode_ = ACK_DECIMATION_WITH_REORDERING;
|
| }
|
| + if (FLAGS_quic_enable_rto_timeout &&
|
| + config.HasClientSentConnectionOption(k5RTO, perspective_)) {
|
| + close_connection_after_five_rtos_ = true;
|
| + }
|
| }
|
|
|
| void QuicConnection::OnSendConnectionState(
|
| @@ -580,6 +580,13 @@ bool QuicConnection::OnUnauthenticatedHeader(const QuicPacketHeader& header) {
|
| "when multipath is not enabled.");
|
| return false;
|
| }
|
| + if (!packet_generator_.IsPendingPacketEmpty()) {
|
| + QUIC_BUG << "Pending frames must be serialized before incoming packets are "
|
| + << "processed, because that may change a queued ack frame.";
|
| + SendConnectionCloseWithDetails(QUIC_INTERNAL_ERROR,
|
| + "Should not process packets while sending.");
|
| + return false;
|
| + }
|
|
|
| // If this packet has already been seen, or the sender has told us that it
|
| // will not be retransmitted, then stop processing the packet.
|
| @@ -669,7 +676,7 @@ bool QuicConnection::OnAckFrame(const QuicAckFrame& incoming_ack) {
|
| return false;
|
| }
|
|
|
| - if (FLAGS_quic_respect_send_alarm2 && send_alarm_->IsSet()) {
|
| + if (send_alarm_->IsSet()) {
|
| send_alarm_->Cancel();
|
| }
|
| ProcessAckFrame(incoming_ack);
|
| @@ -1024,6 +1031,10 @@ void QuicConnection::PopulateAckFrame(QuicAckFrame* ack) {
|
| clock_->ApproximateNow());
|
| }
|
|
|
| +const QuicFrame QuicConnection::GetUpdatedAckFrame() {
|
| + return received_packet_manager_.GetUpdatedAckFrame(clock_->ApproximateNow());
|
| +}
|
| +
|
| void QuicConnection::PopulateStopWaitingFrame(
|
| QuicStopWaitingFrame* stop_waiting) {
|
| stop_waiting->least_unacked = GetLeastUnacked();
|
| @@ -1105,7 +1116,7 @@ QuicConsumedData QuicConnection::SendStreamData(
|
| // also if there is possibility of revival. Only bundle an ack if there's no
|
| // processing left that may cause received_info_ to change.
|
| ScopedRetransmissionScheduler alarm_delayer(this);
|
| - ScopedPacketBundler ack_bundler(this, BUNDLE_PENDING_ACK);
|
| + ScopedPacketBundler ack_bundler(this, SEND_ACK_IF_PENDING);
|
| return packet_generator_.ConsumeData(id, iov, offset, fin, listener);
|
| }
|
|
|
| @@ -1113,7 +1124,7 @@ void QuicConnection::SendRstStream(QuicStreamId id,
|
| QuicRstStreamErrorCode error,
|
| QuicStreamOffset bytes_written) {
|
| // Opportunistically bundle an ack with this outgoing packet.
|
| - ScopedPacketBundler ack_bundler(this, BUNDLE_PENDING_ACK);
|
| + ScopedPacketBundler ack_bundler(this, SEND_ACK_IF_PENDING);
|
| packet_generator_.AddControlFrame(QuicFrame(new QuicRstStreamFrame(
|
| id, AdjustErrorForVersion(error, version()), bytes_written)));
|
|
|
| @@ -1147,20 +1158,20 @@ void QuicConnection::SendRstStream(QuicStreamId id,
|
| void QuicConnection::SendWindowUpdate(QuicStreamId id,
|
| QuicStreamOffset byte_offset) {
|
| // Opportunistically bundle an ack with this outgoing packet.
|
| - ScopedPacketBundler ack_bundler(this, BUNDLE_PENDING_ACK);
|
| + ScopedPacketBundler ack_bundler(this, SEND_ACK_IF_PENDING);
|
| packet_generator_.AddControlFrame(
|
| QuicFrame(new QuicWindowUpdateFrame(id, byte_offset)));
|
| }
|
|
|
| void QuicConnection::SendBlocked(QuicStreamId id) {
|
| // Opportunistically bundle an ack with this outgoing packet.
|
| - ScopedPacketBundler ack_bundler(this, BUNDLE_PENDING_ACK);
|
| + ScopedPacketBundler ack_bundler(this, SEND_ACK_IF_PENDING);
|
| packet_generator_.AddControlFrame(QuicFrame(new QuicBlockedFrame(id)));
|
| }
|
|
|
| void QuicConnection::SendPathClose(QuicPathId path_id) {
|
| // Opportunistically bundle an ack with this outgoing packet.
|
| - ScopedPacketBundler ack_bundler(this, BUNDLE_PENDING_ACK);
|
| + ScopedPacketBundler ack_bundler(this, SEND_ACK_IF_PENDING);
|
| packet_generator_.AddControlFrame(QuicFrame(new QuicPathCloseFrame(path_id)));
|
| OnPathClosed(path_id);
|
| }
|
| @@ -1201,17 +1212,13 @@ void QuicConnection::ProcessUdpPacket(const IPEndPoint& self_address,
|
| last_size_ = packet.length();
|
| current_packet_data_ = packet.data();
|
|
|
| - if (FLAGS_check_peer_address_change_after_decryption) {
|
| - last_packet_destination_address_ = self_address;
|
| - last_packet_source_address_ = peer_address;
|
| - if (!IsInitializedIPEndPoint(self_address_)) {
|
| - self_address_ = last_packet_destination_address_;
|
| - }
|
| - if (!IsInitializedIPEndPoint(peer_address_)) {
|
| - peer_address_ = last_packet_source_address_;
|
| - }
|
| - } else {
|
| - CheckForAddressMigration(self_address, peer_address);
|
| + last_packet_destination_address_ = self_address;
|
| + last_packet_source_address_ = peer_address;
|
| + if (!IsInitializedIPEndPoint(self_address_)) {
|
| + self_address_ = last_packet_destination_address_;
|
| + }
|
| + if (!IsInitializedIPEndPoint(peer_address_)) {
|
| + peer_address_ = last_packet_source_address_;
|
| }
|
|
|
| stats_.bytes_received += packet.length();
|
| @@ -1242,35 +1249,6 @@ void QuicConnection::ProcessUdpPacket(const IPEndPoint& self_address,
|
| current_packet_data_ = nullptr;
|
| }
|
|
|
| -void QuicConnection::CheckForAddressMigration(const IPEndPoint& self_address,
|
| - const IPEndPoint& peer_address) {
|
| - peer_ip_changed_ = false;
|
| - peer_port_changed_ = false;
|
| - self_ip_changed_ = false;
|
| - self_port_changed_ = false;
|
| -
|
| - if (peer_address_.address().empty()) {
|
| - peer_address_ = peer_address;
|
| - }
|
| - if (self_address_.address().empty()) {
|
| - self_address_ = self_address;
|
| - }
|
| -
|
| - if (!peer_address.address().empty() && !peer_address_.address().empty()) {
|
| - peer_ip_changed_ = (peer_address.address() != peer_address_.address());
|
| - peer_port_changed_ = (peer_address.port() != peer_address_.port());
|
| -
|
| - // Store in case we want to migrate connection in ProcessValidatedPacket.
|
| - migrating_peer_ip_ = peer_address.address();
|
| - migrating_peer_port_ = peer_address.port();
|
| - }
|
| -
|
| - if (!self_address.address().empty() && !self_address_.address().empty()) {
|
| - self_ip_changed_ = (self_address.address() != self_address_.address());
|
| - self_port_changed_ = (self_address.port() != self_address_.port());
|
| - }
|
| -}
|
| -
|
| void QuicConnection::OnCanWrite() {
|
| DCHECK(!writer_->IsWriteBlocked());
|
|
|
| @@ -1285,8 +1263,8 @@ void QuicConnection::OnCanWrite() {
|
| return;
|
| }
|
|
|
| - { // Limit the scope of the bundler. ACK inclusion happens elsewhere.
|
| - ScopedPacketBundler bundler(this, NO_ACK);
|
| + {
|
| + ScopedPacketBundler bundler(this, SEND_ACK_IF_QUEUED);
|
| visitor_->OnCanWrite();
|
| visitor_->PostProcessAfterData();
|
| }
|
| @@ -1310,7 +1288,7 @@ void QuicConnection::WriteIfNotBlocked() {
|
|
|
| void QuicConnection::WriteAndBundleAcksIfNotBlocked() {
|
| if (!writer_->IsWriteBlocked()) {
|
| - ScopedPacketBundler bundler(this, ack_queued_ ? SEND_ACK : NO_ACK);
|
| + ScopedPacketBundler bundler(this, SEND_ACK_IF_QUEUED);
|
| OnCanWrite();
|
| }
|
| }
|
| @@ -1321,24 +1299,14 @@ bool QuicConnection::ProcessValidatedPacket(const QuicPacketHeader& header) {
|
| return false;
|
| }
|
|
|
| - if (FLAGS_check_peer_address_change_after_decryption) {
|
| - if (perspective_ == Perspective::IS_SERVER &&
|
| - IsInitializedIPEndPoint(self_address_) &&
|
| - IsInitializedIPEndPoint(last_packet_destination_address_) &&
|
| - (!(self_address_ == last_packet_destination_address_))) {
|
| - SendConnectionCloseWithDetails(
|
| - QUIC_ERROR_MIGRATING_ADDRESS,
|
| - "Self address migration is not supported at the server.");
|
| - return false;
|
| - }
|
| - } else {
|
| - if (perspective_ == Perspective::IS_SERVER &&
|
| - (self_ip_changed_ || self_port_changed_)) {
|
| - SendConnectionCloseWithDetails(
|
| - QUIC_ERROR_MIGRATING_ADDRESS,
|
| - "Self address migration is not supported at the server.");
|
| - return false;
|
| - }
|
| + if (perspective_ == Perspective::IS_SERVER &&
|
| + IsInitializedIPEndPoint(self_address_) &&
|
| + IsInitializedIPEndPoint(last_packet_destination_address_) &&
|
| + (!(self_address_ == last_packet_destination_address_))) {
|
| + SendConnectionCloseWithDetails(
|
| + QUIC_ERROR_MIGRATING_ADDRESS,
|
| + "Self address migration is not supported at the server.");
|
| + return false;
|
| }
|
|
|
| if (!Near(header.packet_number, last_header_.packet_number)) {
|
| @@ -1474,17 +1442,15 @@ bool QuicConnection::CanWrite(HasRetransmittableData retransmittable) {
|
| return false;
|
| }
|
|
|
| - if (FLAGS_quic_respect_send_alarm2) {
|
| - // Allow acks to be sent immediately.
|
| - // TODO(ianswett): Remove retransmittable from
|
| - // SendAlgorithmInterface::TimeUntilSend.
|
| - if (retransmittable == NO_RETRANSMITTABLE_DATA) {
|
| - return true;
|
| - }
|
| - // If the send alarm is set, wait for it to fire.
|
| - if (send_alarm_->IsSet()) {
|
| - return false;
|
| - }
|
| + // Allow acks to be sent immediately.
|
| + // TODO(ianswett): Remove retransmittable from
|
| + // SendAlgorithmInterface::TimeUntilSend.
|
| + if (retransmittable == NO_RETRANSMITTABLE_DATA) {
|
| + return true;
|
| + }
|
| + // If the send alarm is set, wait for it to fire.
|
| + if (send_alarm_->IsSet()) {
|
| + return false;
|
| }
|
|
|
| QuicTime now = clock_->Now();
|
| @@ -1502,9 +1468,6 @@ bool QuicConnection::CanWrite(HasRetransmittableData retransmittable) {
|
| << "ms";
|
| return false;
|
| }
|
| - if (!FLAGS_quic_respect_send_alarm2) {
|
| - send_alarm_->Cancel();
|
| - }
|
| return true;
|
| }
|
|
|
| @@ -1760,7 +1723,7 @@ void QuicConnection::OnPingTimeout() {
|
| }
|
|
|
| void QuicConnection::SendPing() {
|
| - ScopedPacketBundler bundler(this, ack_queued_ ? SEND_ACK : NO_ACK);
|
| + ScopedPacketBundler bundler(this, SEND_ACK_IF_QUEUED);
|
| packet_generator_.AddControlFrame(QuicFrame(QuicPingFrame()));
|
| // Send PING frame immediately, without checking for congestion window bounds.
|
| packet_generator_.FlushAllQueuedFrames();
|
| @@ -1782,6 +1745,14 @@ void QuicConnection::OnRetransmissionTimeout() {
|
| return;
|
| }
|
|
|
| + if (close_connection_after_five_rtos_ &&
|
| + sent_packet_manager_.consecutive_rto_count() >= 4) {
|
| + // Close on the 5th consecutive RTO, so after 4 previous RTOs have occurred.
|
| + SendConnectionCloseWithDetails(QUIC_TOO_MANY_RTOS,
|
| + "5 consecutive retransmission timeouts");
|
| + return;
|
| + }
|
| +
|
| sent_packet_manager_.OnRetransmissionTimeout();
|
| WriteIfNotBlocked();
|
|
|
| @@ -1956,7 +1927,7 @@ void QuicConnection::SendGoAway(QuicErrorCode error,
|
| << QuicUtils::ErrorToString(error) << " (" << error << ")";
|
|
|
| // Opportunistically bundle an ack with this outgoing packet.
|
| - ScopedPacketBundler ack_bundler(this, BUNDLE_PENDING_ACK);
|
| + ScopedPacketBundler ack_bundler(this, SEND_ACK_IF_PENDING);
|
| packet_generator_.AddControlFrame(
|
| QuicFrame(new QuicGoAwayFrame(error, last_good_stream_id, reason)));
|
| }
|
| @@ -2121,7 +2092,7 @@ void QuicConnection::MaybeSetMtuAlarm() {
|
|
|
| QuicConnection::ScopedPacketBundler::ScopedPacketBundler(
|
| QuicConnection* connection,
|
| - AckBundling send_ack)
|
| + AckBundling ack_mode)
|
| : connection_(connection),
|
| already_in_batch_mode_(connection != nullptr &&
|
| connection->packet_generator_.InBatchMode()) {
|
| @@ -2134,18 +2105,30 @@ QuicConnection::ScopedPacketBundler::ScopedPacketBundler(
|
| DVLOG(1) << "Entering Batch Mode.";
|
| connection_->packet_generator_.StartBatchOperations();
|
| }
|
| - // Bundle an ack if the alarm is set or with every second packet if we need to
|
| - // raise the peer's least unacked.
|
| - bool ack_pending =
|
| - connection_->ack_alarm_->IsSet() || connection_->stop_waiting_count_ > 1;
|
| - if (send_ack == SEND_ACK || (send_ack == BUNDLE_PENDING_ACK && ack_pending)) {
|
| + if (ShouldSendAck(ack_mode)) {
|
| DVLOG(1) << "Bundling ack with outgoing packet.";
|
| - DCHECK(send_ack == SEND_ACK || connection_->ack_frame_updated() ||
|
| + DCHECK(ack_mode == SEND_ACK || connection_->ack_frame_updated() ||
|
| connection_->stop_waiting_count_ > 1);
|
| connection_->SendAck();
|
| }
|
| }
|
|
|
| +bool QuicConnection::ScopedPacketBundler::ShouldSendAck(
|
| + AckBundling ack_mode) const {
|
| + switch (ack_mode) {
|
| + case SEND_ACK:
|
| + return true;
|
| + case SEND_ACK_IF_QUEUED:
|
| + return connection_->ack_queued();
|
| + case SEND_ACK_IF_PENDING:
|
| + return connection_->ack_alarm_->IsSet() ||
|
| + connection_->stop_waiting_count_ > 1;
|
| + default:
|
| + QUIC_BUG << "Unsupported ack_mode.";
|
| + return true;
|
| + }
|
| +}
|
| +
|
| QuicConnection::ScopedPacketBundler::~ScopedPacketBundler() {
|
| if (connection_ == nullptr) {
|
| return;
|
| @@ -2271,50 +2254,25 @@ void QuicConnection::DiscoverMtu() {
|
|
|
| void QuicConnection::MaybeMigrateConnectionToNewPeerAddress() {
|
| IPEndPoint last_peer_address;
|
| - if (FLAGS_check_peer_address_change_after_decryption) {
|
| - last_peer_address = last_packet_source_address_;
|
| - } else {
|
| - last_peer_address = IPEndPoint(
|
| - peer_ip_changed_ ? migrating_peer_ip_ : peer_address_.address(),
|
| - peer_port_changed_ ? migrating_peer_port_ : peer_address_.port());
|
| - }
|
| + last_peer_address = last_packet_source_address_;
|
| PeerAddressChangeType peer_address_change_type =
|
| QuicUtils::DetermineAddressChangeType(peer_address_, last_peer_address);
|
| // TODO(fayang): Currently, all peer address change type are allowed. Need to
|
| // add a method ShouldAllowPeerAddressChange(PeerAddressChangeType type) to
|
| - // determine whehter |type| is allowed.
|
| - if (FLAGS_check_peer_address_change_after_decryption) {
|
| - if (peer_address_change_type == NO_CHANGE) {
|
| - return;
|
| - }
|
| -
|
| - IPEndPoint old_peer_address = peer_address_;
|
| - peer_address_ = last_packet_source_address_;
|
| -
|
| - DVLOG(1) << ENDPOINT << "Peer's ip:port changed from "
|
| - << old_peer_address.ToString() << " to "
|
| - << peer_address_.ToString() << ", migrating connection.";
|
| -
|
| - visitor_->OnConnectionMigration(peer_address_change_type);
|
| - sent_packet_manager_.OnConnectionMigration(peer_address_change_type);
|
| -
|
| + // determine whether |type| is allowed.
|
| + if (peer_address_change_type == NO_CHANGE) {
|
| return;
|
| }
|
|
|
| - if (peer_ip_changed_ || peer_port_changed_) {
|
| - IPEndPoint old_peer_address = peer_address_;
|
| - peer_address_ = IPEndPoint(
|
| - peer_ip_changed_ ? migrating_peer_ip_ : peer_address_.address(),
|
| - peer_port_changed_ ? migrating_peer_port_ : peer_address_.port());
|
| + IPEndPoint old_peer_address = peer_address_;
|
| + peer_address_ = last_packet_source_address_;
|
|
|
| - DVLOG(1) << ENDPOINT << "Peer's ip:port changed from "
|
| - << old_peer_address.ToString() << " to "
|
| - << peer_address_.ToString() << ", migrating connection.";
|
| + DVLOG(1) << ENDPOINT << "Peer's ip:port changed from "
|
| + << old_peer_address.ToString() << " to " << peer_address_.ToString()
|
| + << ", migrating connection.";
|
|
|
| - visitor_->OnConnectionMigration(peer_address_change_type);
|
| - DCHECK_NE(peer_address_change_type, NO_CHANGE);
|
| - sent_packet_manager_.OnConnectionMigration(peer_address_change_type);
|
| - }
|
| + visitor_->OnConnectionMigration(peer_address_change_type);
|
| + sent_packet_manager_.OnConnectionMigration(peer_address_change_type);
|
| }
|
|
|
| void QuicConnection::OnPathClosed(QuicPathId path_id) {
|
|
|