summaryrefslogtreecommitdiff
path: root/chromium/net/quic/quic_chromium_client_session.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/net/quic/quic_chromium_client_session.cc')
-rw-r--r--chromium/net/quic/quic_chromium_client_session.cc193
1 files changed, 123 insertions, 70 deletions
diff --git a/chromium/net/quic/quic_chromium_client_session.cc b/chromium/net/quic/quic_chromium_client_session.cc
index 1abab6ba7af..c30b69fc6c1 100644
--- a/chromium/net/quic/quic_chromium_client_session.cc
+++ b/chromium/net/quic/quic_chromium_client_session.cc
@@ -4,6 +4,8 @@
#include "net/quic/quic_chromium_client_session.h"
+#include <utility>
+
#include "base/callback_helpers.h"
#include "base/location.h"
#include "base/metrics/histogram_macros.h"
@@ -19,7 +21,7 @@
#include "net/http/transport_security_state.h"
#include "net/quic/crypto/proof_verifier_chromium.h"
#include "net/quic/crypto/quic_server_info.h"
-#include "net/quic/quic_connection_helper.h"
+#include "net/quic/quic_chromium_connection_helper.h"
#include "net/quic/quic_crypto_client_stream_factory.h"
#include "net/quic/quic_server_id.h"
#include "net/quic/quic_stream_factory.h"
@@ -40,6 +42,11 @@ const int k0RttHandshakeTimeoutMs = 300;
// IPv6 packets have an additional 20 bytes of overhead than IPv4 packets.
const size_t kAdditionalOverheadForIPv6 = 20;
+// Maximum number of Readers that are created for any session due to
+// connection migration. A new Reader is created every time this endpoint's
+// IP address changes.
+const size_t kMaxReadersPerQuicSession = 5;
+
// Histograms for tracking down the crashes from http://crbug.com/354669
// Note: these values must be kept in sync with the corresponding values in:
// tools/metrics/histograms/histograms.xml
@@ -106,12 +113,11 @@ scoped_ptr<base::Value> NetLogQuicClientSessionCallback(
scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
dict->SetString("host", server_id->host());
dict->SetInteger("port", server_id->port());
- dict->SetBoolean("is_https", server_id->is_https());
dict->SetBoolean("privacy_mode",
server_id->privacy_mode() == PRIVACY_MODE_ENABLED);
dict->SetBoolean("require_confirmation", require_confirmation);
dict->SetInteger("cert_verify_flags", cert_verify_flags);
- return dict.Pass();
+ return std::move(dict);
}
} // namespace
@@ -124,7 +130,7 @@ QuicChromiumClientSession::StreamRequest::~StreamRequest() {
int QuicChromiumClientSession::StreamRequest::StartRequest(
const base::WeakPtr<QuicChromiumClientSession>& session,
- QuicReliableClientStream** stream,
+ QuicChromiumClientStream** stream,
const CompletionCallback& callback) {
session_ = session;
stream_ = stream;
@@ -144,7 +150,7 @@ void QuicChromiumClientSession::StreamRequest::CancelRequest() {
}
void QuicChromiumClientSession::StreamRequest::OnRequestCompleteSuccess(
- QuicReliableClientStream* stream) {
+ QuicChromiumClientStream* stream) {
session_.reset();
*stream_ = stream;
ResetAndReturn(&callback_).Run(OK);
@@ -179,34 +185,28 @@ QuicChromiumClientSession::QuicChromiumClientSession(
server_id_(server_id),
require_confirmation_(false),
stream_factory_(stream_factory),
- socket_(socket.Pass()),
transport_security_state_(transport_security_state),
- server_info_(server_info.Pass()),
+ server_info_(std::move(server_info)),
num_total_streams_(0),
task_runner_(task_runner),
net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_QUIC_SESSION)),
- packet_reader_(socket_.get(),
- clock,
- this,
- yield_after_packets,
- yield_after_duration,
- net_log_),
dns_resolution_end_time_(dns_resolution_end_time),
logger_(new QuicConnectionLogger(this,
connection_description,
- socket_performance_watcher.Pass(),
+ std::move(socket_performance_watcher),
net_log_)),
going_away_(false),
disabled_reason_(QUIC_DISABLED_NOT),
weak_factory_(this) {
+ sockets_.push_back(std::move(socket));
+ packet_readers_.push_back(make_scoped_ptr(new QuicPacketReader(
+ sockets_.back().get(), clock, this, yield_after_packets,
+ yield_after_duration, net_log_)));
crypto_stream_.reset(
- crypto_client_stream_factory
- ? crypto_client_stream_factory->CreateQuicCryptoClientStream(
- server_id, this, crypto_config)
- : new QuicCryptoClientStream(
- server_id, this,
- new ProofVerifyContextChromium(cert_verify_flags, net_log_),
- crypto_config));
+ crypto_client_stream_factory->CreateQuicCryptoClientStream(
+ server_id, this, make_scoped_ptr(new ProofVerifyContextChromium(
+ cert_verify_flags, net_log_)),
+ crypto_config));
connection->set_debug_visitor(logger_.get());
net_log_.BeginEvent(NetLog::TYPE_QUIC_SESSION,
base::Bind(NetLogQuicClientSessionCallback, &server_id,
@@ -274,20 +274,8 @@ QuicChromiumClientSession::~QuicChromiumClientSession() {
bool port_selected = stream_factory_->enable_port_selection();
SSLInfo ssl_info;
- if (!GetSSLInfo(&ssl_info) || !ssl_info.cert.get()) {
- if (port_selected) {
- UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectSelectPortForHTTP",
- round_trip_handshakes, 0, 3, 4);
- } else {
- UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectRandomPortForHTTP",
- round_trip_handshakes, 0, 3, 4);
- if (require_confirmation_) {
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "Net.QuicSession.ConnectRandomPortRequiringConfirmationForHTTP",
- round_trip_handshakes, 0, 3, 4);
- }
- }
- } else {
+ // QUIC supports only secure urls.
+ if (GetSSLInfo(&ssl_info) && ssl_info.cert.get()) {
if (port_selected) {
UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectSelectPortForHTTPS",
round_trip_handshakes, 0, 3, 4);
@@ -350,6 +338,13 @@ QuicChromiumClientSession::~QuicChromiumClientSession() {
static_cast<base::HistogramBase::Sample>(stats.max_sequence_reordering));
}
+void QuicChromiumClientSession::OnHeadersHeadOfLineBlocking(
+ QuicTime::Delta delta) {
+ UMA_HISTOGRAM_TIMES(
+ "Net.QuicSession.HeadersHOLBlockedTime",
+ base::TimeDelta::FromMicroseconds(delta.ToMicroseconds()));
+}
+
void QuicChromiumClientSession::OnStreamFrame(const QuicStreamFrame& frame) {
// Record total number of stream frames.
UMA_HISTOGRAM_COUNTS("Net.QuicNumStreamFramesInPacket", 1);
@@ -378,7 +373,7 @@ void QuicChromiumClientSession::RemoveObserver(Observer* observer) {
int QuicChromiumClientSession::TryCreateStream(
StreamRequest* request,
- QuicReliableClientStream** stream) {
+ QuicChromiumClientStream** stream) {
if (!crypto_stream_->encryption_established()) {
DLOG(DFATAL) << "Encryption not established.";
return ERR_CONNECTION_CLOSED;
@@ -399,7 +394,7 @@ int QuicChromiumClientSession::TryCreateStream(
return ERR_CONNECTION_CLOSED;
}
- if (GetNumOpenStreams() < get_max_open_streams()) {
+ if (GetNumOpenOutgoingStreams() < get_max_open_streams()) {
*stream = CreateOutgoingReliableStreamImpl();
return OK;
}
@@ -418,15 +413,15 @@ void QuicChromiumClientSession::CancelRequest(StreamRequest* request) {
}
}
-QuicReliableClientStream*
-QuicChromiumClientSession::CreateOutgoingDynamicStream() {
+QuicChromiumClientStream*
+QuicChromiumClientSession::CreateOutgoingDynamicStream(SpdyPriority priority) {
if (!crypto_stream_->encryption_established()) {
DVLOG(1) << "Encryption not active so no outgoing stream created.";
return nullptr;
}
- if (GetNumOpenStreams() >= get_max_open_streams()) {
+ if (GetNumOpenOutgoingStreams() >= get_max_open_streams()) {
DVLOG(1) << "Failed to create a new outgoing stream. "
- << "Already " << GetNumOpenStreams() << " open.";
+ << "Already " << GetNumOpenOutgoingStreams() << " open.";
return nullptr;
}
if (goaway_received()) {
@@ -441,18 +436,19 @@ QuicChromiumClientSession::CreateOutgoingDynamicStream() {
return CreateOutgoingReliableStreamImpl();
}
-QuicReliableClientStream*
+QuicChromiumClientStream*
QuicChromiumClientSession::CreateOutgoingReliableStreamImpl() {
DCHECK(connection()->connected());
- QuicReliableClientStream* stream =
- new QuicReliableClientStream(GetNextStreamId(), this, net_log_);
+ QuicChromiumClientStream* stream =
+ new QuicChromiumClientStream(GetNextOutgoingStreamId(), this, net_log_);
ActivateStream(stream);
++num_total_streams_;
- UMA_HISTOGRAM_COUNTS("Net.QuicSession.NumOpenStreams", GetNumOpenStreams());
+ UMA_HISTOGRAM_COUNTS("Net.QuicSession.NumOpenStreams",
+ GetNumOpenOutgoingStreams());
// The previous histogram puts 100 in a bucket betweeen 86-113 which does
// not shed light on if chrome ever things it has more than 100 streams open.
UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.TooManyOpenStreams",
- GetNumOpenStreams() > 100);
+ GetNumOpenOutgoingStreams() > 100);
return stream;
}
@@ -475,7 +471,7 @@ bool QuicChromiumClientSession::GetSSLInfo(SSLInfo* ssl_info) const {
// Report the TLS cipher suite that most closely resembles the crypto
// parameters of the QUIC connection.
QuicTag aead = crypto_stream_->crypto_negotiated_params().aead;
- uint16 cipher_suite;
+ uint16_t cipher_suite;
int security_bits;
switch (aead) {
case kAESG:
@@ -486,6 +482,10 @@ bool QuicChromiumClientSession::GetSSLInfo(SSLInfo* ssl_info) const {
cipher_suite = 0xcc13; // TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
security_bits = 256;
break;
+ case kCC20:
+ cipher_suite = 0xcc13; // TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
+ security_bits = 256;
+ break;
default:
NOTREACHED();
return false;
@@ -506,6 +506,9 @@ bool QuicChromiumClientSession::GetSSLInfo(SSLInfo* ssl_info) const {
ssl_info->security_bits = security_bits;
ssl_info->handshake_type = SSLInfo::HANDSHAKE_FULL;
ssl_info->pinning_failure_log = pinning_failure_log_;
+
+ ssl_info->UpdateSignedCertificateTimestamps(*ct_verify_result_);
+
return true;
}
@@ -562,15 +565,15 @@ bool QuicChromiumClientSession::CanPool(const std::string& hostname,
}
SSLInfo ssl_info;
if (!GetSSLInfo(&ssl_info) || !ssl_info.cert.get()) {
- // We can always pool with insecure QUIC sessions.
- return true;
+ NOTREACHED() << "QUIC should always have certificates.";
+ return false;
}
return SpdySession::CanPool(transport_security_state_, ssl_info,
server_id_.host(), hostname);
}
-QuicDataStream* QuicChromiumClientSession::CreateIncomingDynamicStream(
+QuicSpdyStream* QuicChromiumClientSession::CreateIncomingDynamicStream(
QuicStreamId id) {
DLOG(ERROR) << "Server push not supported";
return nullptr;
@@ -594,7 +597,7 @@ void QuicChromiumClientSession::SendRstStream(QuicStreamId id,
}
void QuicChromiumClientSession::OnClosedStream() {
- if (GetNumOpenStreams() < get_max_open_streams() &&
+ if (GetNumOpenOutgoingStreams() < get_max_open_streams() &&
!stream_requests_.empty() && crypto_stream_->encryption_established() &&
!goaway_received() && !going_away_ && connection()->connected()) {
StreamRequest* request = stream_requests_.front();
@@ -602,7 +605,7 @@ void QuicChromiumClientSession::OnClosedStream() {
request->OnRequestCompleteSuccess(CreateOutgoingReliableStreamImpl());
}
- if (GetNumOpenStreams() == 0) {
+ if (GetNumOpenOutgoingStreams() == 0) {
stream_factory_->OnIdleSession(this);
}
}
@@ -664,6 +667,12 @@ void QuicChromiumClientSession::OnCryptoHandshakeEvent(
void QuicChromiumClientSession::OnCryptoHandshakeMessageSent(
const CryptoHandshakeMessage& message) {
logger_->OnCryptoHandshakeMessageSent(message);
+
+ if (message.tag() == kREJ || message.tag() == kSREJ) {
+ UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.RejectLength",
+ message.GetSerialized().length(), 1000, 10000,
+ 50);
+ }
}
void QuicChromiumClientSession::OnCryptoHandshakeMessageReceived(
@@ -676,6 +685,11 @@ void QuicChromiumClientSession::OnGoAway(const QuicGoAwayFrame& frame) {
NotifyFactoryOfSessionGoingAway();
}
+void QuicChromiumClientSession::OnRstStream(const QuicRstStreamFrame& frame) {
+ QuicSession::OnRstStream(frame);
+ OnClosedStream();
+}
+
void QuicChromiumClientSession::OnConnectionClosed(QuicErrorCode error,
bool from_peer) {
DCHECK(!connection()->connected());
@@ -701,9 +715,9 @@ void QuicChromiumClientSession::OnConnectionClosed(QuicErrorCode error,
if (error == QUIC_CONNECTION_TIMED_OUT) {
UMA_HISTOGRAM_COUNTS(
"Net.QuicSession.ConnectionClose.NumOpenStreams.TimedOut",
- GetNumOpenStreams());
+ GetNumOpenOutgoingStreams());
if (IsCryptoHandshakeConfirmed()) {
- if (GetNumOpenStreams() > 0) {
+ if (GetNumOpenOutgoingStreams() > 0) {
disabled_reason_ = QUIC_DISABLED_TIMEOUT_WITH_OPEN_STREAMS;
UMA_HISTOGRAM_BOOLEAN(
"Net.QuicSession.TimedOutWithOpenStreams.HasUnackedPackets",
@@ -730,7 +744,7 @@ void QuicChromiumClientSession::OnConnectionClosed(QuicErrorCode error,
} else {
UMA_HISTOGRAM_COUNTS(
"Net.QuicSession.ConnectionClose.NumOpenStreams.HandshakeTimedOut",
- GetNumOpenStreams());
+ GetNumOpenOutgoingStreams());
UMA_HISTOGRAM_COUNTS(
"Net.QuicSession.ConnectionClose.NumTotalStreams.HandshakeTimedOut",
num_total_streams_);
@@ -761,7 +775,10 @@ void QuicChromiumClientSession::OnConnectionClosed(QuicErrorCode error,
if (!callback_.is_null()) {
base::ResetAndReturn(&callback_).Run(ERR_QUIC_PROTOCOL_ERROR);
}
- socket_->Close();
+
+ for (auto& socket : sockets_) {
+ socket->Close();
+ }
QuicSession::OnConnectionClosed(error, from_peer);
DCHECK(dynamic_streams().empty());
CloseAllStreams(ERR_UNEXPECTED);
@@ -797,15 +814,19 @@ void QuicChromiumClientSession::OnProofVerifyDetailsAvailable(
const ProofVerifyDetails& verify_details) {
const ProofVerifyDetailsChromium* verify_details_chromium =
reinterpret_cast<const ProofVerifyDetailsChromium*>(&verify_details);
- CertVerifyResult* result_copy = new CertVerifyResult;
- result_copy->CopyFrom(verify_details_chromium->cert_verify_result);
- cert_verify_result_.reset(result_copy);
+ cert_verify_result_.reset(new CertVerifyResult);
+ cert_verify_result_->CopyFrom(verify_details_chromium->cert_verify_result);
pinning_failure_log_ = verify_details_chromium->pinning_failure_log;
+ scoped_ptr<ct::CTVerifyResult> ct_verify_result_copy(
+ new ct::CTVerifyResult(verify_details_chromium->ct_verify_result));
+ ct_verify_result_ = std::move(ct_verify_result_copy);
logger_->OnCertificateVerified(*cert_verify_result_);
}
void QuicChromiumClientSession::StartReading() {
- packet_reader_.StartReading();
+ for (auto& packet_reader : packet_readers_) {
+ packet_reader->StartReading();
+ }
}
void QuicChromiumClientSession::CloseSessionOnError(int error,
@@ -837,7 +858,7 @@ void QuicChromiumClientSession::CloseSessionOnErrorInner(
CloseAllStreams(net_error);
CloseAllObservers(net_error);
net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_CLOSE_ON_ERROR,
- NetLog::IntegerCallback("net_error", net_error));
+ NetLog::IntCallback("net_error", net_error));
if (connection()->connected())
connection()->CloseConnection(quic_error, false);
@@ -848,7 +869,7 @@ void QuicChromiumClientSession::CloseAllStreams(int net_error) {
while (!dynamic_streams().empty()) {
ReliableQuicStream* stream = dynamic_streams().begin()->second;
QuicStreamId id = stream->id();
- static_cast<QuicReliableClientStream*>(stream)->OnError(net_error);
+ static_cast<QuicChromiumClientStream*>(stream)->OnError(net_error);
CloseStream(id);
}
}
@@ -865,7 +886,7 @@ scoped_ptr<base::Value> QuicChromiumClientSession::GetInfoAsValue(
const std::set<HostPortPair>& aliases) {
scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
dict->SetString("version", QuicVersionToString(connection()->version()));
- dict->SetInteger("open_streams", GetNumOpenStreams());
+ dict->SetInteger("open_streams", GetNumOpenOutgoingStreams());
scoped_ptr<base::ListValue> stream_list(new base::ListValue());
for (base::hash_map<QuicStreamId, ReliableQuicStream*>::const_iterator it =
dynamic_streams().begin();
@@ -873,7 +894,7 @@ scoped_ptr<base::Value> QuicChromiumClientSession::GetInfoAsValue(
stream_list->Append(
new base::StringValue(base::UintToString(it->second->id())));
}
- dict->Set("active_streams", stream_list.Pass());
+ dict->Set("active_streams", std::move(stream_list));
dict->SetInteger("total_streams", num_total_streams_);
dict->SetString("peer_address", peer_address().ToString());
@@ -891,9 +912,9 @@ scoped_ptr<base::Value> QuicChromiumClientSession::GetInfoAsValue(
it != aliases.end(); it++) {
alias_list->Append(new base::StringValue(it->ToString()));
}
- dict->Set("aliases", alias_list.Pass());
+ dict->Set("aliases", std::move(alias_list));
- return dict.Pass();
+ return std::move(dict);
}
base::WeakPtr<QuicChromiumClientSession>
@@ -901,7 +922,15 @@ QuicChromiumClientSession::GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
-void QuicChromiumClientSession::OnReadError(int result) {
+void QuicChromiumClientSession::OnReadError(
+ int result,
+ const DatagramClientSocket* socket) {
+ DCHECK(socket != nullptr);
+ if (socket != GetDefaultSocket()) {
+ // Ignore read errors from old sockets that are no longer active.
+ // TODO(jri): Maybe clean up old sockets on error.
+ return;
+ }
DVLOG(1) << "Closing session on read error: " << result;
UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.ReadError", -result);
NotifyFactoryOfSessionGoingAway();
@@ -934,7 +963,7 @@ void QuicChromiumClientSession::NotifyFactoryOfSessionClosedLater() {
RecordUnexpectedNotGoingAway(NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER);
going_away_ = true;
- DCHECK_EQ(0u, GetNumOpenStreams());
+ DCHECK_EQ(0u, GetNumActiveStreams());
DCHECK(!connection()->connected());
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
@@ -950,7 +979,7 @@ void QuicChromiumClientSession::NotifyFactoryOfSessionClosed() {
RecordUnexpectedNotGoingAway(NOTIFY_FACTORY_OF_SESSION_CLOSED);
going_away_ = true;
- DCHECK_EQ(0u, GetNumOpenStreams());
+ DCHECK_EQ(0u, GetNumActiveStreams());
// Will delete |this|.
if (stream_factory_)
stream_factory_->OnSessionClosed(this);
@@ -967,7 +996,31 @@ void QuicChromiumClientSession::OnConnectTimeout() {
// if (stream_factory_)
// stream_factory_->OnSessionConnectTimeout(this);
// CloseAllStreams(ERR_QUIC_HANDSHAKE_FAILED);
- // DCHECK_EQ(0u, GetNumOpenStreams());
+ // DCHECK_EQ(0u, GetNumOpenOutgoingStreams());
+}
+
+bool QuicChromiumClientSession::MigrateToSocket(
+ scoped_ptr<DatagramClientSocket> socket,
+ scoped_ptr<QuicPacketReader> reader,
+ scoped_ptr<QuicPacketWriter> writer) {
+ DCHECK_EQ(sockets_.size(), packet_readers_.size());
+ if (sockets_.size() >= kMaxReadersPerQuicSession) {
+ return false;
+ }
+ // TODO(jri): Make SetQuicPacketWriter take a scoped_ptr.
+ connection()->SetQuicPacketWriter(writer.release(), /*owns_writer=*/true);
+ packet_readers_.push_back(std::move(reader));
+ sockets_.push_back(std::move(socket));
+ StartReading();
+ connection()->SendPing();
+ return true;
+}
+
+const DatagramClientSocket* QuicChromiumClientSession::GetDefaultSocket()
+ const {
+ DCHECK(sockets_.back().get() != nullptr);
+ // The most recently added socket is the currently active one.
+ return sockets_.back().get();
}
} // namespace net