| // Copyright 2025 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "remoting/host/register_support_host_request_base.h" |
| |
| #include "base/logging.h" |
| #include "base/strings/stringize_macros.h" |
| #include "remoting/base/environment_details.h" |
| #include "remoting/base/errors.h" |
| #include "remoting/base/http_status.h" |
| #include "remoting/signaling/signaling_address.h" |
| |
| namespace remoting { |
| |
| namespace { |
| |
| ErrorCode MapError(HttpStatus::Code status_code) { |
| switch (status_code) { |
| case HttpStatus::Code::OK: |
| return ErrorCode::OK; |
| case HttpStatus::Code::DEADLINE_EXCEEDED: |
| return ErrorCode::OPERATION_TIMEOUT; |
| case HttpStatus::Code::INVALID_ARGUMENT: |
| return ErrorCode::INVALID_ARGUMENT; |
| case HttpStatus::Code::PERMISSION_DENIED: |
| return ErrorCode::UNAUTHORIZED_ACCOUNT; |
| case HttpStatus::Code::UNAUTHENTICATED: |
| return ErrorCode::AUTHENTICATION_FAILED; |
| case HttpStatus::Code::FAILED_PRECONDITION: |
| return ErrorCode::INVALID_STATE; |
| case HttpStatus::Code::NETWORK_ERROR: |
| return ErrorCode::NETWORK_FAILURE; |
| default: |
| return ErrorCode::UNKNOWN_ERROR; |
| } |
| } |
| |
| } // namespace |
| |
| RegisterSupportHostRequestBase::RegisterSupportHostRequestBase() = default; |
| |
| RegisterSupportHostRequestBase::~RegisterSupportHostRequestBase() { |
| if (signal_strategy_) { |
| signal_strategy_->RemoveListener(this); |
| } |
| } |
| |
| void RegisterSupportHostRequestBase::StartRequest( |
| SignalStrategy* signal_strategy, |
| std::unique_ptr<net::ClientCertStore> client_cert_store, |
| scoped_refptr<RsaKeyPair> key_pair, |
| const std::string& authorized_helper, |
| std::optional<ChromeOsEnterpriseParams> params, |
| RegisterCallback callback) { |
| DCHECK_EQ(State::NOT_STARTED, state_); |
| DCHECK(signal_strategy); |
| DCHECK(key_pair); |
| DCHECK(callback); |
| signal_strategy_ = signal_strategy; |
| key_pair_ = key_pair; |
| callback_ = std::move(callback); |
| enterprise_params_ = std::move(params); |
| authorized_helper_ = authorized_helper; |
| |
| signal_strategy_->AddListener(this); |
| Initialize(std::move(client_cert_store)); |
| } |
| |
| void RegisterSupportHostRequestBase::OnSignalingStateChanged( |
| SignalStrategy::State state) { |
| switch (state) { |
| case SignalStrategy::State::CONNECTED: |
| RegisterHostInternal(); |
| break; |
| case SignalStrategy::State::DISCONNECTED: |
| RunCallback({}, {}, ErrorCode::SIGNALING_ERROR); |
| break; |
| default: |
| // Do nothing. |
| break; |
| } |
| } |
| |
| void RegisterSupportHostRequestBase::RegisterHostInternal() { |
| DCHECK_EQ(SignalStrategy::CONNECTED, signal_strategy_->GetState()); |
| if (state_ != State::NOT_STARTED) { |
| return; |
| } |
| state_ = State::REGISTERING; |
| internal::RemoteSupportHostStruct host; |
| host.public_key = key_pair_->GetPublicKey(); |
| host.version = STRINGIZE(VERSION); |
| host.authorized_helper_email = authorized_helper_; |
| host.operating_system_info.name = GetOperatingSystemName(); |
| host.operating_system_info.version = GetOperatingSystemVersion(); |
| const SignalingAddress& local_address = signal_strategy_->GetLocalAddress(); |
| if (!local_address.GetFtlInfo(&host.tachyon_account_info.account_id, |
| &host.tachyon_account_info.registration_id)) { |
| LOG(ERROR) << "Local signaling ID is not a valid Tachyon ID: " |
| << local_address.id(); |
| } |
| |
| RegisterHost( |
| host, enterprise_params_, |
| base::BindOnce(&RegisterSupportHostRequestBase::OnRegisterHostResult, |
| base::Unretained(this))); |
| } |
| |
| void RegisterSupportHostRequestBase::OnRegisterHostResult( |
| const HttpStatus& status, |
| std::string_view support_id, |
| base::TimeDelta support_id_lifetime) { |
| if (!status.ok()) { |
| state_ = State::NOT_STARTED; |
| LOG(ERROR) << "Failed to register support host: " << status.error_message() |
| << " (" << static_cast<int>(status.error_code()) << ")"; |
| RunCallback({}, {}, MapError(status.error_code())); |
| return; |
| } |
| state_ = State::REGISTERED; |
| RunCallback(support_id, support_id_lifetime, ErrorCode::OK); |
| } |
| |
| void RegisterSupportHostRequestBase::RunCallback(std::string_view support_id, |
| base::TimeDelta lifetime, |
| ErrorCode error_code) { |
| if (!callback_) { |
| // Callback has already been run, so just return. |
| return; |
| } |
| |
| // Cleanup state before calling the callback. |
| CancelPendingRequests(); |
| signal_strategy_->RemoveListener(this); |
| signal_strategy_ = nullptr; |
| |
| // TODO: yuweih - make callback take std::string_view. |
| std::move(callback_).Run(std::string(support_id), lifetime, error_code); |
| } |
| |
| } // namespace remoting |