| Index: mojo/edk/system/remote_message_pipe_bootstrap.cc
|
| diff --git a/mojo/edk/system/remote_message_pipe_bootstrap.cc b/mojo/edk/system/remote_message_pipe_bootstrap.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..4d46437dd8b403a16f93e963e54c3c851d370481
|
| --- /dev/null
|
| +++ b/mojo/edk/system/remote_message_pipe_bootstrap.cc
|
| @@ -0,0 +1,189 @@
|
| +// Copyright 2016 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 "mojo/edk/system/remote_message_pipe_bootstrap.h"
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/bind_helpers.h"
|
| +#include "base/macros.h"
|
| +#include "base/thread_task_runner_handle.h"
|
| +#include "mojo/edk/embedder/embedder.h"
|
| +#include "mojo/edk/system/node_controller.h"
|
| +
|
| +namespace mojo {
|
| +namespace edk {
|
| +
|
| +namespace {
|
| +
|
| +const size_t kMaxTokenSize = 256;
|
| +
|
| +class ParentBootstrap : public RemoteMessagePipeBootstrap {
|
| + public:
|
| + static void Create(NodeController* node_controller,
|
| + ScopedPlatformHandle platform_handle,
|
| + const std::string& token) {
|
| + // Owns itself.
|
| + new ParentBootstrap(node_controller, std::move(platform_handle), token);
|
| + }
|
| +
|
| + private:
|
| + ParentBootstrap(NodeController* node_controller,
|
| + ScopedPlatformHandle platform_handle,
|
| + const std::string& token)
|
| + : RemoteMessagePipeBootstrap(std::move(platform_handle)),
|
| + node_controller_(node_controller),
|
| + token_(token) {
|
| + DCHECK_LE(token_.size(), kMaxTokenSize);
|
| + Channel::MessagePtr message(new Channel::Message(token_.size(), 0));
|
| + memcpy(message->mutable_payload(), token_.data(), token_.size());
|
| + channel_->Write(std::move(message));
|
| + }
|
| +
|
| + ~ParentBootstrap() override {}
|
| +
|
| + void OnTokenReceived(const std::string& token) override {
|
| + // It's possible for two different endpoints in the same parent process to
|
| + // initiate parent bootstrap on the same platform channel without being
|
| + // aware of the other.
|
| + //
|
| + // This will successfully connect the two endpoints as long as at least one
|
| + // of the ParentBootstrap instances receives the other's token. It's OK that
|
| + // they race. NodeController will silently ignore any missed reservations.
|
| + node_controller_->ConnectReservedPorts(token_, token);
|
| + ShutDown();
|
| + }
|
| +
|
| + NodeController* node_controller_;
|
| + const std::string token_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(ParentBootstrap);
|
| +};
|
| +
|
| +class ChildBootstrap : public RemoteMessagePipeBootstrap {
|
| + public:
|
| + static void Create(NodeController* node_controller,
|
| + ScopedPlatformHandle platform_handle,
|
| + const ports::PortRef& port,
|
| + const base::Closure& callback) {
|
| + // Owns itself.
|
| + new ChildBootstrap(
|
| + node_controller, std::move(platform_handle), port, callback);
|
| + }
|
| +
|
| + private:
|
| + ChildBootstrap(NodeController* node_controller,
|
| + ScopedPlatformHandle platform_handle,
|
| + const ports::PortRef& port,
|
| + const base::Closure& callback)
|
| + : RemoteMessagePipeBootstrap(std::move(platform_handle)),
|
| + node_controller_(node_controller),
|
| + port_(port),
|
| + callback_(callback) {
|
| + }
|
| +
|
| + ~ChildBootstrap() override {}
|
| +
|
| + void OnTokenReceived(const std::string& token) override {
|
| + CHECK(!callback_.is_null());
|
| + base::Closure callback = callback_;
|
| + callback_.Reset();
|
| +
|
| + node_controller_->ConnectToParentPort(port_, token, callback);
|
| + ShutDown();
|
| + }
|
| +
|
| + NodeController* const node_controller_;
|
| + const ports::PortRef port_;
|
| + base::Closure callback_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(ChildBootstrap);
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| +// static
|
| +void RemoteMessagePipeBootstrap::CreateForParent(
|
| + NodeController* node_controller,
|
| + ScopedPlatformHandle platform_handle,
|
| + const std::string& token) {
|
| + node_controller->io_task_runner()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&ParentBootstrap::Create, base::Unretained(node_controller),
|
| + base::Passed(&platform_handle), token));
|
| +}
|
| +
|
| +// static
|
| +void RemoteMessagePipeBootstrap::CreateForChild(
|
| + NodeController* node_controller,
|
| + ScopedPlatformHandle platform_handle,
|
| + const ports::PortRef& port,
|
| + const base::Closure& callback) {
|
| + node_controller->io_task_runner()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&ChildBootstrap::Create, base::Unretained(node_controller),
|
| + base::Passed(&platform_handle), port, callback));
|
| +}
|
| +
|
| +RemoteMessagePipeBootstrap::~RemoteMessagePipeBootstrap() {
|
| + DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
|
| + base::MessageLoop::current()->RemoveDestructionObserver(this);
|
| + if (channel_)
|
| + channel_->ShutDown();
|
| +}
|
| +
|
| +RemoteMessagePipeBootstrap::RemoteMessagePipeBootstrap(
|
| + ScopedPlatformHandle platform_handle)
|
| + : io_task_runner_(base::ThreadTaskRunnerHandle::Get()),
|
| + channel_(Channel::Create(this, std::move(platform_handle),
|
| + io_task_runner_)) {
|
| + base::MessageLoop::current()->AddDestructionObserver(this);
|
| + channel_->Start();
|
| +}
|
| +
|
| +void RemoteMessagePipeBootstrap::ShutDown() {
|
| + DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
|
| +
|
| + if (shutting_down_)
|
| + return;
|
| +
|
| + shutting_down_ = true;
|
| +
|
| + // Shut down asynchronously so implementations are free to call it whenever.
|
| + io_task_runner_->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&RemoteMessagePipeBootstrap::ShutDownNow,
|
| + base::Unretained(this)));
|
| +}
|
| +
|
| +void RemoteMessagePipeBootstrap::WillDestroyCurrentMessageLoop() {
|
| + DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
|
| + ShutDownNow();
|
| +}
|
| +
|
| +void RemoteMessagePipeBootstrap::OnChannelMessage(
|
| + const void* payload,
|
| + size_t payload_size,
|
| + ScopedPlatformHandleVectorPtr handles) {
|
| + DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
|
| + DCHECK(!handles || !handles->size());
|
| + if (payload_size > kMaxTokenSize) {
|
| + DLOG(ERROR) << "Invalid token payload. Dropping message pipe bootstrap.";
|
| + ShutDown();
|
| + return;
|
| + }
|
| +
|
| + OnTokenReceived(std::string(static_cast<const char*>(payload), payload_size));
|
| +}
|
| +
|
| +void RemoteMessagePipeBootstrap::OnChannelError() {
|
| + DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
|
| + ShutDown();
|
| +}
|
| +
|
| +void RemoteMessagePipeBootstrap::ShutDownNow() {
|
| + delete this;
|
| +}
|
| +
|
| +} // namespace edk
|
| +} // namespace mojo
|
|
|