| 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/threading/thread_task_runner_handle.h" | |
| 11 #include "mojo/edk/embedder/embedder.h" | |
| 12 #include "mojo/edk/system/node_controller.h" | |
| 13 #include "mojo/edk/system/ports/name.h" | |
| 14 | |
| 15 namespace mojo { | |
| 16 namespace edk { | |
| 17 | |
| 18 namespace { | |
| 19 | |
| 20 struct BootstrapData { | |
| 21 // The node name of the sender. | |
| 22 ports::NodeName node_name; | |
| 23 | |
| 24 // The port name of the sender's local bootstrap port. | |
| 25 ports::PortName port_name; | |
| 26 }; | |
| 27 | |
| 28 } // namespace | |
| 29 | |
| 30 // static | |
| 31 void RemoteMessagePipeBootstrap::Create( | |
| 32 NodeController* node_controller, | |
| 33 ScopedPlatformHandle platform_handle, | |
| 34 const ports::PortRef& port) { | |
| 35 CHECK(node_controller); | |
| 36 CHECK(node_controller->io_task_runner()); | |
| 37 if (node_controller->io_task_runner()->RunsTasksOnCurrentThread()) { | |
| 38 // Owns itself. | |
| 39 new RemoteMessagePipeBootstrap( | |
| 40 node_controller, std::move(platform_handle), port); | |
| 41 } else { | |
| 42 node_controller->io_task_runner()->PostTask( | |
| 43 FROM_HERE, | |
| 44 base::Bind(&RemoteMessagePipeBootstrap::Create, | |
| 45 base::Unretained(node_controller), | |
| 46 base::Passed(&platform_handle), port)); | |
| 47 } | |
| 48 } | |
| 49 | |
| 50 RemoteMessagePipeBootstrap::~RemoteMessagePipeBootstrap() { | |
| 51 DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); | |
| 52 base::MessageLoop::current()->RemoveDestructionObserver(this); | |
| 53 if (channel_) | |
| 54 channel_->ShutDown(); | |
| 55 } | |
| 56 | |
| 57 RemoteMessagePipeBootstrap::RemoteMessagePipeBootstrap( | |
| 58 NodeController* node_controller, | |
| 59 ScopedPlatformHandle platform_handle, | |
| 60 const ports::PortRef& port) | |
| 61 : node_controller_(node_controller), | |
| 62 local_port_(port), | |
| 63 io_task_runner_(base::ThreadTaskRunnerHandle::Get()), | |
| 64 channel_(Channel::Create(this, std::move(platform_handle), | |
| 65 io_task_runner_)) { | |
| 66 base::MessageLoop::current()->AddDestructionObserver(this); | |
| 67 channel_->Start(); | |
| 68 | |
| 69 Channel::MessagePtr message(new Channel::Message(sizeof(BootstrapData), 0)); | |
| 70 BootstrapData* data = static_cast<BootstrapData*>(message->mutable_payload()); | |
| 71 data->node_name = node_controller_->name(); | |
| 72 data->port_name = local_port_.name(); | |
| 73 channel_->Write(std::move(message)); | |
| 74 } | |
| 75 | |
| 76 void RemoteMessagePipeBootstrap::ShutDown() { | |
| 77 DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); | |
| 78 | |
| 79 if (shutting_down_) | |
| 80 return; | |
| 81 | |
| 82 shutting_down_ = true; | |
| 83 | |
| 84 // Shut down asynchronously so ShutDown() can be called from within | |
| 85 // OnChannelMessage and OnChannelError. | |
| 86 io_task_runner_->PostTask( | |
| 87 FROM_HERE, | |
| 88 base::Bind(&RemoteMessagePipeBootstrap::ShutDownNow, | |
| 89 base::Unretained(this))); | |
| 90 } | |
| 91 | |
| 92 void RemoteMessagePipeBootstrap::WillDestroyCurrentMessageLoop() { | |
| 93 DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); | |
| 94 ShutDownNow(); | |
| 95 } | |
| 96 | |
| 97 void RemoteMessagePipeBootstrap::OnChannelMessage( | |
| 98 const void* payload, | |
| 99 size_t payload_size, | |
| 100 ScopedPlatformHandleVectorPtr handles) { | |
| 101 DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); | |
| 102 DCHECK(!handles || !handles->size()); | |
| 103 | |
| 104 const BootstrapData* data = static_cast<const BootstrapData*>(payload); | |
| 105 if (peer_info_received_) { | |
| 106 // This should only be a confirmation from the other end, which tells us | |
| 107 // it's now safe to shut down. | |
| 108 if (payload_size != 0) | |
| 109 DLOG(ERROR) << "Unexpected message received in message pipe bootstrap."; | |
| 110 ShutDown(); | |
| 111 return; | |
| 112 } | |
| 113 | |
| 114 if (payload_size != sizeof(BootstrapData)) { | |
| 115 DLOG(ERROR) << "Invalid bootstrap payload."; | |
| 116 ShutDown(); | |
| 117 return; | |
| 118 } | |
| 119 | |
| 120 peer_info_received_ = true; | |
| 121 | |
| 122 // We need to choose one side to initiate the port merge. It doesn't matter | |
| 123 // who does it as long as they don't both try. Simple solution: pick the one | |
| 124 // with the "smaller" port name. | |
| 125 if (local_port_.name() < data->port_name) { | |
| 126 node_controller_->node()->MergePorts(local_port_, data->node_name, | |
| 127 data->port_name); | |
| 128 } | |
| 129 | |
| 130 // Send another ping to the other end to trigger shutdown. This may race with | |
| 131 // the other end sending its own ping, but it doesn't matter. Whoever wins | |
| 132 // will cause the other end to tear down, and the ensuing channel error will | |
| 133 // in turn clean up the remaining end. | |
| 134 | |
| 135 Channel::MessagePtr message(new Channel::Message(0, 0)); | |
| 136 channel_->Write(std::move(message)); | |
| 137 } | |
| 138 | |
| 139 void RemoteMessagePipeBootstrap::OnChannelError() { | |
| 140 DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); | |
| 141 ShutDown(); | |
| 142 } | |
| 143 | |
| 144 void RemoteMessagePipeBootstrap::ShutDownNow() { | |
| 145 delete this; | |
| 146 } | |
| 147 | |
| 148 } // namespace edk | |
| 149 } // namespace mojo | |
| OLD | NEW |