blob: 0c1bd22bc82e687227f1728c51450e6f0b88d471 [file] [log] [blame]
// Copyright 2021 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 "remoting/host/mojo_ipc/mojo_ipc_server.h"
#include <memory>
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/notreached.h"
#include "base/task/thread_pool.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "remoting/host/mojo_ipc/mojo_server_endpoint_connector.h"
#if defined(OS_WIN)
#include "base/strings/stringprintf.h"
#include "base/win/win_util.h"
#endif // defined(OS_WIN)
namespace remoting {
namespace {
// Delay to throttle resending invitations when there is a recurring error.
// TODO(yuweih): Implement backoff.
base::TimeDelta kResentInvitationOnErrorDelay = base::Seconds(5);
mojo::PlatformChannelServerEndpoint CreateServerEndpointOnIoSequence(
const mojo::NamedPlatformChannel::ServerName& server_name) {
mojo::NamedPlatformChannel::Options options;
options.server_name = server_name;
#if defined(OS_WIN)
options.enforce_uniqueness = false;
// Create a named pipe owned by the current user (the LocalService account
// (SID: S-1-5-19) when running in the network process) which is available to
// all authenticated users.
// presubmit: allow wstring
std::wstring user_sid;
if (!base::win::GetUserSidString(&user_sid)) {
LOG(ERROR) << "Failed to get user SID string.";
return mojo::PlatformChannelServerEndpoint();
}
options.security_descriptor = base::StringPrintf(
L"O:%lsG:%lsD:(A;;GA;;;AU)", user_sid.c_str(), user_sid.c_str());
#endif // defined(OS_WIN)
mojo::NamedPlatformChannel channel(options);
return channel.TakeServerEndpoint();
}
} // namespace
MojoIpcServerBase::MojoIpcServerBase(
const mojo::NamedPlatformChannel::ServerName& server_name)
: server_name_(server_name),
endpoint_connector_(MojoServerEndpointConnector::Create(this)) {
io_sequence_ =
base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()});
}
MojoIpcServerBase::~MojoIpcServerBase() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
void MojoIpcServerBase::StartServer() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (server_started_) {
return;
}
server_started_ = true;
SendInvitation();
}
void MojoIpcServerBase::StopServer() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!server_started_) {
return;
}
server_started_ = false;
UntrackAllMessagePipes();
active_connections_.clear();
}
void MojoIpcServerBase::Close(mojo::ReceiverId id) {
UntrackMessagePipe(id);
auto it = active_connections_.find(id);
if (it != active_connections_.end()) {
active_connections_.erase(it);
}
}
void MojoIpcServerBase::SendInvitation() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
io_sequence_->PostTaskAndReplyWithResult(
FROM_HERE,
base::BindOnce(&CreateServerEndpointOnIoSequence, server_name_),
base::BindOnce(&MojoIpcServerBase::OnServerEndpointCreated,
weak_factory_.GetWeakPtr()));
}
void MojoIpcServerBase::OnIpcDisconnected() {
if (disconnect_handler_) {
disconnect_handler_.Run();
}
Close(current_receiver());
}
void MojoIpcServerBase::OnServerEndpointCreated(
mojo::PlatformChannelServerEndpoint endpoint) {
if (on_invitation_sent_callback_for_testing_) {
on_invitation_sent_callback_for_testing_.Run();
}
if (!endpoint.is_valid()) {
OnServerEndpointConnectionFailed();
return;
}
endpoint_connector_->Connect(std::move(endpoint));
}
void MojoIpcServerBase::OnServerEndpointConnected(
std::unique_ptr<mojo::IsolatedConnection> connection,
mojo::ScopedMessagePipeHandle message_pipe,
base::ProcessId peer_pid) {
auto receiver_id = TrackMessagePipe(std::move(message_pipe), peer_pid);
active_connections_[receiver_id] = std::move(connection);
SendInvitation();
}
void MojoIpcServerBase::OnServerEndpointConnectionFailed() {
resent_invitation_on_error_timer_.Start(FROM_HERE,
kResentInvitationOnErrorDelay, this,
&MojoIpcServerBase::SendInvitation);
}
} // namespace remoting