| Index: net/quic/chromium/quic_stream_factory.cc
|
| diff --git a/net/quic/chromium/quic_stream_factory.cc b/net/quic/chromium/quic_stream_factory.cc
|
| index 8212a9c0366cecc3cf5d4a411710c79a23eee8df..8f8245b5f41ca1a6836481c7aead650ba88327f3 100644
|
| --- a/net/quic/chromium/quic_stream_factory.cc
|
| +++ b/net/quic/chromium/quic_stream_factory.cc
|
| @@ -726,6 +726,11 @@
|
| bool enable_non_blocking_io,
|
| bool disable_disk_cache,
|
| bool prefer_aes,
|
| + int max_number_of_lossy_connections,
|
| + float packet_loss_threshold,
|
| + int max_disabled_reasons,
|
| + int threshold_public_resets_post_handshake,
|
| + int threshold_timeouts_with_open_streams,
|
| int socket_receive_buffer_size,
|
| bool delay_tcp_race,
|
| int max_server_configs_stored_in_properties,
|
| @@ -772,8 +777,17 @@
|
| enable_non_blocking_io_(enable_non_blocking_io),
|
| disable_disk_cache_(disable_disk_cache),
|
| prefer_aes_(prefer_aes),
|
| - disable_quic_on_timeout_with_open_streams_(
|
| - disable_quic_on_timeout_with_open_streams),
|
| + max_number_of_lossy_connections_(max_number_of_lossy_connections),
|
| + packet_loss_threshold_(packet_loss_threshold),
|
| + max_disabled_reasons_(max_disabled_reasons),
|
| + num_public_resets_post_handshake_(0),
|
| + num_timeouts_with_open_streams_(0),
|
| + max_public_resets_post_handshake_(0),
|
| + max_timeouts_with_open_streams_(0),
|
| + threshold_timeouts_with_open_streams_(
|
| + threshold_timeouts_with_open_streams),
|
| + threshold_public_resets_post_handshake_(
|
| + threshold_public_resets_post_handshake),
|
| socket_receive_buffer_size_(socket_receive_buffer_size),
|
| delay_tcp_race_(delay_tcp_race),
|
| ping_timeout_(QuicTime::Delta::FromSeconds(kPingTimeoutSecs)),
|
| @@ -802,6 +816,8 @@
|
| weak_factory_(this) {
|
| if (ssl_config_service_.get())
|
| ssl_config_service_->AddObserver(this);
|
| + if (disable_quic_on_timeout_with_open_streams)
|
| + threshold_timeouts_with_open_streams_ = 1;
|
| DCHECK(transport_security_state_);
|
| DCHECK(http_server_properties_);
|
| crypto_config_.set_user_agent_id(user_agent_id);
|
| @@ -1137,19 +1153,86 @@
|
| new QuicHttpStream(session->GetWeakPtr()));
|
| }
|
|
|
| -bool QuicStreamFactory::IsQuicDisabled() const {
|
| +QuicChromiumClientSession::QuicDisabledReason
|
| +QuicStreamFactory::QuicDisabledReason(uint16_t port) const {
|
| + if (max_number_of_lossy_connections_ > 0 &&
|
| + number_of_lossy_connections_.find(port) !=
|
| + number_of_lossy_connections_.end() &&
|
| + number_of_lossy_connections_.at(port) >=
|
| + max_number_of_lossy_connections_) {
|
| + return QuicChromiumClientSession::QUIC_DISABLED_BAD_PACKET_LOSS_RATE;
|
| + }
|
| + if (threshold_public_resets_post_handshake_ > 0 &&
|
| + num_public_resets_post_handshake_ >=
|
| + threshold_public_resets_post_handshake_) {
|
| + return QuicChromiumClientSession::QUIC_DISABLED_PUBLIC_RESET_POST_HANDSHAKE;
|
| + }
|
| + if (threshold_timeouts_with_open_streams_ > 0 &&
|
| + num_timeouts_with_open_streams_ >=
|
| + threshold_timeouts_with_open_streams_) {
|
| + return QuicChromiumClientSession::QUIC_DISABLED_TIMEOUT_WITH_OPEN_STREAMS;
|
| + }
|
| + return QuicChromiumClientSession::QUIC_DISABLED_NOT;
|
| +}
|
| +
|
| +const char* QuicStreamFactory::QuicDisabledReasonString() const {
|
| + // TODO(ckrasic) - better solution for port/lossy connections?
|
| + const uint16_t port = 443;
|
| + switch (QuicDisabledReason(port)) {
|
| + case QuicChromiumClientSession::QUIC_DISABLED_BAD_PACKET_LOSS_RATE:
|
| + return "Bad packet loss rate.";
|
| + case QuicChromiumClientSession::QUIC_DISABLED_PUBLIC_RESET_POST_HANDSHAKE:
|
| + return "Public resets after successful handshakes.";
|
| + case QuicChromiumClientSession::QUIC_DISABLED_TIMEOUT_WITH_OPEN_STREAMS:
|
| + return "Connection timeouts with streams open.";
|
| + default:
|
| + return "";
|
| + }
|
| +}
|
| +
|
| +bool QuicStreamFactory::IsQuicDisabled(uint16_t port) const {
|
| return status_ != OPEN;
|
| }
|
|
|
| -bool QuicStreamFactory::OnHandshakeConfirmed(
|
| - QuicChromiumClientSession* session) {
|
| - if (!IsQuicDisabled())
|
| +bool QuicStreamFactory::OnHandshakeConfirmed(QuicChromiumClientSession* session,
|
| + float packet_loss_rate) {
|
| + DCHECK(session);
|
| + uint16_t port = session->server_id().port();
|
| + if (packet_loss_rate < packet_loss_threshold_) {
|
| + number_of_lossy_connections_[port] = 0;
|
| return false;
|
| -
|
| - session->CloseSessionOnErrorAndNotifyFactoryLater(
|
| - ERR_ABORTED, QUIC_TIMEOUTS_WITH_OPEN_STREAMS);
|
| -
|
| - return true;
|
| + }
|
| +
|
| + // We mark it as recently broken, which means that 0-RTT will be disabled
|
| + // but we'll still race.
|
| + http_server_properties_->MarkAlternativeServiceRecentlyBroken(
|
| + AlternativeService(QUIC, session->server_id().host(), port));
|
| +
|
| + bool was_quic_disabled = IsQuicDisabled(port);
|
| + ++number_of_lossy_connections_[port];
|
| +
|
| + // Collect data for port 443 for packet loss events.
|
| + if (port == 443 && max_number_of_lossy_connections_ > 0) {
|
| + UMA_HISTOGRAM_SPARSE_SLOWLY(
|
| + base::StringPrintf("Net.QuicStreamFactory.BadPacketLossEvents%d",
|
| + max_number_of_lossy_connections_),
|
| + std::min(number_of_lossy_connections_[port],
|
| + max_number_of_lossy_connections_));
|
| + }
|
| +
|
| + MaybeDisableQuic(port);
|
| +
|
| + bool is_quic_disabled = IsQuicDisabled(port);
|
| + if (is_quic_disabled) {
|
| + // Close QUIC connection if Quic is disabled for this port.
|
| + session->CloseSessionOnErrorAndNotifyFactoryLater(
|
| + ERR_ABORTED, QUIC_BAD_PACKET_LOSS_RATE);
|
| +
|
| + // If this bad packet loss rate disabled the QUIC, then record it.
|
| + if (!was_quic_disabled)
|
| + UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicStreamFactory.QuicIsDisabled", port);
|
| + }
|
| + return is_quic_disabled;
|
| }
|
|
|
| void QuicStreamFactory::OnTcpJobCompleted(bool succeeded) {
|
| @@ -1165,6 +1248,7 @@
|
| }
|
|
|
| status_ = OPEN;
|
| + num_timeouts_with_open_streams_ = 0;
|
| }
|
|
|
| void QuicStreamFactory::OnIdleSession(QuicChromiumClientSession* session) {}
|
| @@ -1196,8 +1280,97 @@
|
| session_aliases_.erase(session);
|
| }
|
|
|
| +void QuicStreamFactory::MaybeDisableQuic(QuicChromiumClientSession* session) {
|
| + DCHECK(session);
|
| + uint16_t port = session->server_id().port();
|
| + if (IsQuicDisabled(port))
|
| + return;
|
| +
|
| + // Expire the oldest disabled_reason if appropriate. This enforces that we
|
| + // only consider the max_disabled_reasons_ most recent sessions.
|
| + QuicChromiumClientSession::QuicDisabledReason disabled_reason;
|
| + if (static_cast<int>(disabled_reasons_.size()) == max_disabled_reasons_) {
|
| + disabled_reason = disabled_reasons_.front();
|
| + disabled_reasons_.pop_front();
|
| + if (disabled_reason ==
|
| + QuicChromiumClientSession::QUIC_DISABLED_PUBLIC_RESET_POST_HANDSHAKE) {
|
| + --num_public_resets_post_handshake_;
|
| + } else if (disabled_reason == QuicChromiumClientSession::
|
| + QUIC_DISABLED_TIMEOUT_WITH_OPEN_STREAMS) {
|
| + --num_timeouts_with_open_streams_;
|
| + }
|
| + }
|
| + disabled_reason = session->disabled_reason();
|
| + disabled_reasons_.push_back(disabled_reason);
|
| + if (disabled_reason ==
|
| + QuicChromiumClientSession::QUIC_DISABLED_PUBLIC_RESET_POST_HANDSHAKE) {
|
| + ++num_public_resets_post_handshake_;
|
| + } else if (disabled_reason == QuicChromiumClientSession::
|
| + QUIC_DISABLED_TIMEOUT_WITH_OPEN_STREAMS) {
|
| + ++num_timeouts_with_open_streams_;
|
| + }
|
| + if (num_timeouts_with_open_streams_ > max_timeouts_with_open_streams_) {
|
| + max_timeouts_with_open_streams_ = num_timeouts_with_open_streams_;
|
| + UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicStreamFactory.TimeoutsWithOpenStreams",
|
| + num_timeouts_with_open_streams_, 1, 20, 10);
|
| + }
|
| +
|
| + if (num_public_resets_post_handshake_ > max_public_resets_post_handshake_) {
|
| + max_public_resets_post_handshake_ = num_public_resets_post_handshake_;
|
| + UMA_HISTOGRAM_CUSTOM_COUNTS(
|
| + "Net.QuicStreamFactory.PublicResetsPostHandshake",
|
| + num_public_resets_post_handshake_, 1, 20, 10);
|
| + }
|
| +
|
| + MaybeDisableQuic(port);
|
| + if (IsQuicDisabled(port)) {
|
| + if (disabled_reason ==
|
| + QuicChromiumClientSession::QUIC_DISABLED_PUBLIC_RESET_POST_HANDSHAKE) {
|
| + session->CloseSessionOnErrorAndNotifyFactoryLater(
|
| + ERR_ABORTED, QUIC_PUBLIC_RESETS_POST_HANDSHAKE);
|
| + } else if (disabled_reason == QuicChromiumClientSession::
|
| + QUIC_DISABLED_TIMEOUT_WITH_OPEN_STREAMS) {
|
| + session->CloseSessionOnErrorAndNotifyFactoryLater(
|
| + ERR_ABORTED, QUIC_TIMEOUTS_WITH_OPEN_STREAMS);
|
| + }
|
| + UMA_HISTOGRAM_ENUMERATION("Net.QuicStreamFactory.DisabledReasons",
|
| + disabled_reason,
|
| + QuicChromiumClientSession::QUIC_DISABLED_MAX);
|
| + }
|
| +}
|
| +
|
| +void QuicStreamFactory::MaybeDisableQuic(uint16_t port) {
|
| + if (status_ == DISABLED)
|
| + return;
|
| +
|
| + QuicChromiumClientSession::QuicDisabledReason disabled_reason =
|
| + QuicDisabledReason(port);
|
| + if (disabled_reason == QuicChromiumClientSession::QUIC_DISABLED_NOT) {
|
| + DCHECK_EQ(OPEN, status_);
|
| + return;
|
| + }
|
| +
|
| + if (disabled_reason ==
|
| + QuicChromiumClientSession::QUIC_DISABLED_TIMEOUT_WITH_OPEN_STREAMS) {
|
| + // When QUIC there are too many timeouts with open stream, the factory
|
| + // should be closed. When TCP jobs complete, they will move the factory
|
| + // to either fully disabled or back to open.
|
| + status_ = CLOSED;
|
| + DCHECK(IsQuicDisabled(port));
|
| + DCHECK_NE(QuicChromiumClientSession::QuicDisabledReason(port),
|
| + QuicChromiumClientSession::QUIC_DISABLED_NOT);
|
| + return;
|
| + }
|
| +
|
| + status_ = DISABLED;
|
| + DCHECK(IsQuicDisabled(port));
|
| + DCHECK_NE(QuicChromiumClientSession::QuicDisabledReason(port),
|
| + QuicChromiumClientSession::QUIC_DISABLED_NOT);
|
| +}
|
| +
|
| void QuicStreamFactory::OnSessionClosed(QuicChromiumClientSession* session) {
|
| DCHECK_EQ(0u, session->GetNumActiveStreams());
|
| + MaybeDisableQuic(session);
|
| OnSessionGoingAway(session);
|
| delete session;
|
| all_sessions_.erase(session);
|
| @@ -1208,8 +1381,6 @@
|
| if (ping_timeout_ > reduced_ping_timeout_) {
|
| ping_timeout_ = reduced_ping_timeout_;
|
| }
|
| - if (disable_quic_on_timeout_with_open_streams_)
|
| - status_ = CLOSED;
|
| }
|
|
|
| void QuicStreamFactory::CancelRequest(QuicStreamRequest* request) {
|
| @@ -1264,12 +1435,14 @@
|
| }
|
|
|
| void QuicStreamFactory::OnIPAddressChanged() {
|
| + num_timeouts_with_open_streams_ = 0;
|
| status_ = OPEN;
|
| CloseAllSessions(ERR_NETWORK_CHANGED, QUIC_IP_ADDRESS_CHANGED);
|
| set_require_confirmation(true);
|
| }
|
|
|
| void QuicStreamFactory::OnNetworkConnected(NetworkHandle network) {
|
| + num_timeouts_with_open_streams_ = 0;
|
| status_ = OPEN;
|
| }
|
|
|
|
|