Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(200)

Side by Side Diff: mojo/edk/system/node_channel.cc

Issue 1585493002: [mojo] Ports EDK (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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/node_channel.h"
6
7 #include <cstring>
8 #include <limits>
9 #include <sstream>
10
11 #include "base/logging.h"
12 #include "mojo/edk/system/channel.h"
13
14 namespace mojo {
15 namespace edk {
16
17 namespace {
18
19 template <typename T>
20 T Align(T t) {
21 const auto k = kChannelMessageAlignment;
22 return t + (k - (t % k)) % k;
23 }
24
25 enum class MessageType : uint32_t {
26 ACCEPT_CHILD,
27 ACCEPT_PARENT,
28 PORTS_MESSAGE,
29 REQUEST_PORT_CONNECTION,
30 CONNECT_TO_PORT,
31 REQUEST_INTRODUCTION,
32 INTRODUCE,
33 #if defined(OS_WIN)
34 RELAY_PORTS_MESSAGE,
35 #endif
36 };
37
38 struct Header {
39 MessageType type;
40 uint32_t padding;
41 };
42
43 static_assert(sizeof(Header) % kChannelMessageAlignment == 0,
44 "Invalid header size.");
45
46 struct AcceptChildData {
47 ports::NodeName parent_name;
48 ports::NodeName token;
49 };
50
51 struct AcceptParentData {
52 ports::NodeName token;
53 ports::NodeName child_name;
54 };
55
56 // This is followed by arbitrary payload data which is interpreted as a token
57 // string for port location.
58 struct RequestPortConnectionData {
59 ports::PortName connector_port_name;
60 };
61
62 struct ConnectToPortData {
63 ports::PortName connector_port_name;
64 ports::PortName connectee_port_name;
65 };
66
67 // Used for both REQUEST_INTRODUCTION and INTRODUCE.
68 //
69 // For INTRODUCE the message must also include a platform handle the recipient
70 // can use to communicate with the named node. If said handle is omitted, the
71 // peer cannot be introduced.
72 struct IntroductionData {
73 ports::NodeName name;
74 };
75
76 #if defined(OS_WIN)
77 // This struct is followed by the full payload of a message to be relayed.
78 struct RelayPortsMessageData {
79 ports::NodeName destination;
80 };
81 #endif
82
83 template <typename DataType>
84 Channel::MessagePtr CreateMessage(MessageType type,
85 size_t payload_size,
86 size_t num_handles,
87 DataType** out_data) {
88 Channel::MessagePtr message(
89 new Channel::Message(sizeof(Header) + payload_size, num_handles));
90 Header* header = reinterpret_cast<Header*>(message->mutable_payload());
91 header->type = type;
92 header->padding = 0;
93 *out_data = reinterpret_cast<DataType*>(&header[1]);
94 return message;
95 };
96
97 template <typename DataType>
98 void GetMessagePayload(const void* bytes, DataType** out_data) {
99 *out_data = reinterpret_cast<const DataType*>(
100 static_cast<const char*>(bytes) + sizeof(Header));
101 }
102
103 } // namespace
104
105 // static
106 scoped_refptr<NodeChannel> NodeChannel::Create(
107 Delegate* delegate,
108 ScopedPlatformHandle platform_handle,
109 scoped_refptr<base::TaskRunner> io_task_runner) {
110 return new NodeChannel(delegate, std::move(platform_handle), io_task_runner);
111 }
112
113 // static
114 Channel::MessagePtr NodeChannel::CreatePortsMessage(size_t payload_size,
115 void** payload,
116 size_t num_handles) {
117 return CreateMessage(MessageType::PORTS_MESSAGE, payload_size, num_handles,
118 payload);
119 }
120
121 // static
122 void NodeChannel::GetPortsMessageData(Channel::Message* message,
123 void** data,
124 size_t* num_data_bytes) {
125 *data = reinterpret_cast<Header*>(message->mutable_payload()) + 1;
126 *num_data_bytes = message->payload_size() - sizeof(Header);
127 }
128
129 void NodeChannel::Start() {
130 base::AutoLock lock(channel_lock_);
131 DCHECK(channel_);
132 channel_->Start();
133 }
134
135 void NodeChannel::ShutDown() {
136 base::AutoLock lock(channel_lock_);
137 if (channel_) {
138 channel_->ShutDown();
139 channel_ = nullptr;
140 }
141 }
142
143 void NodeChannel::SetRemoteProcessHandle(base::ProcessHandle process_handle) {
144 #if defined(OS_WIN)
145 DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
146 base::AutoLock lock(remote_process_handle_lock_);
147 remote_process_handle_ = process_handle;
148 #endif
149 }
150
151 void NodeChannel::SetRemoteNodeName(const ports::NodeName& name) {
152 DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
153 remote_node_name_ = name;
154 }
155
156 void NodeChannel::AcceptChild(const ports::NodeName& parent_name,
157 const ports::NodeName& token) {
158 AcceptChildData* data;
159 Channel::MessagePtr message = CreateMessage(
160 MessageType::ACCEPT_CHILD, sizeof(AcceptChildData), 0, &data);
161 data->parent_name = parent_name;
162 data->token = token;
163 WriteChannelMessage(std::move(message));
164 }
165
166 void NodeChannel::AcceptParent(const ports::NodeName& token,
167 const ports::NodeName& child_name) {
168 AcceptParentData* data;
169 Channel::MessagePtr message = CreateMessage(
170 MessageType::ACCEPT_PARENT, sizeof(AcceptParentData), 0, &data);
171 data->token = token;
172 data->child_name = child_name;
173 WriteChannelMessage(std::move(message));
174 }
175
176 void NodeChannel::PortsMessage(Channel::MessagePtr message) {
177 WriteChannelMessage(std::move(message));
178 }
179
180 void NodeChannel::RequestPortConnection(
181 const ports::PortName& connector_port_name,
182 const std::string& token) {
183 RequestPortConnectionData* data;
184 Channel::MessagePtr message = CreateMessage(
185 MessageType::REQUEST_PORT_CONNECTION,
186 sizeof(RequestPortConnectionData) + token.size(), 0, &data);
187 data->connector_port_name = connector_port_name;
188 memcpy(data + 1, token.data(), token.size());
189 WriteChannelMessage(std::move(message));
190 }
191
192 void NodeChannel::ConnectToPort(const ports::PortName& connector_port_name,
193 const ports::PortName& connectee_port_name) {
194 ConnectToPortData* data;
195 Channel::MessagePtr message = CreateMessage(
196 MessageType::CONNECT_TO_PORT, sizeof(ConnectToPortData), 0, &data);
197 data->connector_port_name = connector_port_name;
198 data->connectee_port_name = connectee_port_name;
199 WriteChannelMessage(std::move(message));
200 }
201
202 void NodeChannel::RequestIntroduction(const ports::NodeName& name) {
203 IntroductionData* data;
204 Channel::MessagePtr message = CreateMessage(
205 MessageType::REQUEST_INTRODUCTION, sizeof(IntroductionData), 0, &data);
206 data->name = name;
207 WriteChannelMessage(std::move(message));
208 }
209
210 void NodeChannel::Introduce(const ports::NodeName& name,
211 ScopedPlatformHandle handle) {
212 IntroductionData* data;
213 ScopedPlatformHandleVectorPtr handles;
214 if (handle.is_valid()) {
215 handles.reset(new PlatformHandleVector(1));
216 handles->at(0) = handle.release();
217 }
218 Channel::MessagePtr message = CreateMessage(
219 MessageType::INTRODUCE, sizeof(IntroductionData), handles ? 1 : 0, &data);
220 message->SetHandles(std::move(handles));
221 data->name = name;
222 WriteChannelMessage(std::move(message));
223 }
224
225 #if defined(OS_WIN)
226 void NodeChannel::RelayPortsMessage(const ports::NodeName& destination,
227 Channel::MessagePtr message) {
228 DCHECK(message->has_handles());
229
230 // Note that this is only used on Windows, and on Windows all platform
231 // handles are included in the message data. We blindly copy all the data
232 // here and the relay node (the parent) will duplicate handles as needed.
233 size_t num_bytes = sizeof(RelayPortsMessageData) + message->data_num_bytes();
234 RelayPortsMessageData* data;
235 Channel::MessagePtr relay_message = CreateMessage(
236 MessageType::RELAY_PORTS_MESSAGE, num_bytes, 0, &data);
237 data->destination = destination;
238 memcpy(data + 1, message->data(), message->data_num_bytes());
239
240 // When the handles are duplicated in the parent, the source handles will
241 // be closed. If the parent never receives this message then these handles
242 // will leak, but that means something else has probably broken and the
243 // sending process won't likely be around much longer.
244 ScopedPlatformHandleVectorPtr handles = message->TakeHandles();
245 handles->clear();
246
247 WriteChannelMessage(std::move(relay_message));
248 }
249 #endif
250
251 NodeChannel::NodeChannel(Delegate* delegate,
252 ScopedPlatformHandle platform_handle,
253 scoped_refptr<base::TaskRunner> io_task_runner)
254 : delegate_(delegate),
255 io_task_runner_(io_task_runner),
256 channel_(
257 Channel::Create(this, std::move(platform_handle), io_task_runner_)) {
258 }
259
260 NodeChannel::~NodeChannel() {
261 ShutDown();
262 }
263
264 void NodeChannel::OnChannelMessage(const void* payload,
265 size_t payload_size,
266 ScopedPlatformHandleVectorPtr handles) {
267 DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
268
269 const Header* header = static_cast<const Header*>(payload);
270 switch (header->type) {
271 case MessageType::ACCEPT_CHILD: {
272 const AcceptChildData* data;
273 GetMessagePayload(payload, &data);
274 delegate_->OnAcceptChild(remote_node_name_, data->parent_name,
275 data->token);
276 break;
277 }
278
279 case MessageType::ACCEPT_PARENT: {
280 const AcceptParentData* data;
281 GetMessagePayload(payload, &data);
282 delegate_->OnAcceptParent(remote_node_name_, data->token,
283 data->child_name);
284 break;
285 }
286
287 case MessageType::PORTS_MESSAGE: {
288 size_t num_handles = handles ? handles->size() : 0;
289 Channel::MessagePtr message(
290 new Channel::Message(payload_size, num_handles));
291 message->SetHandles(std::move(handles));
292 memcpy(message->mutable_payload(), payload, payload_size);
293 delegate_->OnPortsMessage(std::move(message));
294 break;
295 }
296
297 case MessageType::REQUEST_PORT_CONNECTION: {
298 const RequestPortConnectionData* data;
299 GetMessagePayload(payload, &data);
300
301 const char* token_data = reinterpret_cast<const char*>(data + 1);
302 const size_t token_size = payload_size - sizeof(*data) - sizeof(Header);
303 std::string token(token_data, token_size);
304
305 delegate_->OnRequestPortConnection(remote_node_name_,
306 data->connector_port_name, token);
307 break;
308 }
309
310 case MessageType::CONNECT_TO_PORT: {
311 const ConnectToPortData* data;
312 GetMessagePayload(payload, &data);
313 delegate_->OnConnectToPort(remote_node_name_, data->connector_port_name,
314 data->connectee_port_name);
315 break;
316 }
317
318 case MessageType::REQUEST_INTRODUCTION: {
319 const IntroductionData* data;
320 GetMessagePayload(payload, &data);
321 delegate_->OnRequestIntroduction(remote_node_name_, data->name);
322 break;
323 }
324
325 case MessageType::INTRODUCE: {
326 const IntroductionData* data;
327 GetMessagePayload(payload, &data);
328 ScopedPlatformHandle handle;
329 if (handles && !handles->empty()) {
330 handle = ScopedPlatformHandle(handles->at(0));
331 handles->clear();
332 }
333 delegate_->OnIntroduce(remote_node_name_, data->name, std::move(handle));
334 break;
335 }
336
337 #if defined(OS_WIN)
338 case MessageType::RELAY_PORTS_MESSAGE: {
339 base::ProcessHandle from_process;
340 {
341 base::AutoLock lock(remote_process_handle_lock_);
342 from_process = remote_process_handle_;
343 }
344 const RelayPortsMessageData* data;
345 GetMessagePayload(payload, &data);
346 const void* message_start = data + 1;
347 Channel::MessagePtr message = Channel::Message::Deserialize(
348 message_start, payload_size - sizeof(Header) - sizeof(*data));
349 if (!message) {
350 DLOG(ERROR) << "Dropping invalid relay message.";
351 break;
352 }
353 delegate_->OnRelayPortsMessage(remote_node_name_, from_process,
354 data->destination, std::move(message));
355 break;
356 }
357 #endif
358
359 default:
360 DLOG(ERROR) << "Received unknown message type "
361 << static_cast<uint32_t>(header->type) << " from node "
362 << remote_node_name_;
363 delegate_->OnChannelError(remote_node_name_);
364 break;
365 }
366 }
367
368 void NodeChannel::OnChannelError() {
369 DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
370
371 ShutDown();
372 // |OnChannelError()| may cause |this| to be destroyed, but still need access
373 // to the name name after that destruction. So may a copy of
374 // |remote_node_name_| so it can be used if |this| becomes destroyed.
375 ports::NodeName node_name = remote_node_name_;
376 delegate_->OnChannelError(node_name);
377 }
378
379 void NodeChannel::WriteChannelMessage(Channel::MessagePtr message) {
380 #if defined(OS_WIN)
381 // Map handles to the destination process. Note: only messages from the parent
382 // node should contain handles on Windows. If a child node needs to send
383 // handles, it should do so via RelayPortsMessage, which stashes the handles
384 // in the message in such a way that they go undetected here.
385
386 if (message->has_handles()) {
387 base::ProcessHandle remote_process_handle;
388 {
389 base::AutoLock lock(remote_process_handle_lock_);
390 remote_process_handle = remote_process_handle_;
391 }
392
393 if (remote_process_handle == base::kNullProcessHandle) {
394 DLOG(ERROR) << "Sending a message with handles as a non-parent. "
395 << "This is most likely broken.";
396 } else {
397 for (size_t i = 0; i < message->num_handles(); ++i) {
398 BOOL result = DuplicateHandle(
399 base::GetCurrentProcessHandle(), message->handles()[i].handle,
400 remote_process_handle,
401 reinterpret_cast<HANDLE*>(message->handles() + i), 0, FALSE,
402 DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
403 DCHECK(result);
404 }
405 }
406 }
407 #endif
408
409 base::AutoLock lock(channel_lock_);
410 if (!channel_)
411 DLOG(ERROR) << "Dropping message on closed channel.";
412 else
413 channel_->Write(std::move(message));
414 }
415
416 } // namespace edk
417 } // namespace mojo
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698