| 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 | 
|  |