Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / net / quic / quic_client_session.cc
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/stl_util.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/values.h"
14 #include "net/base/io_buffer.h"
15 #include "net/base/net_errors.h"
16 #include "net/quic/quic_connection_helper.h"
17 #include "net/quic/quic_crypto_client_stream_factory.h"
18 #include "net/quic/quic_default_packet_writer.h"
19 #include "net/quic/quic_stream_factory.h"
20 #include "net/ssl/ssl_info.h"
21 #include "net/udp/datagram_client_socket.h"
22
23 namespace net {
24
25 namespace {
26
27 // Note: these values must be kept in sync with the corresponding values in:
28 // tools/metrics/histograms/histograms.xml
29 enum HandshakeState {
30   STATE_STARTED = 0,
31   STATE_ENCRYPTION_ESTABLISHED = 1,
32   STATE_HANDSHAKE_CONFIRMED = 2,
33   STATE_FAILED = 3,
34   NUM_HANDSHAKE_STATES = 4
35 };
36
37 void RecordHandshakeState(HandshakeState state) {
38   UMA_HISTOGRAM_ENUMERATION("Net.QuicHandshakeState", state,
39                             NUM_HANDSHAKE_STATES);
40 }
41
42 }  // namespace
43
44 QuicClientSession::StreamRequest::StreamRequest() : stream_(NULL) {}
45
46 QuicClientSession::StreamRequest::~StreamRequest() {
47   CancelRequest();
48 }
49
50 int QuicClientSession::StreamRequest::StartRequest(
51     const base::WeakPtr<QuicClientSession>& session,
52     QuicReliableClientStream** stream,
53     const CompletionCallback& callback) {
54   session_ = session;
55   stream_ = stream;
56   int rv = session_->TryCreateStream(this, stream_);
57   if (rv == ERR_IO_PENDING) {
58     callback_ = callback;
59   }
60
61   return rv;
62 }
63
64 void QuicClientSession::StreamRequest::CancelRequest() {
65   if (session_)
66     session_->CancelRequest(this);
67   session_.reset();
68   callback_.Reset();
69 }
70
71 void QuicClientSession::StreamRequest::OnRequestCompleteSuccess(
72     QuicReliableClientStream* stream) {
73   session_.reset();
74   *stream_ = stream;
75   ResetAndReturn(&callback_).Run(OK);
76 }
77
78 void QuicClientSession::StreamRequest::OnRequestCompleteFailure(int rv) {
79   session_.reset();
80   ResetAndReturn(&callback_).Run(rv);
81 }
82
83 QuicClientSession::QuicClientSession(
84     QuicConnection* connection,
85     scoped_ptr<DatagramClientSocket> socket,
86     scoped_ptr<QuicDefaultPacketWriter> writer,
87     QuicStreamFactory* stream_factory,
88     QuicCryptoClientStreamFactory* crypto_client_stream_factory,
89     const string& server_hostname,
90     const QuicConfig& config,
91     QuicCryptoClientConfig* crypto_config,
92     NetLog* net_log)
93     : QuicSession(connection, config),
94       require_confirmation_(false),
95       stream_factory_(stream_factory),
96       socket_(socket.Pass()),
97       writer_(writer.Pass()),
98       read_buffer_(new IOBufferWithSize(kMaxPacketSize)),
99       read_pending_(false),
100       num_total_streams_(0),
101       net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_QUIC_SESSION)),
102       logger_(net_log_),
103       num_packets_read_(0),
104       weak_factory_(this) {
105   crypto_stream_.reset(
106       crypto_client_stream_factory ?
107           crypto_client_stream_factory->CreateQuicCryptoClientStream(
108               server_hostname, this, crypto_config) :
109           new QuicCryptoClientStream(server_hostname, this, crypto_config));
110
111   connection->set_debug_visitor(&logger_);
112   // TODO(rch): pass in full host port proxy pair
113   net_log_.BeginEvent(
114       NetLog::TYPE_QUIC_SESSION,
115       NetLog::StringCallback("host", &server_hostname));
116 }
117
118 QuicClientSession::~QuicClientSession() {
119   // The session must be closed before it is destroyed.
120   DCHECK(streams()->empty());
121   CloseAllStreams(ERR_UNEXPECTED);
122   DCHECK(observers_.empty());
123   CloseAllObservers(ERR_UNEXPECTED);
124
125   connection()->set_debug_visitor(NULL);
126   net_log_.EndEvent(NetLog::TYPE_QUIC_SESSION);
127
128   while (!stream_requests_.empty()) {
129     StreamRequest* request = stream_requests_.front();
130     stream_requests_.pop_front();
131     request->OnRequestCompleteFailure(ERR_ABORTED);
132   }
133
134   if (IsEncryptionEstablished())
135     RecordHandshakeState(STATE_ENCRYPTION_ESTABLISHED);
136   if (IsCryptoHandshakeConfirmed())
137     RecordHandshakeState(STATE_HANDSHAKE_CONFIRMED);
138   else
139     RecordHandshakeState(STATE_FAILED);
140
141   UMA_HISTOGRAM_COUNTS("Net.QuicSession.NumTotalStreams", num_total_streams_);
142   UMA_HISTOGRAM_COUNTS("Net.QuicNumSentClientHellos",
143                        crypto_stream_->num_sent_client_hellos());
144   if (!IsCryptoHandshakeConfirmed())
145     return;
146
147   // Sending one client_hello means we had zero handshake-round-trips.
148   int round_trip_handshakes = crypto_stream_->num_sent_client_hellos() - 1;
149
150   // Don't bother with these histogram during tests, which mock out
151   // num_sent_client_hellos().
152   if (round_trip_handshakes < 0 || !stream_factory_)
153     return;
154
155   bool port_selected = stream_factory_->enable_port_selection();
156   SSLInfo ssl_info;
157   if (!crypto_stream_->GetSSLInfo(&ssl_info) || !ssl_info.cert) {
158     if (port_selected) {
159       UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectSelectPortForHTTP",
160                                   round_trip_handshakes, 0, 3, 4);
161     } else {
162       UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectRandomPortForHTTP",
163                                   round_trip_handshakes, 0, 3, 4);
164     }
165   } else {
166     if (port_selected) {
167       UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectSelectPortForHTTPS",
168                                   round_trip_handshakes, 0, 3, 4);
169     } else {
170       UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectRandomPortForHTTPS",
171                                   round_trip_handshakes, 0, 3, 4);
172     }
173   }
174 }
175
176 bool QuicClientSession::OnStreamFrames(
177     const std::vector<QuicStreamFrame>& frames) {
178   // Record total number of stream frames.
179   UMA_HISTOGRAM_COUNTS("Net.QuicNumStreamFramesInPacket", frames.size());
180
181   // Record number of frames per stream in packet.
182   typedef std::map<QuicStreamId, size_t> FrameCounter;
183   FrameCounter frames_per_stream;
184   for (size_t i = 0; i < frames.size(); ++i) {
185     frames_per_stream[frames[i].stream_id]++;
186   }
187   for (FrameCounter::const_iterator it = frames_per_stream.begin();
188        it != frames_per_stream.end(); ++it) {
189     UMA_HISTOGRAM_COUNTS("Net.QuicNumStreamFramesPerStreamInPacket",
190                          it->second);
191   }
192
193   return QuicSession::OnStreamFrames(frames);
194 }
195
196 void QuicClientSession::AddObserver(Observer* observer) {
197   DCHECK(!ContainsKey(observers_, observer));
198   observers_.insert(observer);
199 }
200
201 void QuicClientSession::RemoveObserver(Observer* observer) {
202   DCHECK(ContainsKey(observers_, observer));
203   observers_.erase(observer);
204 }
205
206 int QuicClientSession::TryCreateStream(StreamRequest* request,
207                                        QuicReliableClientStream** stream) {
208   if (!crypto_stream_->encryption_established()) {
209     DLOG(DFATAL) << "Encryption not established.";
210     return ERR_CONNECTION_CLOSED;
211   }
212
213   if (goaway_received()) {
214     DVLOG(1) << "Going away.";
215     return ERR_CONNECTION_CLOSED;
216   }
217
218   if (!connection()->connected()) {
219     DVLOG(1) << "Already closed.";
220     return ERR_CONNECTION_CLOSED;
221   }
222
223   if (GetNumOpenStreams() < get_max_open_streams()) {
224     *stream = CreateOutgoingReliableStreamImpl();
225     return OK;
226   }
227
228   stream_requests_.push_back(request);
229   return ERR_IO_PENDING;
230 }
231
232 void QuicClientSession::CancelRequest(StreamRequest* request) {
233   // Remove |request| from the queue while preserving the order of the
234   // other elements.
235   StreamRequestQueue::iterator it =
236       std::find(stream_requests_.begin(), stream_requests_.end(), request);
237   if (it != stream_requests_.end()) {
238     it = stream_requests_.erase(it);
239   }
240 }
241
242 QuicReliableClientStream* QuicClientSession::CreateOutgoingDataStream() {
243   if (!crypto_stream_->encryption_established()) {
244     DVLOG(1) << "Encryption not active so no outgoing stream created.";
245     return NULL;
246   }
247   if (GetNumOpenStreams() >= get_max_open_streams()) {
248     DVLOG(1) << "Failed to create a new outgoing stream. "
249                << "Already " << GetNumOpenStreams() << " open.";
250     return NULL;
251   }
252   if (goaway_received()) {
253     DVLOG(1) << "Failed to create a new outgoing stream. "
254                << "Already received goaway.";
255     return NULL;
256   }
257
258   return CreateOutgoingReliableStreamImpl();
259 }
260
261 QuicReliableClientStream*
262 QuicClientSession::CreateOutgoingReliableStreamImpl() {
263   DCHECK(connection()->connected());
264   QuicReliableClientStream* stream =
265       new QuicReliableClientStream(GetNextStreamId(), this, net_log_);
266   ActivateStream(stream);
267   ++num_total_streams_;
268   UMA_HISTOGRAM_COUNTS("Net.QuicSession.NumOpenStreams", GetNumOpenStreams());
269   return stream;
270 }
271
272 QuicCryptoClientStream* QuicClientSession::GetCryptoStream() {
273   return crypto_stream_.get();
274 };
275
276 bool QuicClientSession::GetSSLInfo(SSLInfo* ssl_info) {
277   DCHECK(crypto_stream_.get());
278   return crypto_stream_->GetSSLInfo(ssl_info);
279 }
280
281 int QuicClientSession::CryptoConnect(bool require_confirmation,
282                                      const CompletionCallback& callback) {
283   require_confirmation_ = require_confirmation;
284   RecordHandshakeState(STATE_STARTED);
285   if (!crypto_stream_->CryptoConnect()) {
286     // TODO(wtc): change crypto_stream_.CryptoConnect() to return a
287     // QuicErrorCode and map it to a net error code.
288     return ERR_CONNECTION_FAILED;
289   }
290
291   bool can_notify = require_confirmation_ ?
292       IsCryptoHandshakeConfirmed() : IsEncryptionEstablished();
293   if (can_notify) {
294     return OK;
295   }
296
297   callback_ = callback;
298   return ERR_IO_PENDING;
299 }
300
301 int QuicClientSession::GetNumSentClientHellos() const {
302   return crypto_stream_->num_sent_client_hellos();
303 }
304
305 bool QuicClientSession::CanPool(const std::string& hostname) const {
306   // TODO(rch): When QUIC supports channel ID or client certificates, this
307   // logic will need to be revised.
308   DCHECK(connection()->connected());
309   SSLInfo ssl_info;
310   bool unused = false;
311   DCHECK(crypto_stream_);
312   if (!crypto_stream_->GetSSLInfo(&ssl_info) || !ssl_info.cert) {
313     // We can always pool with insecure QUIC sessions.
314     return true;
315   }
316   // Only pool secure QUIC sessions if the cert matches the new hostname.
317   return ssl_info.cert->VerifyNameMatch(hostname, &unused);
318 }
319
320 QuicDataStream* QuicClientSession::CreateIncomingDataStream(
321     QuicStreamId id) {
322   DLOG(ERROR) << "Server push not supported";
323   return NULL;
324 }
325
326 void QuicClientSession::CloseStream(QuicStreamId stream_id) {
327   QuicSession::CloseStream(stream_id);
328   OnClosedStream();
329 }
330
331 void QuicClientSession::SendRstStream(QuicStreamId id,
332                                       QuicRstStreamErrorCode error,
333                                       QuicStreamOffset bytes_written) {
334   QuicSession::SendRstStream(id, error, bytes_written);
335   OnClosedStream();
336 }
337
338 void QuicClientSession::OnClosedStream() {
339   if (GetNumOpenStreams() < get_max_open_streams() &&
340       !stream_requests_.empty() &&
341       crypto_stream_->encryption_established() &&
342       !goaway_received() &&
343       connection()->connected()) {
344     StreamRequest* request = stream_requests_.front();
345     stream_requests_.pop_front();
346     request->OnRequestCompleteSuccess(CreateOutgoingReliableStreamImpl());
347   }
348
349   if (GetNumOpenStreams() == 0) {
350     stream_factory_->OnIdleSession(this);
351   }
352 }
353
354 void QuicClientSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) {
355   if (!callback_.is_null() &&
356       (!require_confirmation_ || event == HANDSHAKE_CONFIRMED)) {
357     // TODO(rtenneti): Currently for all CryptoHandshakeEvent events, callback_
358     // could be called because there are no error events in CryptoHandshakeEvent
359     // enum. If error events are added to CryptoHandshakeEvent, then the
360     // following code needs to changed.
361     base::ResetAndReturn(&callback_).Run(OK);
362   }
363   if (event == HANDSHAKE_CONFIRMED) {
364     ObserverSet::iterator it = observers_.begin();
365     while (it != observers_.end()) {
366       Observer* observer = *it;
367       ++it;
368       observer->OnCryptoHandshakeConfirmed();
369     }
370   }
371   QuicSession::OnCryptoHandshakeEvent(event);
372 }
373
374 void QuicClientSession::OnCryptoHandshakeMessageSent(
375     const CryptoHandshakeMessage& message) {
376   logger_.OnCryptoHandshakeMessageSent(message);
377 }
378
379 void QuicClientSession::OnCryptoHandshakeMessageReceived(
380     const CryptoHandshakeMessage& message) {
381   logger_.OnCryptoHandshakeMessageReceived(message);
382 }
383
384 void QuicClientSession::OnConnectionClosed(QuicErrorCode error,
385                                            bool from_peer) {
386   DCHECK(!connection()->connected());
387   logger_.OnConnectionClosed(error, from_peer);
388   if (from_peer) {
389     UMA_HISTOGRAM_SPARSE_SLOWLY(
390         "Net.QuicSession.ConnectionCloseErrorCodeServer", error);
391   } else {
392     UMA_HISTOGRAM_SPARSE_SLOWLY(
393         "Net.QuicSession.ConnectionCloseErrorCodeClient", error);
394   }
395
396   if (error == QUIC_CONNECTION_TIMED_OUT) {
397     UMA_HISTOGRAM_COUNTS(
398         "Net.QuicSession.ConnectionClose.NumOpenStreams.TimedOut",
399         GetNumOpenStreams());
400     if (!IsCryptoHandshakeConfirmed()) {
401       // If there have been any streams created, they were 0-RTT speculative
402       // requests that have not be serviced.
403       UMA_HISTOGRAM_COUNTS(
404           "Net.QuicSession.ConnectionClose.NumTotalStreams.HandshakeTimedOut",
405           num_total_streams_);
406     }
407   }
408
409   UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.QuicVersion",
410                               connection()->version());
411   NotifyFactoryOfSessionGoingAway();
412   if (!callback_.is_null()) {
413     base::ResetAndReturn(&callback_).Run(ERR_QUIC_PROTOCOL_ERROR);
414   }
415   socket_->Close();
416   QuicSession::OnConnectionClosed(error, from_peer);
417   DCHECK(streams()->empty());
418   CloseAllStreams(ERR_UNEXPECTED);
419   CloseAllObservers(ERR_UNEXPECTED);
420   NotifyFactoryOfSessionClosedLater();
421 }
422
423 void QuicClientSession::OnSuccessfulVersionNegotiation(
424     const QuicVersion& version) {
425   logger_.OnSuccessfulVersionNegotiation(version);
426   QuicSession::OnSuccessfulVersionNegotiation(version);
427 }
428
429 void QuicClientSession::StartReading() {
430   if (read_pending_) {
431     return;
432   }
433   read_pending_ = true;
434   int rv = socket_->Read(read_buffer_.get(),
435                          read_buffer_->size(),
436                          base::Bind(&QuicClientSession::OnReadComplete,
437                                     weak_factory_.GetWeakPtr()));
438   if (rv == ERR_IO_PENDING) {
439     num_packets_read_ = 0;
440     return;
441   }
442
443   if (++num_packets_read_ > 32) {
444     num_packets_read_ = 0;
445     // Data was read, process it.
446     // Schedule the work through the message loop to avoid recursive
447     // callbacks.
448     base::MessageLoop::current()->PostTask(
449         FROM_HERE,
450         base::Bind(&QuicClientSession::OnReadComplete,
451                    weak_factory_.GetWeakPtr(), rv));
452   } else {
453     OnReadComplete(rv);
454   }
455 }
456
457 void QuicClientSession::CloseSessionOnError(int error) {
458   UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.CloseSessionOnError", -error);
459   CloseSessionOnErrorInner(error, QUIC_INTERNAL_ERROR);
460   NotifyFactoryOfSessionClosed();
461 }
462
463 void QuicClientSession::CloseSessionOnErrorInner(int net_error,
464                                                  QuicErrorCode quic_error) {
465   if (!callback_.is_null()) {
466     base::ResetAndReturn(&callback_).Run(net_error);
467   }
468   CloseAllStreams(net_error);
469   CloseAllObservers(net_error);
470   net_log_.AddEvent(
471       NetLog::TYPE_QUIC_SESSION_CLOSE_ON_ERROR,
472       NetLog::IntegerCallback("net_error", net_error));
473
474   connection()->CloseConnection(quic_error, false);
475   DCHECK(!connection()->connected());
476 }
477
478 void QuicClientSession::CloseAllStreams(int net_error) {
479   while (!streams()->empty()) {
480     ReliableQuicStream* stream = streams()->begin()->second;
481     QuicStreamId id = stream->id();
482     static_cast<QuicReliableClientStream*>(stream)->OnError(net_error);
483     CloseStream(id);
484   }
485 }
486
487 void QuicClientSession::CloseAllObservers(int net_error) {
488   while (!observers_.empty()) {
489     Observer* observer = *observers_.begin();
490     observers_.erase(observer);
491     observer->OnSessionClosed(net_error);
492   }
493 }
494
495 base::Value* QuicClientSession::GetInfoAsValue(
496     const std::set<HostPortProxyPair>& aliases) const {
497   base::DictionaryValue* dict = new base::DictionaryValue();
498   // TODO(rch): remove "host_port_pair" when Chrome 34 is stable.
499   dict->SetString("host_port_pair", aliases.begin()->first.ToString());
500   dict->SetString("version", QuicVersionToString(connection()->version()));
501   dict->SetInteger("open_streams", GetNumOpenStreams());
502   dict->SetInteger("total_streams", num_total_streams_);
503   dict->SetString("peer_address", peer_address().ToString());
504   dict->SetString("guid", base::Uint64ToString(guid()));
505   dict->SetBoolean("connected", connection()->connected());
506
507   base::ListValue* alias_list = new base::ListValue();
508   for (std::set<HostPortProxyPair>::const_iterator it = aliases.begin();
509        it != aliases.end(); it++) {
510     alias_list->Append(new base::StringValue(it->first.ToString()));
511   }
512   dict->Set("aliases", alias_list);
513
514   return dict;
515 }
516
517 base::WeakPtr<QuicClientSession> QuicClientSession::GetWeakPtr() {
518   return weak_factory_.GetWeakPtr();
519 }
520
521 void QuicClientSession::OnReadComplete(int result) {
522   read_pending_ = false;
523   if (result == 0)
524     result = ERR_CONNECTION_CLOSED;
525
526   if (result < 0) {
527     DVLOG(1) << "Closing session on read error: " << result;
528     UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.ReadError", -result);
529     NotifyFactoryOfSessionGoingAway();
530     CloseSessionOnErrorInner(result, QUIC_PACKET_READ_ERROR);
531     NotifyFactoryOfSessionClosedLater();
532     return;
533   }
534
535   scoped_refptr<IOBufferWithSize> buffer(read_buffer_);
536   read_buffer_ = new IOBufferWithSize(kMaxPacketSize);
537   QuicEncryptedPacket packet(buffer->data(), result);
538   IPEndPoint local_address;
539   IPEndPoint peer_address;
540   socket_->GetLocalAddress(&local_address);
541   socket_->GetPeerAddress(&peer_address);
542   // ProcessUdpPacket might result in |this| being deleted, so we
543   // use a weak pointer to be safe.
544   connection()->ProcessUdpPacket(local_address, peer_address, packet);
545   if (!connection()->connected()) {
546     NotifyFactoryOfSessionClosedLater();
547     return;
548   }
549   StartReading();
550 }
551
552 void QuicClientSession::NotifyFactoryOfSessionGoingAway() {
553   if (stream_factory_)
554     stream_factory_->OnSessionGoingAway(this);
555 }
556
557 void QuicClientSession::NotifyFactoryOfSessionClosedLater() {
558   DCHECK_EQ(0u, GetNumOpenStreams());
559   DCHECK(!connection()->connected());
560   base::MessageLoop::current()->PostTask(
561       FROM_HERE,
562       base::Bind(&QuicClientSession::NotifyFactoryOfSessionClosed,
563                  weak_factory_.GetWeakPtr()));
564 }
565
566 void QuicClientSession::NotifyFactoryOfSessionClosed() {
567   DCHECK_EQ(0u, GetNumOpenStreams());
568   // Will delete |this|.
569   if (stream_factory_)
570     stream_factory_->OnSessionClosed(this);
571 }
572
573 }  // namespace net