| // Copyright (c) 2015 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "net/tools/quic/quic_client_base.h" |
| |
| #include "net/quic/crypto/quic_random.h" |
| #include "net/quic/quic_server_id.h" |
| |
| namespace net { |
| |
| QuicClientBase::QuicClientBase(const QuicServerId& server_id, |
| const QuicVersionVector& supported_versions, |
| const QuicConfig& config, |
| QuicConnectionHelperInterface* helper, |
| QuicAlarmFactory* alarm_factory, |
| ProofVerifier* proof_verifier) |
| : server_id_(server_id), |
| config_(config), |
| crypto_config_(proof_verifier), |
| helper_(helper), |
| alarm_factory_(alarm_factory), |
| supported_versions_(supported_versions), |
| initial_max_packet_length_(0), |
| num_stateless_rejects_received_(0), |
| num_sent_client_hellos_(0), |
| connection_error_(QUIC_NO_ERROR), |
| connected_or_attempting_connect_(false) {} |
| |
| QuicClientBase::~QuicClientBase() {} |
| |
| bool QuicClientBase::Initialize() { |
| num_sent_client_hellos_ = 0; |
| num_stateless_rejects_received_ = 0; |
| connection_error_ = QUIC_NO_ERROR; |
| connected_or_attempting_connect_ = false; |
| return true; |
| } |
| |
| ProofVerifier* QuicClientBase::proof_verifier() const { |
| return crypto_config_.proof_verifier(); |
| } |
| |
| QuicClientSession* QuicClientBase::CreateQuicClientSession( |
| QuicConnection* connection) { |
| session_.reset(new QuicClientSession(config_, connection, server_id_, |
| &crypto_config_, &push_promise_index_)); |
| if (initial_max_packet_length_ != 0) { |
| session()->connection()->SetMaxPacketLength(initial_max_packet_length_); |
| } |
| return session_.get(); |
| } |
| |
| bool QuicClientBase::EncryptionBeingEstablished() { |
| return !session_->IsEncryptionEstablished() && |
| session_->connection()->connected(); |
| } |
| |
| QuicSpdyClientStream* QuicClientBase::CreateReliableClientStream() { |
| if (!connected()) { |
| return nullptr; |
| } |
| |
| return session_->CreateOutgoingDynamicStream(kDefaultPriority); |
| } |
| |
| void QuicClientBase::WaitForStreamToClose(QuicStreamId id) { |
| DCHECK(connected()); |
| |
| while (connected() && !session_->IsClosedStream(id)) { |
| WaitForEvents(); |
| } |
| } |
| |
| void QuicClientBase::WaitForCryptoHandshakeConfirmed() { |
| DCHECK(connected()); |
| |
| while (connected() && !session_->IsCryptoHandshakeConfirmed()) { |
| WaitForEvents(); |
| } |
| } |
| |
| bool QuicClientBase::connected() const { |
| return session_.get() && session_->connection() && |
| session_->connection()->connected(); |
| } |
| |
| bool QuicClientBase::goaway_received() const { |
| return session_ != nullptr && session_->goaway_received(); |
| } |
| |
| int QuicClientBase::GetNumSentClientHellos() { |
| // If we are not actively attempting to connect, the session object |
| // corresponds to the previous connection and should not be used. |
| const int current_session_hellos = !connected_or_attempting_connect_ |
| ? 0 |
| : session_->GetNumSentClientHellos(); |
| return num_sent_client_hellos_ + current_session_hellos; |
| } |
| |
| void QuicClientBase::UpdateStats() { |
| num_sent_client_hellos_ += session()->GetNumSentClientHellos(); |
| if (session()->error() == QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) { |
| ++num_stateless_rejects_received_; |
| } |
| } |
| |
| int QuicClientBase::GetNumReceivedServerConfigUpdates() { |
| // If we are not actively attempting to connect, the session object |
| // corresponds to the previous connection and should not be used. |
| // We do not need to take stateless rejects into account, since we |
| // don't expect any scup messages to be sent during a |
| // statelessly-rejected connection. |
| return !connected_or_attempting_connect_ |
| ? 0 |
| : session_->GetNumReceivedServerConfigUpdates(); |
| } |
| |
| QuicErrorCode QuicClientBase::connection_error() const { |
| // Return the high-level error if there was one. Otherwise, return the |
| // connection error from the last session. |
| if (connection_error_ != QUIC_NO_ERROR) { |
| return connection_error_; |
| } |
| if (session_.get() == nullptr) { |
| return QUIC_NO_ERROR; |
| } |
| return session_->error(); |
| } |
| |
| QuicConnectionId QuicClientBase::GetNextConnectionId() { |
| QuicConnectionId server_designated_id = GetNextServerDesignatedConnectionId(); |
| return server_designated_id ? server_designated_id |
| : GenerateNewConnectionId(); |
| } |
| |
| QuicConnectionId QuicClientBase::GetNextServerDesignatedConnectionId() { |
| QuicCryptoClientConfig::CachedState* cached = |
| crypto_config_.LookupOrCreate(server_id_); |
| // If the cached state indicates that we should use a server-designated |
| // connection ID, then return that connection ID. |
| CHECK(cached != nullptr) << "QuicClientCryptoConfig::LookupOrCreate returned " |
| << "unexpected nullptr."; |
| return cached->has_server_designated_connection_id() |
| ? cached->GetNextServerDesignatedConnectionId() |
| : 0; |
| } |
| |
| QuicConnectionId QuicClientBase::GenerateNewConnectionId() { |
| return QuicRandom::GetInstance()->RandUint64(); |
| } |
| |
| } // namespace net |