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_stream_factory.h" 19 #include "net/ssl/ssl_info.h" 20 #include "net/udp/datagram_client_socket.h" 21 22 namespace net { 23 24 namespace { 25 26 // Note: these values must be kept in sync with the corresponding values in: 27 // tools/metrics/histograms/histograms.xml 28 enum HandshakeState { 29 STATE_STARTED = 0, 30 STATE_ENCRYPTION_ESTABLISHED = 1, 31 STATE_HANDSHAKE_CONFIRMED = 2, 32 STATE_FAILED = 3, 33 NUM_HANDSHAKE_STATES = 4 34 }; 35 36 void RecordHandshakeState(HandshakeState state) { 37 UMA_HISTOGRAM_ENUMERATION("Net.QuicHandshakeState", state, 38 NUM_HANDSHAKE_STATES); 39 } 40 41 } // namespace 42 43 QuicClientSession::StreamRequest::StreamRequest() : stream_(NULL) {} 44 45 QuicClientSession::StreamRequest::~StreamRequest() { 46 CancelRequest(); 47 } 48 49 int QuicClientSession::StreamRequest::StartRequest( 50 const base::WeakPtr<QuicClientSession> session, 51 QuicReliableClientStream** stream, 52 const CompletionCallback& callback) { 53 session_ = session; 54 stream_ = stream; 55 int rv = session_->TryCreateStream(this, stream_); 56 if (rv == ERR_IO_PENDING) { 57 callback_ = callback; 58 } 59 60 return rv; 61 } 62 63 void QuicClientSession::StreamRequest::CancelRequest() { 64 if (session_) 65 session_->CancelRequest(this); 66 session_.reset(); 67 callback_.Reset(); 68 } 69 70 void QuicClientSession::StreamRequest::OnRequestCompleteSuccess( 71 QuicReliableClientStream* stream) { 72 session_.reset(); 73 *stream_ = stream; 74 ResetAndReturn(&callback_).Run(OK); 75 } 76 77 void QuicClientSession::StreamRequest::OnRequestCompleteFailure(int rv) { 78 session_.reset(); 79 ResetAndReturn(&callback_).Run(rv); 80 } 81 82 QuicClientSession::QuicClientSession( 83 QuicConnection* connection, 84 DatagramClientSocket* socket, 85 QuicStreamFactory* stream_factory, 86 QuicCryptoClientStreamFactory* crypto_client_stream_factory, 87 const string& server_hostname, 88 const QuicConfig& config, 89 QuicCryptoClientConfig* crypto_config, 90 NetLog* net_log) 91 : QuicSession(connection, config, false), 92 weak_factory_(this), 93 stream_factory_(stream_factory), 94 socket_(socket), 95 read_buffer_(new IOBufferWithSize(kMaxPacketSize)), 96 read_pending_(false), 97 num_total_streams_(0), 98 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_QUIC_SESSION)), 99 logger_(net_log_) { 100 crypto_stream_.reset( 101 crypto_client_stream_factory ? 102 crypto_client_stream_factory->CreateQuicCryptoClientStream( 103 server_hostname, this, crypto_config) : 104 new QuicCryptoClientStream(server_hostname, this, crypto_config)); 105 106 connection->set_debug_visitor(&logger_); 107 // TODO(rch): pass in full host port proxy pair 108 net_log_.BeginEvent( 109 NetLog::TYPE_QUIC_SESSION, 110 NetLog::StringCallback("host", &server_hostname)); 111 } 112 113 QuicClientSession::~QuicClientSession() { 114 connection()->set_debug_visitor(NULL); 115 net_log_.EndEvent(NetLog::TYPE_QUIC_SESSION); 116 117 while (!stream_requests_.empty()) { 118 StreamRequest* request = stream_requests_.front(); 119 stream_requests_.pop_front(); 120 request->OnRequestCompleteFailure(ERR_ABORTED); 121 } 122 123 if (IsEncryptionEstablished()) 124 RecordHandshakeState(STATE_ENCRYPTION_ESTABLISHED); 125 if (IsCryptoHandshakeConfirmed()) 126 RecordHandshakeState(STATE_HANDSHAKE_CONFIRMED); 127 else 128 RecordHandshakeState(STATE_FAILED); 129 130 UMA_HISTOGRAM_COUNTS("Net.QuicNumSentClientHellos", 131 crypto_stream_->num_sent_client_hellos()); 132 if (IsCryptoHandshakeConfirmed()) { 133 UMA_HISTOGRAM_COUNTS("Net.QuicNumSentClientHellosCryptoHandshakeConfirmed", 134 crypto_stream_->num_sent_client_hellos()); 135 } 136 } 137 138 int QuicClientSession::TryCreateStream(StreamRequest* request, 139 QuicReliableClientStream** stream) { 140 if (!crypto_stream_->encryption_established()) { 141 DLOG(DFATAL) << "Encryption not established."; 142 return ERR_CONNECTION_CLOSED; 143 } 144 145 if (goaway_received()) { 146 DLOG(INFO) << "Going away."; 147 return ERR_CONNECTION_CLOSED; 148 } 149 150 if (!connection()->connected()) { 151 DLOG(INFO) << "Already closed."; 152 return ERR_CONNECTION_CLOSED; 153 } 154 155 if (GetNumOpenStreams() < get_max_open_streams()) { 156 *stream = CreateOutgoingReliableStreamImpl(); 157 return OK; 158 } 159 160 stream_requests_.push_back(request); 161 return ERR_IO_PENDING; 162 } 163 164 void QuicClientSession::CancelRequest(StreamRequest* request) { 165 // Remove |request| from the queue while preserving the order of the 166 // other elements. 167 StreamRequestQueue::iterator it = 168 std::find(stream_requests_.begin(), stream_requests_.end(), request); 169 if (it != stream_requests_.end()) { 170 it = stream_requests_.erase(it); 171 } 172 } 173 174 QuicReliableClientStream* QuicClientSession::CreateOutgoingReliableStream() { 175 if (!crypto_stream_->encryption_established()) { 176 DLOG(INFO) << "Encryption not active so no outgoing stream created."; 177 return NULL; 178 } 179 if (GetNumOpenStreams() >= get_max_open_streams()) { 180 DLOG(INFO) << "Failed to create a new outgoing stream. " 181 << "Already " << GetNumOpenStreams() << " open."; 182 return NULL; 183 } 184 if (goaway_received()) { 185 DLOG(INFO) << "Failed to create a new outgoing stream. " 186 << "Already received goaway."; 187 return NULL; 188 } 189 190 return CreateOutgoingReliableStreamImpl(); 191 } 192 193 QuicReliableClientStream* 194 QuicClientSession::CreateOutgoingReliableStreamImpl() { 195 DCHECK(connection()->connected()); 196 QuicReliableClientStream* stream = 197 new QuicReliableClientStream(GetNextStreamId(), this, net_log_); 198 ActivateStream(stream); 199 ++num_total_streams_; 200 return stream; 201 } 202 203 QuicCryptoClientStream* QuicClientSession::GetCryptoStream() { 204 return crypto_stream_.get(); 205 }; 206 207 bool QuicClientSession::GetSSLInfo(SSLInfo* ssl_info) { 208 DCHECK(crypto_stream_.get()); 209 return crypto_stream_->GetSSLInfo(ssl_info); 210 } 211 212 int QuicClientSession::CryptoConnect(const CompletionCallback& callback) { 213 RecordHandshakeState(STATE_STARTED); 214 if (!crypto_stream_->CryptoConnect()) { 215 // TODO(wtc): change crypto_stream_.CryptoConnect() to return a 216 // QuicErrorCode and map it to a net error code. 217 return ERR_CONNECTION_FAILED; 218 } 219 220 if (IsEncryptionEstablished()) { 221 return OK; 222 } 223 224 callback_ = callback; 225 return ERR_IO_PENDING; 226 } 227 228 ReliableQuicStream* QuicClientSession::CreateIncomingReliableStream( 229 QuicStreamId id) { 230 DLOG(ERROR) << "Server push not supported"; 231 return NULL; 232 } 233 234 void QuicClientSession::CloseStream(QuicStreamId stream_id) { 235 QuicSession::CloseStream(stream_id); 236 237 if (GetNumOpenStreams() < get_max_open_streams() && 238 !stream_requests_.empty() && 239 crypto_stream_->encryption_established() && 240 !goaway_received() && 241 connection()->connected()) { 242 StreamRequest* request = stream_requests_.front(); 243 stream_requests_.pop_front(); 244 request->OnRequestCompleteSuccess(CreateOutgoingReliableStreamImpl()); 245 } 246 247 if (GetNumOpenStreams() == 0) { 248 stream_factory_->OnIdleSession(this); 249 } 250 } 251 252 void QuicClientSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) { 253 if (!callback_.is_null()) { 254 // TODO(rtenneti): Currently for all CryptoHandshakeEvent events, callback_ 255 // could be called because there are no error events in CryptoHandshakeEvent 256 // enum. If error events are added to CryptoHandshakeEvent, then the 257 // following code needs to changed. 258 base::ResetAndReturn(&callback_).Run(OK); 259 } 260 QuicSession::OnCryptoHandshakeEvent(event); 261 } 262 263 void QuicClientSession::ConnectionClose(QuicErrorCode error, bool from_peer) { 264 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.ConnectionCloseErrorCode", 265 error); 266 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.QuicVersion", 267 connection()->version()); 268 if (!callback_.is_null()) { 269 base::ResetAndReturn(&callback_).Run(ERR_QUIC_PROTOCOL_ERROR); 270 } 271 QuicSession::ConnectionClose(error, from_peer); 272 NotifyFactoryOfSessionCloseLater(); 273 } 274 275 void QuicClientSession::StartReading() { 276 if (read_pending_) { 277 return; 278 } 279 read_pending_ = true; 280 int rv = socket_->Read(read_buffer_.get(), 281 read_buffer_->size(), 282 base::Bind(&QuicClientSession::OnReadComplete, 283 weak_factory_.GetWeakPtr())); 284 if (rv == ERR_IO_PENDING) { 285 return; 286 } 287 288 // Data was read, process it. 289 // Schedule the work through the message loop to avoid recursive 290 // callbacks. 291 base::MessageLoop::current()->PostTask( 292 FROM_HERE, 293 base::Bind(&QuicClientSession::OnReadComplete, 294 weak_factory_.GetWeakPtr(), rv)); 295 } 296 297 void QuicClientSession::CloseSessionOnError(int error) { 298 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.CloseSessionOnError", -error); 299 CloseSessionOnErrorInner(error); 300 NotifyFactoryOfSessionClose(); 301 } 302 303 void QuicClientSession::CloseSessionOnErrorInner(int error) { 304 if (!callback_.is_null()) { 305 base::ResetAndReturn(&callback_).Run(error); 306 } 307 while (!streams()->empty()) { 308 ReliableQuicStream* stream = streams()->begin()->second; 309 QuicStreamId id = stream->id(); 310 static_cast<QuicReliableClientStream*>(stream)->OnError(error); 311 CloseStream(id); 312 } 313 net_log_.AddEvent( 314 NetLog::TYPE_QUIC_SESSION_CLOSE_ON_ERROR, 315 NetLog::IntegerCallback("net_error", error)); 316 317 connection()->CloseConnection(QUIC_INTERNAL_ERROR, false); 318 DCHECK(!connection()->connected()); 319 } 320 321 base::Value* QuicClientSession::GetInfoAsValue(const HostPortPair& pair) const { 322 base::DictionaryValue* dict = new base::DictionaryValue(); 323 dict->SetString("host_port_pair", pair.ToString()); 324 dict->SetString("version", QuicVersionToString(connection()->version())); 325 dict->SetInteger("open_streams", GetNumOpenStreams()); 326 dict->SetInteger("total_streams", num_total_streams_); 327 dict->SetString("peer_address", peer_address().ToString()); 328 dict->SetString("guid", base::Uint64ToString(guid())); 329 return dict; 330 } 331 332 base::WeakPtr<QuicClientSession> QuicClientSession::GetWeakPtr() { 333 return weak_factory_.GetWeakPtr(); 334 } 335 336 void QuicClientSession::OnReadComplete(int result) { 337 read_pending_ = false; 338 if (result == 0) 339 result = ERR_CONNECTION_CLOSED; 340 341 if (result < 0) { 342 DLOG(INFO) << "Closing session on read error: " << result; 343 CloseSessionOnErrorInner(result); 344 NotifyFactoryOfSessionCloseLater(); 345 return; 346 } 347 348 scoped_refptr<IOBufferWithSize> buffer(read_buffer_); 349 read_buffer_ = new IOBufferWithSize(kMaxPacketSize); 350 QuicEncryptedPacket packet(buffer->data(), result); 351 IPEndPoint local_address; 352 IPEndPoint peer_address; 353 socket_->GetLocalAddress(&local_address); 354 socket_->GetPeerAddress(&peer_address); 355 // ProcessUdpPacket might result in |this| being deleted, so we 356 // use a weak pointer to be safe. 357 connection()->ProcessUdpPacket(local_address, peer_address, packet); 358 if (!connection()->connected()) { 359 stream_factory_->OnSessionClose(this); 360 return; 361 } 362 StartReading(); 363 } 364 365 void QuicClientSession::NotifyFactoryOfSessionCloseLater() { 366 DCHECK_EQ(0u, GetNumOpenStreams()); 367 DCHECK(!connection()->connected()); 368 base::MessageLoop::current()->PostTask( 369 FROM_HERE, 370 base::Bind(&QuicClientSession::NotifyFactoryOfSessionClose, 371 weak_factory_.GetWeakPtr())); 372 } 373 374 void QuicClientSession::NotifyFactoryOfSessionClose() { 375 DCHECK_EQ(0u, GetNumOpenStreams()); 376 DCHECK(stream_factory_); 377 // Will delete |this|. 378 stream_factory_->OnSessionClose(this); 379 } 380 381 } // namespace net 382