Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(179)

Side by Side Diff: net/quic/quic_client_session.cc

Issue 992733002: Remove //net (except for Android test stuff) and sdch (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/quic/quic_client_session.h ('k') | net/quic/quic_client_session_base.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/quic/quic_client_session.h"
6
7 #include "base/callback_helpers.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/metrics/histogram.h"
10 #include "base/metrics/sparse_histogram.h"
11 #include "base/profiler/scoped_tracker.h"
12 #include "base/stl_util.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/values.h"
15 #include "net/base/io_buffer.h"
16 #include "net/base/net_errors.h"
17 #include "net/base/network_activity_monitor.h"
18 #include "net/http/transport_security_state.h"
19 #include "net/quic/crypto/proof_verifier_chromium.h"
20 #include "net/quic/crypto/quic_server_info.h"
21 #include "net/quic/quic_connection_helper.h"
22 #include "net/quic/quic_crypto_client_stream_factory.h"
23 #include "net/quic/quic_server_id.h"
24 #include "net/quic/quic_stream_factory.h"
25 #include "net/spdy/spdy_session.h"
26 #include "net/ssl/channel_id_service.h"
27 #include "net/ssl/ssl_connection_status_flags.h"
28 #include "net/ssl/ssl_info.h"
29 #include "net/udp/datagram_client_socket.h"
30
31 namespace net {
32
33 namespace {
34
35 // The length of time to wait for a 0-RTT handshake to complete
36 // before allowing the requests to possibly proceed over TCP.
37 const int k0RttHandshakeTimeoutMs = 300;
38
39 // IPv6 packets have an additional 20 bytes of overhead than IPv4 packets.
40 const size_t kAdditionalOverheadForIPv6 = 20;
41
42 // Histograms for tracking down the crashes from http://crbug.com/354669
43 // Note: these values must be kept in sync with the corresponding values in:
44 // tools/metrics/histograms/histograms.xml
45 enum Location {
46 DESTRUCTOR = 0,
47 ADD_OBSERVER = 1,
48 TRY_CREATE_STREAM = 2,
49 CREATE_OUTGOING_RELIABLE_STREAM = 3,
50 NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER = 4,
51 NOTIFY_FACTORY_OF_SESSION_CLOSED = 5,
52 NUM_LOCATIONS = 6,
53 };
54
55 void RecordUnexpectedOpenStreams(Location location) {
56 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedOpenStreams", location,
57 NUM_LOCATIONS);
58 }
59
60 void RecordUnexpectedObservers(Location location) {
61 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedObservers", location,
62 NUM_LOCATIONS);
63 }
64
65 void RecordUnexpectedNotGoingAway(Location location) {
66 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedNotGoingAway", location,
67 NUM_LOCATIONS);
68 }
69
70 // Histogram for recording the different reasons that a QUIC session is unable
71 // to complete the handshake.
72 enum HandshakeFailureReason {
73 HANDSHAKE_FAILURE_UNKNOWN = 0,
74 HANDSHAKE_FAILURE_BLACK_HOLE = 1,
75 HANDSHAKE_FAILURE_PUBLIC_RESET = 2,
76 NUM_HANDSHAKE_FAILURE_REASONS = 3,
77 };
78
79 void RecordHandshakeFailureReason(HandshakeFailureReason reason) {
80 UMA_HISTOGRAM_ENUMERATION(
81 "Net.QuicSession.ConnectionClose.HandshakeNotConfirmed.Reason",
82 reason, NUM_HANDSHAKE_FAILURE_REASONS);
83 }
84
85 // Note: these values must be kept in sync with the corresponding values in:
86 // tools/metrics/histograms/histograms.xml
87 enum HandshakeState {
88 STATE_STARTED = 0,
89 STATE_ENCRYPTION_ESTABLISHED = 1,
90 STATE_HANDSHAKE_CONFIRMED = 2,
91 STATE_FAILED = 3,
92 NUM_HANDSHAKE_STATES = 4
93 };
94
95 void RecordHandshakeState(HandshakeState state) {
96 UMA_HISTOGRAM_ENUMERATION("Net.QuicHandshakeState", state,
97 NUM_HANDSHAKE_STATES);
98 }
99
100 base::Value* NetLogQuicClientSessionCallback(
101 const QuicServerId* server_id,
102 bool require_confirmation,
103 NetLog::LogLevel /* log_level */) {
104 base::DictionaryValue* dict = new base::DictionaryValue();
105 dict->SetString("host", server_id->host());
106 dict->SetInteger("port", server_id->port());
107 dict->SetBoolean("is_https", server_id->is_https());
108 dict->SetBoolean("privacy_mode",
109 server_id->privacy_mode() == PRIVACY_MODE_ENABLED);
110 dict->SetBoolean("require_confirmation", require_confirmation);
111 return dict;
112 }
113
114 } // namespace
115
116 QuicClientSession::StreamRequest::StreamRequest() : stream_(nullptr) {}
117
118 QuicClientSession::StreamRequest::~StreamRequest() {
119 CancelRequest();
120 }
121
122 int QuicClientSession::StreamRequest::StartRequest(
123 const base::WeakPtr<QuicClientSession>& session,
124 QuicReliableClientStream** stream,
125 const CompletionCallback& callback) {
126 session_ = session;
127 stream_ = stream;
128 int rv = session_->TryCreateStream(this, stream_);
129 if (rv == ERR_IO_PENDING) {
130 callback_ = callback;
131 }
132
133 return rv;
134 }
135
136 void QuicClientSession::StreamRequest::CancelRequest() {
137 if (session_)
138 session_->CancelRequest(this);
139 session_.reset();
140 callback_.Reset();
141 }
142
143 void QuicClientSession::StreamRequest::OnRequestCompleteSuccess(
144 QuicReliableClientStream* stream) {
145 session_.reset();
146 *stream_ = stream;
147 ResetAndReturn(&callback_).Run(OK);
148 }
149
150 void QuicClientSession::StreamRequest::OnRequestCompleteFailure(int rv) {
151 session_.reset();
152 ResetAndReturn(&callback_).Run(rv);
153 }
154
155 QuicClientSession::QuicClientSession(
156 QuicConnection* connection,
157 scoped_ptr<DatagramClientSocket> socket,
158 QuicStreamFactory* stream_factory,
159 TransportSecurityState* transport_security_state,
160 scoped_ptr<QuicServerInfo> server_info,
161 const QuicConfig& config,
162 base::TaskRunner* task_runner,
163 NetLog* net_log)
164 : QuicClientSessionBase(connection, config),
165 require_confirmation_(false),
166 stream_factory_(stream_factory),
167 socket_(socket.Pass()),
168 read_buffer_(new IOBufferWithSize(kMaxPacketSize)),
169 transport_security_state_(transport_security_state),
170 server_info_(server_info.Pass()),
171 read_pending_(false),
172 num_total_streams_(0),
173 task_runner_(task_runner),
174 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_QUIC_SESSION)),
175 logger_(new QuicConnectionLogger(this, net_log_)),
176 num_packets_read_(0),
177 going_away_(false),
178 weak_factory_(this) {
179 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
180 tracked_objects::ScopedTracker tracking_profile1(
181 FROM_HERE_WITH_EXPLICIT_FUNCTION(
182 "422516 QuicClientSession::QuicClientSession1"));
183
184 connection->set_debug_visitor(logger_);
185 IPEndPoint address;
186 // TODO(rtenneti): Remove ScopedTracker below once crbug.com/422516 is fixed.
187 tracked_objects::ScopedTracker tracking_profile2(
188 FROM_HERE_WITH_EXPLICIT_FUNCTION(
189 "422516 QuicClientSession::QuicClientSession2"));
190 if (socket && socket->GetLocalAddress(&address) == OK &&
191 address.GetFamily() == ADDRESS_FAMILY_IPV6) {
192 connection->set_max_packet_length(
193 connection->max_packet_length() - kAdditionalOverheadForIPv6);
194 }
195 }
196
197 void QuicClientSession::InitializeSession(
198 const QuicServerId& server_id,
199 QuicCryptoClientConfig* crypto_config,
200 QuicCryptoClientStreamFactory* crypto_client_stream_factory) {
201 server_id_ = server_id;
202 crypto_stream_.reset(
203 crypto_client_stream_factory ?
204 crypto_client_stream_factory->CreateQuicCryptoClientStream(
205 server_id, this, crypto_config) :
206 new QuicCryptoClientStream(server_id, this,
207 new ProofVerifyContextChromium(net_log_),
208 crypto_config));
209 QuicClientSessionBase::InitializeSession();
210 // TODO(rch): pass in full host port proxy pair
211 net_log_.BeginEvent(NetLog::TYPE_QUIC_SESSION,
212 base::Bind(NetLogQuicClientSessionCallback,
213 &server_id,
214 require_confirmation_));
215 }
216
217 QuicClientSession::~QuicClientSession() {
218 if (!streams()->empty())
219 RecordUnexpectedOpenStreams(DESTRUCTOR);
220 if (!observers_.empty())
221 RecordUnexpectedObservers(DESTRUCTOR);
222 if (!going_away_)
223 RecordUnexpectedNotGoingAway(DESTRUCTOR);
224
225 while (!streams()->empty() ||
226 !observers_.empty() ||
227 !stream_requests_.empty()) {
228 // The session must be closed before it is destroyed.
229 DCHECK(streams()->empty());
230 CloseAllStreams(ERR_UNEXPECTED);
231 DCHECK(observers_.empty());
232 CloseAllObservers(ERR_UNEXPECTED);
233
234 connection()->set_debug_visitor(nullptr);
235 net_log_.EndEvent(NetLog::TYPE_QUIC_SESSION);
236
237 while (!stream_requests_.empty()) {
238 StreamRequest* request = stream_requests_.front();
239 stream_requests_.pop_front();
240 request->OnRequestCompleteFailure(ERR_ABORTED);
241 }
242 }
243
244 if (connection()->connected()) {
245 // Ensure that the connection is closed by the time the session is
246 // destroyed.
247 connection()->CloseConnection(QUIC_INTERNAL_ERROR, false);
248 }
249
250 if (IsEncryptionEstablished())
251 RecordHandshakeState(STATE_ENCRYPTION_ESTABLISHED);
252 if (IsCryptoHandshakeConfirmed())
253 RecordHandshakeState(STATE_HANDSHAKE_CONFIRMED);
254 else
255 RecordHandshakeState(STATE_FAILED);
256
257 UMA_HISTOGRAM_COUNTS("Net.QuicSession.NumTotalStreams", num_total_streams_);
258 UMA_HISTOGRAM_COUNTS("Net.QuicNumSentClientHellos",
259 crypto_stream_->num_sent_client_hellos());
260 if (!IsCryptoHandshakeConfirmed())
261 return;
262
263 // Sending one client_hello means we had zero handshake-round-trips.
264 int round_trip_handshakes = crypto_stream_->num_sent_client_hellos() - 1;
265
266 // Don't bother with these histogram during tests, which mock out
267 // num_sent_client_hellos().
268 if (round_trip_handshakes < 0 || !stream_factory_)
269 return;
270
271 bool port_selected = stream_factory_->enable_port_selection();
272 SSLInfo ssl_info;
273 if (!GetSSLInfo(&ssl_info) || !ssl_info.cert.get()) {
274 if (port_selected) {
275 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectSelectPortForHTTP",
276 round_trip_handshakes, 0, 3, 4);
277 } else {
278 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectRandomPortForHTTP",
279 round_trip_handshakes, 0, 3, 4);
280 if (require_confirmation_) {
281 UMA_HISTOGRAM_CUSTOM_COUNTS(
282 "Net.QuicSession.ConnectRandomPortRequiringConfirmationForHTTP",
283 round_trip_handshakes, 0, 3, 4);
284 }
285 }
286 } else {
287 if (port_selected) {
288 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectSelectPortForHTTPS",
289 round_trip_handshakes, 0, 3, 4);
290 } else {
291 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectRandomPortForHTTPS",
292 round_trip_handshakes, 0, 3, 4);
293 if (require_confirmation_) {
294 UMA_HISTOGRAM_CUSTOM_COUNTS(
295 "Net.QuicSession.ConnectRandomPortRequiringConfirmationForHTTPS",
296 round_trip_handshakes, 0, 3, 4);
297 }
298 }
299 }
300 const QuicConnectionStats stats = connection()->GetStats();
301 if (server_info_ && stats.min_rtt_us > 0) {
302 base::TimeTicks wait_for_data_start_time =
303 server_info_->wait_for_data_start_time();
304 base::TimeTicks wait_for_data_end_time =
305 server_info_->wait_for_data_end_time();
306 if (!wait_for_data_start_time.is_null() &&
307 !wait_for_data_end_time.is_null()) {
308 base::TimeDelta wait_time =
309 wait_for_data_end_time - wait_for_data_start_time;
310 const base::HistogramBase::Sample kMaxWaitToRtt = 1000;
311 base::HistogramBase::Sample wait_to_rtt =
312 static_cast<base::HistogramBase::Sample>(
313 100 * wait_time.InMicroseconds() / stats.min_rtt_us);
314 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicServerInfo.WaitForDataReadyToRtt",
315 wait_to_rtt, 0, kMaxWaitToRtt, 50);
316 }
317 }
318
319 if (stats.max_sequence_reordering == 0)
320 return;
321 const base::HistogramBase::Sample kMaxReordering = 100;
322 base::HistogramBase::Sample reordering = kMaxReordering;
323 if (stats.min_rtt_us > 0) {
324 reordering = static_cast<base::HistogramBase::Sample>(
325 100 * stats.max_time_reordering_us / stats.min_rtt_us);
326 }
327 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.MaxReorderingTime",
328 reordering, 0, kMaxReordering, 50);
329 if (stats.min_rtt_us > 100 * 1000) {
330 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.MaxReorderingTimeLongRtt",
331 reordering, 0, kMaxReordering, 50);
332 }
333 UMA_HISTOGRAM_COUNTS(
334 "Net.QuicSession.MaxReordering",
335 static_cast<base::HistogramBase::Sample>(stats.max_sequence_reordering));
336 }
337
338 void QuicClientSession::OnStreamFrames(
339 const std::vector<QuicStreamFrame>& frames) {
340 // Record total number of stream frames.
341 UMA_HISTOGRAM_COUNTS("Net.QuicNumStreamFramesInPacket", frames.size());
342
343 // Record number of frames per stream in packet.
344 typedef std::map<QuicStreamId, size_t> FrameCounter;
345 FrameCounter frames_per_stream;
346 for (size_t i = 0; i < frames.size(); ++i) {
347 frames_per_stream[frames[i].stream_id]++;
348 }
349 for (FrameCounter::const_iterator it = frames_per_stream.begin();
350 it != frames_per_stream.end(); ++it) {
351 UMA_HISTOGRAM_COUNTS("Net.QuicNumStreamFramesPerStreamInPacket",
352 it->second);
353 }
354
355 return QuicSession::OnStreamFrames(frames);
356 }
357
358 void QuicClientSession::AddObserver(Observer* observer) {
359 if (going_away_) {
360 RecordUnexpectedObservers(ADD_OBSERVER);
361 observer->OnSessionClosed(ERR_UNEXPECTED);
362 return;
363 }
364
365 DCHECK(!ContainsKey(observers_, observer));
366 observers_.insert(observer);
367 }
368
369 void QuicClientSession::RemoveObserver(Observer* observer) {
370 DCHECK(ContainsKey(observers_, observer));
371 observers_.erase(observer);
372 }
373
374 int QuicClientSession::TryCreateStream(StreamRequest* request,
375 QuicReliableClientStream** stream) {
376 if (!crypto_stream_->encryption_established()) {
377 DLOG(DFATAL) << "Encryption not established.";
378 return ERR_CONNECTION_CLOSED;
379 }
380
381 if (goaway_received()) {
382 DVLOG(1) << "Going away.";
383 return ERR_CONNECTION_CLOSED;
384 }
385
386 if (!connection()->connected()) {
387 DVLOG(1) << "Already closed.";
388 return ERR_CONNECTION_CLOSED;
389 }
390
391 if (going_away_) {
392 RecordUnexpectedOpenStreams(TRY_CREATE_STREAM);
393 return ERR_CONNECTION_CLOSED;
394 }
395
396 if (GetNumOpenStreams() < get_max_open_streams()) {
397 *stream = CreateOutgoingReliableStreamImpl();
398 return OK;
399 }
400
401 stream_requests_.push_back(request);
402 return ERR_IO_PENDING;
403 }
404
405 void QuicClientSession::CancelRequest(StreamRequest* request) {
406 // Remove |request| from the queue while preserving the order of the
407 // other elements.
408 StreamRequestQueue::iterator it =
409 std::find(stream_requests_.begin(), stream_requests_.end(), request);
410 if (it != stream_requests_.end()) {
411 it = stream_requests_.erase(it);
412 }
413 }
414
415 QuicReliableClientStream* QuicClientSession::CreateOutgoingDataStream() {
416 if (!crypto_stream_->encryption_established()) {
417 DVLOG(1) << "Encryption not active so no outgoing stream created.";
418 return nullptr;
419 }
420 if (GetNumOpenStreams() >= get_max_open_streams()) {
421 DVLOG(1) << "Failed to create a new outgoing stream. "
422 << "Already " << GetNumOpenStreams() << " open.";
423 return nullptr;
424 }
425 if (goaway_received()) {
426 DVLOG(1) << "Failed to create a new outgoing stream. "
427 << "Already received goaway.";
428 return nullptr;
429 }
430 if (going_away_) {
431 RecordUnexpectedOpenStreams(CREATE_OUTGOING_RELIABLE_STREAM);
432 return nullptr;
433 }
434 return CreateOutgoingReliableStreamImpl();
435 }
436
437 QuicReliableClientStream*
438 QuicClientSession::CreateOutgoingReliableStreamImpl() {
439 DCHECK(connection()->connected());
440 QuicReliableClientStream* stream =
441 new QuicReliableClientStream(GetNextStreamId(), this, net_log_);
442 ActivateStream(stream);
443 ++num_total_streams_;
444 UMA_HISTOGRAM_COUNTS("Net.QuicSession.NumOpenStreams", GetNumOpenStreams());
445 return stream;
446 }
447
448 QuicCryptoClientStream* QuicClientSession::GetCryptoStream() {
449 return crypto_stream_.get();
450 };
451
452 // TODO(rtenneti): Add unittests for GetSSLInfo which exercise the various ways
453 // we learn about SSL info (sync vs async vs cached).
454 bool QuicClientSession::GetSSLInfo(SSLInfo* ssl_info) const {
455 ssl_info->Reset();
456 if (!cert_verify_result_) {
457 return false;
458 }
459
460 ssl_info->cert_status = cert_verify_result_->cert_status;
461 ssl_info->cert = cert_verify_result_->verified_cert;
462
463 // TODO(wtc): Define QUIC "cipher suites".
464 // Report the TLS cipher suite that most closely resembles the crypto
465 // parameters of the QUIC connection.
466 QuicTag aead = crypto_stream_->crypto_negotiated_params().aead;
467 uint16 cipher_suite;
468 int security_bits;
469 switch (aead) {
470 case kAESG:
471 cipher_suite = 0xc02f; // TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
472 security_bits = 128;
473 break;
474 case kCC12:
475 cipher_suite = 0xcc13; // TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
476 security_bits = 256;
477 break;
478 default:
479 NOTREACHED();
480 return false;
481 }
482 int ssl_connection_status = 0;
483 ssl_connection_status |= cipher_suite;
484 ssl_connection_status |=
485 (SSL_CONNECTION_VERSION_QUIC & SSL_CONNECTION_VERSION_MASK) <<
486 SSL_CONNECTION_VERSION_SHIFT;
487
488 ssl_info->public_key_hashes = cert_verify_result_->public_key_hashes;
489 ssl_info->is_issued_by_known_root =
490 cert_verify_result_->is_issued_by_known_root;
491
492 ssl_info->connection_status = ssl_connection_status;
493 ssl_info->client_cert_sent = false;
494 ssl_info->channel_id_sent = crypto_stream_->WasChannelIDSent();
495 ssl_info->security_bits = security_bits;
496 ssl_info->handshake_type = SSLInfo::HANDSHAKE_FULL;
497 ssl_info->pinning_failure_log = pinning_failure_log_;
498 return true;
499 }
500
501 int QuicClientSession::CryptoConnect(bool require_confirmation,
502 const CompletionCallback& callback) {
503 require_confirmation_ = require_confirmation;
504 handshake_start_ = base::TimeTicks::Now();
505 RecordHandshakeState(STATE_STARTED);
506 DCHECK(flow_controller());
507 crypto_stream_->CryptoConnect();
508
509 if (IsCryptoHandshakeConfirmed())
510 return OK;
511
512 // Unless we require handshake confirmation, activate the session if
513 // we have established initial encryption.
514 if (!require_confirmation_ && IsEncryptionEstablished()) {
515 // To mitigate the effects of hanging 0-RTT connections, set up a timer to
516 // cancel any requests, if the handshake takes too long.
517 task_runner_->PostDelayedTask(
518 FROM_HERE,
519 base::Bind(&QuicClientSession::OnConnectTimeout,
520 weak_factory_.GetWeakPtr()),
521 base::TimeDelta::FromMilliseconds(k0RttHandshakeTimeoutMs));
522 return OK;
523
524 }
525
526 callback_ = callback;
527 return ERR_IO_PENDING;
528 }
529
530 int QuicClientSession::ResumeCryptoConnect(const CompletionCallback& callback) {
531
532 if (IsCryptoHandshakeConfirmed())
533 return OK;
534
535 if (!connection()->connected())
536 return ERR_QUIC_HANDSHAKE_FAILED;
537
538 callback_ = callback;
539 return ERR_IO_PENDING;
540 }
541
542 int QuicClientSession::GetNumSentClientHellos() const {
543 return crypto_stream_->num_sent_client_hellos();
544 }
545
546 bool QuicClientSession::CanPool(const std::string& hostname,
547 PrivacyMode privacy_mode) const {
548 DCHECK(connection()->connected());
549 if (privacy_mode != server_id_.privacy_mode()) {
550 // Privacy mode must always match.
551 return false;
552 }
553 SSLInfo ssl_info;
554 if (!GetSSLInfo(&ssl_info) || !ssl_info.cert.get()) {
555 // We can always pool with insecure QUIC sessions.
556 return true;
557 }
558
559 return SpdySession::CanPool(transport_security_state_, ssl_info,
560 server_id_.host(), hostname);
561 }
562
563 QuicDataStream* QuicClientSession::CreateIncomingDataStream(
564 QuicStreamId id) {
565 DLOG(ERROR) << "Server push not supported";
566 return nullptr;
567 }
568
569 void QuicClientSession::CloseStream(QuicStreamId stream_id) {
570 ReliableQuicStream* stream = GetStream(stream_id);
571 if (stream) {
572 logger_->UpdateReceivedFrameCounts(
573 stream_id, stream->num_frames_received(),
574 stream->num_duplicate_frames_received());
575 }
576 QuicSession::CloseStream(stream_id);
577 OnClosedStream();
578 }
579
580 void QuicClientSession::SendRstStream(QuicStreamId id,
581 QuicRstStreamErrorCode error,
582 QuicStreamOffset bytes_written) {
583 QuicSession::SendRstStream(id, error, bytes_written);
584 OnClosedStream();
585 }
586
587 void QuicClientSession::OnClosedStream() {
588 if (GetNumOpenStreams() < get_max_open_streams() &&
589 !stream_requests_.empty() &&
590 crypto_stream_->encryption_established() &&
591 !goaway_received() &&
592 !going_away_ &&
593 connection()->connected()) {
594 StreamRequest* request = stream_requests_.front();
595 stream_requests_.pop_front();
596 request->OnRequestCompleteSuccess(CreateOutgoingReliableStreamImpl());
597 }
598
599 if (GetNumOpenStreams() == 0) {
600 stream_factory_->OnIdleSession(this);
601 }
602 }
603
604 void QuicClientSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) {
605 if (!callback_.is_null() &&
606 (!require_confirmation_ ||
607 event == HANDSHAKE_CONFIRMED || event == ENCRYPTION_REESTABLISHED)) {
608 // TODO(rtenneti): Currently for all CryptoHandshakeEvent events, callback_
609 // could be called because there are no error events in CryptoHandshakeEvent
610 // enum. If error events are added to CryptoHandshakeEvent, then the
611 // following code needs to changed.
612 base::ResetAndReturn(&callback_).Run(OK);
613 }
614 if (event == HANDSHAKE_CONFIRMED) {
615 UMA_HISTOGRAM_TIMES("Net.QuicSession.HandshakeConfirmedTime",
616 base::TimeTicks::Now() - handshake_start_);
617 if (server_info_) {
618 // Track how long it has taken to finish handshake once we start waiting
619 // for reading of QUIC server information from disk cache. We could use
620 // this data to compare total time taken if we were to cancel the disk
621 // cache read vs waiting for the read to complete.
622 base::TimeTicks wait_for_data_start_time =
623 server_info_->wait_for_data_start_time();
624 if (!wait_for_data_start_time.is_null()) {
625 UMA_HISTOGRAM_TIMES(
626 "Net.QuicServerInfo.WaitForDataReady.HandshakeConfirmedTime",
627 base::TimeTicks::Now() - wait_for_data_start_time);
628 }
629 }
630
631 ObserverSet::iterator it = observers_.begin();
632 while (it != observers_.end()) {
633 Observer* observer = *it;
634 ++it;
635 observer->OnCryptoHandshakeConfirmed();
636 }
637 if (server_info_)
638 server_info_->OnExternalCacheHit();
639 }
640 QuicSession::OnCryptoHandshakeEvent(event);
641 }
642
643 void QuicClientSession::OnCryptoHandshakeMessageSent(
644 const CryptoHandshakeMessage& message) {
645 logger_->OnCryptoHandshakeMessageSent(message);
646 }
647
648 void QuicClientSession::OnCryptoHandshakeMessageReceived(
649 const CryptoHandshakeMessage& message) {
650 logger_->OnCryptoHandshakeMessageReceived(message);
651 }
652
653 void QuicClientSession::OnConnectionClosed(QuicErrorCode error,
654 bool from_peer) {
655 DCHECK(!connection()->connected());
656 logger_->OnConnectionClosed(error, from_peer);
657 if (from_peer) {
658 UMA_HISTOGRAM_SPARSE_SLOWLY(
659 "Net.QuicSession.ConnectionCloseErrorCodeServer", error);
660 } else {
661 UMA_HISTOGRAM_SPARSE_SLOWLY(
662 "Net.QuicSession.ConnectionCloseErrorCodeClient", error);
663 }
664
665 if (error == QUIC_CONNECTION_TIMED_OUT) {
666 UMA_HISTOGRAM_COUNTS(
667 "Net.QuicSession.ConnectionClose.NumOpenStreams.TimedOut",
668 GetNumOpenStreams());
669 if (IsCryptoHandshakeConfirmed()) {
670 if (GetNumOpenStreams() > 0) {
671 UMA_HISTOGRAM_BOOLEAN(
672 "Net.QuicSession.TimedOutWithOpenStreams.HasUnackedPackets",
673 connection()->sent_packet_manager().HasUnackedPackets());
674 UMA_HISTOGRAM_COUNTS(
675 "Net.QuicSession.TimedOutWithOpenStreams.ConsecutiveRTOCount",
676 connection()->sent_packet_manager().consecutive_rto_count());
677 UMA_HISTOGRAM_COUNTS(
678 "Net.QuicSession.TimedOutWithOpenStreams.ConsecutiveTLPCount",
679 connection()->sent_packet_manager().consecutive_tlp_count());
680 }
681 if (connection()->sent_packet_manager().HasUnackedPackets()) {
682 UMA_HISTOGRAM_TIMES(
683 "Net.QuicSession.LocallyTimedOutWithOpenStreams."
684 "TimeSinceLastReceived.UnackedPackets",
685 NetworkActivityMonitor::GetInstance()->GetTimeSinceLastReceived());
686 } else {
687 UMA_HISTOGRAM_TIMES(
688 "Net.QuicSession.LocallyTimedOutWithOpenStreams."
689 "TimeSinceLastReceived.NoUnackedPackets",
690 NetworkActivityMonitor::GetInstance()->GetTimeSinceLastReceived());
691 }
692
693 } else {
694 UMA_HISTOGRAM_COUNTS(
695 "Net.QuicSession.ConnectionClose.NumOpenStreams.HandshakeTimedOut",
696 GetNumOpenStreams());
697 UMA_HISTOGRAM_COUNTS(
698 "Net.QuicSession.ConnectionClose.NumTotalStreams.HandshakeTimedOut",
699 num_total_streams_);
700 }
701 }
702
703 if (!IsCryptoHandshakeConfirmed()) {
704 if (error == QUIC_PUBLIC_RESET) {
705 RecordHandshakeFailureReason(HANDSHAKE_FAILURE_PUBLIC_RESET);
706 } else if (connection()->GetStats().packets_received == 0) {
707 RecordHandshakeFailureReason(HANDSHAKE_FAILURE_BLACK_HOLE);
708 UMA_HISTOGRAM_SPARSE_SLOWLY(
709 "Net.QuicSession.ConnectionClose.HandshakeFailureBlackHole.QuicError",
710 error);
711 } else {
712 RecordHandshakeFailureReason(HANDSHAKE_FAILURE_UNKNOWN);
713 UMA_HISTOGRAM_SPARSE_SLOWLY(
714 "Net.QuicSession.ConnectionClose.HandshakeFailureUnknown.QuicError",
715 error);
716 }
717 }
718
719 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.QuicVersion",
720 connection()->version());
721 NotifyFactoryOfSessionGoingAway();
722 if (!callback_.is_null()) {
723 base::ResetAndReturn(&callback_).Run(ERR_QUIC_PROTOCOL_ERROR);
724 }
725 socket_->Close();
726 QuicSession::OnConnectionClosed(error, from_peer);
727 DCHECK(streams()->empty());
728 CloseAllStreams(ERR_UNEXPECTED);
729 CloseAllObservers(ERR_UNEXPECTED);
730 NotifyFactoryOfSessionClosedLater();
731 }
732
733 void QuicClientSession::OnSuccessfulVersionNegotiation(
734 const QuicVersion& version) {
735 logger_->OnSuccessfulVersionNegotiation(version);
736 QuicSession::OnSuccessfulVersionNegotiation(version);
737 }
738
739 void QuicClientSession::OnProofValid(
740 const QuicCryptoClientConfig::CachedState& cached) {
741 DCHECK(cached.proof_valid());
742
743 if (!server_info_) {
744 return;
745 }
746
747 QuicServerInfo::State* state = server_info_->mutable_state();
748
749 state->server_config = cached.server_config();
750 state->source_address_token = cached.source_address_token();
751 state->server_config_sig = cached.signature();
752 state->certs = cached.certs();
753
754 server_info_->Persist();
755 }
756
757 void QuicClientSession::OnProofVerifyDetailsAvailable(
758 const ProofVerifyDetails& verify_details) {
759 const ProofVerifyDetailsChromium* verify_details_chromium =
760 reinterpret_cast<const ProofVerifyDetailsChromium*>(&verify_details);
761 CertVerifyResult* result_copy = new CertVerifyResult;
762 result_copy->CopyFrom(verify_details_chromium->cert_verify_result);
763 cert_verify_result_.reset(result_copy);
764 pinning_failure_log_ = verify_details_chromium->pinning_failure_log;
765 logger_->OnCertificateVerified(*cert_verify_result_);
766 }
767
768 void QuicClientSession::StartReading() {
769 if (read_pending_) {
770 return;
771 }
772 read_pending_ = true;
773 int rv = socket_->Read(read_buffer_.get(),
774 read_buffer_->size(),
775 base::Bind(&QuicClientSession::OnReadComplete,
776 weak_factory_.GetWeakPtr()));
777 UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.AsyncRead", rv == ERR_IO_PENDING);
778 if (rv == ERR_IO_PENDING) {
779 num_packets_read_ = 0;
780 return;
781 }
782
783 if (++num_packets_read_ > 32) {
784 num_packets_read_ = 0;
785 // Data was read, process it.
786 // Schedule the work through the message loop to 1) prevent infinite
787 // recursion and 2) avoid blocking the thread for too long.
788 base::MessageLoop::current()->PostTask(
789 FROM_HERE,
790 base::Bind(&QuicClientSession::OnReadComplete,
791 weak_factory_.GetWeakPtr(), rv));
792 } else {
793 OnReadComplete(rv);
794 }
795 }
796
797 void QuicClientSession::CloseSessionOnError(int error) {
798 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.CloseSessionOnError", -error);
799 CloseSessionOnErrorInner(error, QUIC_INTERNAL_ERROR);
800 NotifyFactoryOfSessionClosed();
801 }
802
803 void QuicClientSession::CloseSessionOnErrorInner(int net_error,
804 QuicErrorCode quic_error) {
805 if (!callback_.is_null()) {
806 base::ResetAndReturn(&callback_).Run(net_error);
807 }
808 CloseAllStreams(net_error);
809 CloseAllObservers(net_error);
810 net_log_.AddEvent(
811 NetLog::TYPE_QUIC_SESSION_CLOSE_ON_ERROR,
812 NetLog::IntegerCallback("net_error", net_error));
813
814 if (connection()->connected())
815 connection()->CloseConnection(quic_error, false);
816 DCHECK(!connection()->connected());
817 }
818
819 void QuicClientSession::CloseAllStreams(int net_error) {
820 while (!streams()->empty()) {
821 ReliableQuicStream* stream = streams()->begin()->second;
822 QuicStreamId id = stream->id();
823 static_cast<QuicReliableClientStream*>(stream)->OnError(net_error);
824 CloseStream(id);
825 }
826 }
827
828 void QuicClientSession::CloseAllObservers(int net_error) {
829 while (!observers_.empty()) {
830 Observer* observer = *observers_.begin();
831 observers_.erase(observer);
832 observer->OnSessionClosed(net_error);
833 }
834 }
835
836 base::Value* QuicClientSession::GetInfoAsValue(
837 const std::set<HostPortPair>& aliases) {
838 base::DictionaryValue* dict = new base::DictionaryValue();
839 dict->SetString("version", QuicVersionToString(connection()->version()));
840 dict->SetInteger("open_streams", GetNumOpenStreams());
841 base::ListValue* stream_list = new base::ListValue();
842 for (base::hash_map<QuicStreamId, QuicDataStream*>::const_iterator it
843 = streams()->begin();
844 it != streams()->end();
845 ++it) {
846 stream_list->Append(new base::StringValue(
847 base::Uint64ToString(it->second->id())));
848 }
849 dict->Set("active_streams", stream_list);
850
851 dict->SetInteger("total_streams", num_total_streams_);
852 dict->SetString("peer_address", peer_address().ToString());
853 dict->SetString("connection_id", base::Uint64ToString(connection_id()));
854 dict->SetBoolean("connected", connection()->connected());
855 const QuicConnectionStats& stats = connection()->GetStats();
856 dict->SetInteger("packets_sent", stats.packets_sent);
857 dict->SetInteger("packets_received", stats.packets_received);
858 dict->SetInteger("packets_lost", stats.packets_lost);
859 SSLInfo ssl_info;
860 dict->SetBoolean("secure", GetSSLInfo(&ssl_info) && ssl_info.cert.get());
861
862 base::ListValue* alias_list = new base::ListValue();
863 for (std::set<HostPortPair>::const_iterator it = aliases.begin();
864 it != aliases.end(); it++) {
865 alias_list->Append(new base::StringValue(it->ToString()));
866 }
867 dict->Set("aliases", alias_list);
868
869 return dict;
870 }
871
872 base::WeakPtr<QuicClientSession> QuicClientSession::GetWeakPtr() {
873 return weak_factory_.GetWeakPtr();
874 }
875
876 void QuicClientSession::OnReadComplete(int result) {
877 read_pending_ = false;
878 if (result == 0)
879 result = ERR_CONNECTION_CLOSED;
880
881 if (result < 0) {
882 DVLOG(1) << "Closing session on read error: " << result;
883 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.ReadError", -result);
884 NotifyFactoryOfSessionGoingAway();
885 CloseSessionOnErrorInner(result, QUIC_PACKET_READ_ERROR);
886 NotifyFactoryOfSessionClosedLater();
887 return;
888 }
889
890 QuicEncryptedPacket packet(read_buffer_->data(), result);
891 IPEndPoint local_address;
892 IPEndPoint peer_address;
893 socket_->GetLocalAddress(&local_address);
894 socket_->GetPeerAddress(&peer_address);
895 // ProcessUdpPacket might result in |this| being deleted, so we
896 // use a weak pointer to be safe.
897 connection()->ProcessUdpPacket(local_address, peer_address, packet);
898 if (!connection()->connected()) {
899 NotifyFactoryOfSessionClosedLater();
900 return;
901 }
902 StartReading();
903 }
904
905 void QuicClientSession::NotifyFactoryOfSessionGoingAway() {
906 going_away_ = true;
907 if (stream_factory_)
908 stream_factory_->OnSessionGoingAway(this);
909 }
910
911 void QuicClientSession::NotifyFactoryOfSessionClosedLater() {
912 if (!streams()->empty())
913 RecordUnexpectedOpenStreams(NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER);
914
915 if (!going_away_)
916 RecordUnexpectedNotGoingAway(NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER);
917
918 going_away_ = true;
919 DCHECK_EQ(0u, GetNumOpenStreams());
920 DCHECK(!connection()->connected());
921 base::MessageLoop::current()->PostTask(
922 FROM_HERE,
923 base::Bind(&QuicClientSession::NotifyFactoryOfSessionClosed,
924 weak_factory_.GetWeakPtr()));
925 }
926
927 void QuicClientSession::NotifyFactoryOfSessionClosed() {
928 if (!streams()->empty())
929 RecordUnexpectedOpenStreams(NOTIFY_FACTORY_OF_SESSION_CLOSED);
930
931 if (!going_away_)
932 RecordUnexpectedNotGoingAway(NOTIFY_FACTORY_OF_SESSION_CLOSED);
933
934 going_away_ = true;
935 DCHECK_EQ(0u, GetNumOpenStreams());
936 // Will delete |this|.
937 if (stream_factory_)
938 stream_factory_->OnSessionClosed(this);
939 }
940
941 void QuicClientSession::OnConnectTimeout() {
942 DCHECK(callback_.is_null());
943 DCHECK(IsEncryptionEstablished());
944
945 if (IsCryptoHandshakeConfirmed())
946 return;
947
948 // TODO(rch): re-enable this code once beta is cut.
949 // if (stream_factory_)
950 // stream_factory_->OnSessionConnectTimeout(this);
951 // CloseAllStreams(ERR_QUIC_HANDSHAKE_FAILED);
952 // DCHECK_EQ(0u, GetNumOpenStreams());
953 }
954
955 } // namespace net
OLDNEW
« no previous file with comments | « net/quic/quic_client_session.h ('k') | net/quic/quic_client_session_base.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698