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 |