OLD | NEW |
(Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "mojo/edk/system/remote_message_pipe_bootstrap.h" |
| 6 |
| 7 #include "base/bind.h" |
| 8 #include "base/bind_helpers.h" |
| 9 #include "base/macros.h" |
| 10 #include "base/thread_task_runner_handle.h" |
| 11 #include "mojo/edk/embedder/embedder.h" |
| 12 #include "mojo/edk/system/node_controller.h" |
| 13 |
| 14 namespace mojo { |
| 15 namespace edk { |
| 16 |
| 17 namespace { |
| 18 |
| 19 const size_t kMaxTokenSize = 256; |
| 20 |
| 21 class ParentBootstrap : public RemoteMessagePipeBootstrap { |
| 22 public: |
| 23 static void Create(NodeController* node_controller, |
| 24 ScopedPlatformHandle platform_handle, |
| 25 const std::string& token) { |
| 26 // Owns itself. |
| 27 new ParentBootstrap(node_controller, std::move(platform_handle), token); |
| 28 } |
| 29 |
| 30 private: |
| 31 ParentBootstrap(NodeController* node_controller, |
| 32 ScopedPlatformHandle platform_handle, |
| 33 const std::string& token) |
| 34 : RemoteMessagePipeBootstrap(std::move(platform_handle)), |
| 35 node_controller_(node_controller), |
| 36 token_(token) { |
| 37 DCHECK_LE(token_.size(), kMaxTokenSize); |
| 38 Channel::MessagePtr message(new Channel::Message(token_.size(), 0)); |
| 39 memcpy(message->mutable_payload(), token_.data(), token_.size()); |
| 40 channel_->Write(std::move(message)); |
| 41 } |
| 42 |
| 43 ~ParentBootstrap() override {} |
| 44 |
| 45 void OnTokenReceived(const std::string& token) override { |
| 46 // It's possible for two different endpoints in the same parent process to |
| 47 // initiate parent bootstrap on the same platform channel without being |
| 48 // aware of the other. |
| 49 // |
| 50 // This will successfully connect the two endpoints as long as at least one |
| 51 // of the ParentBootstrap instances receives the other's token. It's OK that |
| 52 // they race. NodeController will silently ignore any missed reservations. |
| 53 node_controller_->ConnectReservedPorts(token_, token); |
| 54 ShutDown(); |
| 55 } |
| 56 |
| 57 NodeController* node_controller_; |
| 58 const std::string token_; |
| 59 |
| 60 DISALLOW_COPY_AND_ASSIGN(ParentBootstrap); |
| 61 }; |
| 62 |
| 63 class ChildBootstrap : public RemoteMessagePipeBootstrap { |
| 64 public: |
| 65 static void Create(NodeController* node_controller, |
| 66 ScopedPlatformHandle platform_handle, |
| 67 const ports::PortRef& port, |
| 68 const base::Closure& callback) { |
| 69 // Owns itself. |
| 70 new ChildBootstrap( |
| 71 node_controller, std::move(platform_handle), port, callback); |
| 72 } |
| 73 |
| 74 private: |
| 75 ChildBootstrap(NodeController* node_controller, |
| 76 ScopedPlatformHandle platform_handle, |
| 77 const ports::PortRef& port, |
| 78 const base::Closure& callback) |
| 79 : RemoteMessagePipeBootstrap(std::move(platform_handle)), |
| 80 node_controller_(node_controller), |
| 81 port_(port), |
| 82 callback_(callback) { |
| 83 } |
| 84 |
| 85 ~ChildBootstrap() override {} |
| 86 |
| 87 void OnTokenReceived(const std::string& token) override { |
| 88 CHECK(!callback_.is_null()); |
| 89 base::Closure callback = callback_; |
| 90 callback_.Reset(); |
| 91 |
| 92 node_controller_->ConnectToParentPort(port_, token, callback); |
| 93 ShutDown(); |
| 94 } |
| 95 |
| 96 NodeController* const node_controller_; |
| 97 const ports::PortRef port_; |
| 98 base::Closure callback_; |
| 99 |
| 100 DISALLOW_COPY_AND_ASSIGN(ChildBootstrap); |
| 101 }; |
| 102 |
| 103 } // namespace |
| 104 |
| 105 // static |
| 106 void RemoteMessagePipeBootstrap::CreateForParent( |
| 107 NodeController* node_controller, |
| 108 ScopedPlatformHandle platform_handle, |
| 109 const std::string& token) { |
| 110 node_controller->io_task_runner()->PostTask( |
| 111 FROM_HERE, |
| 112 base::Bind(&ParentBootstrap::Create, base::Unretained(node_controller), |
| 113 base::Passed(&platform_handle), token)); |
| 114 } |
| 115 |
| 116 // static |
| 117 void RemoteMessagePipeBootstrap::CreateForChild( |
| 118 NodeController* node_controller, |
| 119 ScopedPlatformHandle platform_handle, |
| 120 const ports::PortRef& port, |
| 121 const base::Closure& callback) { |
| 122 node_controller->io_task_runner()->PostTask( |
| 123 FROM_HERE, |
| 124 base::Bind(&ChildBootstrap::Create, base::Unretained(node_controller), |
| 125 base::Passed(&platform_handle), port, callback)); |
| 126 } |
| 127 |
| 128 RemoteMessagePipeBootstrap::~RemoteMessagePipeBootstrap() { |
| 129 DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); |
| 130 base::MessageLoop::current()->RemoveDestructionObserver(this); |
| 131 if (channel_) |
| 132 channel_->ShutDown(); |
| 133 } |
| 134 |
| 135 RemoteMessagePipeBootstrap::RemoteMessagePipeBootstrap( |
| 136 ScopedPlatformHandle platform_handle) |
| 137 : io_task_runner_(base::ThreadTaskRunnerHandle::Get()), |
| 138 channel_(Channel::Create(this, std::move(platform_handle), |
| 139 io_task_runner_)) { |
| 140 base::MessageLoop::current()->AddDestructionObserver(this); |
| 141 channel_->Start(); |
| 142 } |
| 143 |
| 144 void RemoteMessagePipeBootstrap::ShutDown() { |
| 145 DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); |
| 146 |
| 147 if (shutting_down_) |
| 148 return; |
| 149 |
| 150 shutting_down_ = true; |
| 151 |
| 152 // Shut down asynchronously so implementations are free to call it whenever. |
| 153 io_task_runner_->PostTask( |
| 154 FROM_HERE, |
| 155 base::Bind(&RemoteMessagePipeBootstrap::ShutDownNow, |
| 156 base::Unretained(this))); |
| 157 } |
| 158 |
| 159 void RemoteMessagePipeBootstrap::WillDestroyCurrentMessageLoop() { |
| 160 DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); |
| 161 ShutDownNow(); |
| 162 } |
| 163 |
| 164 void RemoteMessagePipeBootstrap::OnChannelMessage( |
| 165 const void* payload, |
| 166 size_t payload_size, |
| 167 ScopedPlatformHandleVectorPtr handles) { |
| 168 DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); |
| 169 DCHECK(!handles || !handles->size()); |
| 170 if (payload_size > kMaxTokenSize) { |
| 171 DLOG(ERROR) << "Invalid token payload. Dropping message pipe bootstrap."; |
| 172 ShutDown(); |
| 173 return; |
| 174 } |
| 175 |
| 176 OnTokenReceived(std::string(static_cast<const char*>(payload), payload_size)); |
| 177 } |
| 178 |
| 179 void RemoteMessagePipeBootstrap::OnChannelError() { |
| 180 DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); |
| 181 ShutDown(); |
| 182 } |
| 183 |
| 184 void RemoteMessagePipeBootstrap::ShutDownNow() { |
| 185 delete this; |
| 186 } |
| 187 |
| 188 } // namespace edk |
| 189 } // namespace mojo |
OLD | NEW |