blob: 3141723f88768c8baa0e3293bc735a20d1eb1e0f [file] [log] [blame]
// Copyright 2018 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 "chromeos/services/secure_channel/multiplexed_channel_impl.h"
#include "base/logging.h"
#include "base/no_destructor.h"
#include "base/stl_util.h"
#include "chromeos/components/multidevice/logging/logging.h"
#include "chromeos/services/secure_channel/single_client_message_proxy_impl.h"
namespace chromeos {
namespace secure_channel {
// static
MultiplexedChannelImpl::Factory*
MultiplexedChannelImpl::Factory::test_factory_ = nullptr;
// static
MultiplexedChannelImpl::Factory* MultiplexedChannelImpl::Factory::Get() {
if (test_factory_)
return test_factory_;
static base::NoDestructor<MultiplexedChannelImpl::Factory> factory;
return factory.get();
}
// static
void MultiplexedChannelImpl::Factory::SetFactoryForTesting(
Factory* test_factory) {
test_factory_ = test_factory;
}
MultiplexedChannelImpl::Factory::~Factory() = default;
std::unique_ptr<MultiplexedChannel>
MultiplexedChannelImpl::Factory::BuildInstance(
std::unique_ptr<AuthenticatedChannel> authenticated_channel,
MultiplexedChannel::Delegate* delegate,
ConnectionDetails connection_details,
std::vector<std::unique_ptr<ClientConnectionParameters>>* initial_clients) {
DCHECK(authenticated_channel);
DCHECK(!authenticated_channel->is_disconnected());
DCHECK(delegate);
DCHECK(initial_clients);
DCHECK(!initial_clients->empty());
auto channel = base::WrapUnique(new MultiplexedChannelImpl(
std::move(authenticated_channel), delegate, connection_details));
for (auto& client_connection_parameters : *initial_clients) {
bool success =
channel->AddClientToChannel(std::move(client_connection_parameters));
if (!success) {
PA_LOG(ERROR) << "MultiplexedChannelImpl::Factory::BuildInstance(): "
<< "Failed to add initial client.";
NOTREACHED();
}
}
return channel;
}
MultiplexedChannelImpl::MultiplexedChannelImpl(
std::unique_ptr<AuthenticatedChannel> authenticated_channel,
MultiplexedChannel::Delegate* delegate,
ConnectionDetails connection_details)
: MultiplexedChannel(delegate, connection_details),
authenticated_channel_(std::move(authenticated_channel)) {
authenticated_channel_->AddObserver(this);
}
MultiplexedChannelImpl::~MultiplexedChannelImpl() {
authenticated_channel_->RemoveObserver(this);
}
bool MultiplexedChannelImpl::IsDisconnecting() const {
return is_disconnecting_;
}
bool MultiplexedChannelImpl::IsDisconnected() const {
return is_disconnected_;
}
void MultiplexedChannelImpl::PerformAddClientToChannel(
std::unique_ptr<ClientConnectionParameters> client_connection_parameters) {
DCHECK(client_connection_parameters->IsClientWaitingForResponse());
auto proxy = SingleClientMessageProxyImpl::Factory::Get()->BuildInstance(
this /* delegate */, std::move(client_connection_parameters));
DCHECK(!base::ContainsKey(id_to_proxy_map_, proxy->GetProxyId()));
id_to_proxy_map_[proxy->GetProxyId()] = std::move(proxy);
}
void MultiplexedChannelImpl::OnDisconnected() {
is_disconnecting_ = false;
is_disconnected_ = true;
for (auto& proxy_entry : id_to_proxy_map_)
proxy_entry.second->HandleRemoteDeviceDisconnection();
NotifyDisconnected();
}
void MultiplexedChannelImpl::OnMessageReceived(const std::string& feature,
const std::string& payload) {
for (auto& proxy_entry : id_to_proxy_map_)
proxy_entry.second->HandleReceivedMessage(feature, payload);
}
void MultiplexedChannelImpl::OnSendMessageRequested(
const std::string& message_feaure,
const std::string& message_payload,
base::OnceClosure on_sent_callback) {
authenticated_channel_->SendMessage(message_feaure, message_payload,
std::move(on_sent_callback));
}
void MultiplexedChannelImpl::GetConnectionMetadata(
base::OnceCallback<void(mojom::ConnectionMetadataPtr)> callback) {
authenticated_channel_->GetConnectionMetadata(std::move(callback));
}
void MultiplexedChannelImpl::OnClientDisconnected(
const base::UnguessableToken& proxy_id) {
size_t num_entries_deleted = id_to_proxy_map_.erase(proxy_id);
if (num_entries_deleted != 1u) {
PA_LOG(ERROR) << "MultiplexedChannelImpl::OnClientDisconnected(): Client "
<< "disconnected, but no entry in the map existed.";
NOTREACHED();
}
if (!id_to_proxy_map_.empty())
return;
// If there are no clients remaining, the underlying channel should be
// disconnected.
is_disconnecting_ = true;
authenticated_channel_->Disconnect();
}
} // namespace secure_channel
} // namespace chromeos