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/channel.h"
6
7 #include <stddef.h>
8 #include <string.h>
9
10 #include <algorithm>
11 #include <limits>
12 #include <utility>
13
14 #include "base/macros.h"
15 #include "base/memory/aligned_memory.h"
16 #include "base/process/process_handle.h"
17 #include "mojo/edk/embedder/platform_handle.h"
18
19 #if defined(OS_MACOSX) && !defined(OS_IOS)
20 #include "base/mac/mach_logging.h"
21 #elif defined(OS_WIN)
22 #include "base/win/win_util.h"
23 #endif
24
25 namespace mojo {
26 namespace edk {
27
28 namespace {
29
30 static_assert(
31 IsAlignedForChannelMessage(sizeof(Channel::Message::LegacyHeader)),
32 "Invalid LegacyHeader size.");
33
34 static_assert(IsAlignedForChannelMessage(sizeof(Channel::Message::Header)),
35 "Invalid Header size.");
36
37 static_assert(sizeof(Channel::Message::LegacyHeader) == 8,
38 "LegacyHeader must be 8 bytes on ChromeOS and Android");
39
40 static_assert(offsetof(Channel::Message::LegacyHeader, num_bytes) ==
41 offsetof(Channel::Message::Header, num_bytes),
42 "num_bytes should be at the same offset in both Header structs.");
43 static_assert(offsetof(Channel::Message::LegacyHeader, message_type) ==
44 offsetof(Channel::Message::Header, message_type),
45 "message_type should be at the same offset in both Header "
46 "structs.");
47
48 } // namespace
49
50 const size_t kReadBufferSize = 4096;
51 const size_t kMaxUnusedReadBufferCapacity = 4096;
52 const size_t kMaxChannelMessageSize = 256 * 1024 * 1024;
53 const size_t kMaxAttachedHandles = 128;
54
Message(size_t payload_size,size_t max_handles)55 Channel::Message::Message(size_t payload_size, size_t max_handles)
56 #if defined(MOJO_EDK_LEGACY_PROTOCOL)
57 : Message(payload_size, max_handles, MessageType::NORMAL_LEGACY) {
58 }
59 #else
60 : Message(payload_size, max_handles, MessageType::NORMAL) {
61 }
62 #endif
63
Message(size_t payload_size,size_t max_handles,MessageType message_type)64 Channel::Message::Message(size_t payload_size,
65 size_t max_handles,
66 MessageType message_type)
67 : max_handles_(max_handles) {
68 DCHECK_LE(max_handles_, kMaxAttachedHandles);
69
70 const bool is_legacy_message = (message_type == MessageType::NORMAL_LEGACY);
71 size_t extra_header_size = 0;
72 #if defined(OS_WIN)
73 // On Windows we serialize HANDLEs into the extra header space.
74 extra_header_size = max_handles_ * sizeof(HandleEntry);
75 #elif defined(OS_MACOSX) && !defined(OS_IOS)
76 // On OSX, some of the platform handles may be mach ports, which are
77 // serialised into the message buffer. Since there could be a mix of fds and
78 // mach ports, we store the mach ports as an <index, port> pair (of uint32_t),
79 // so that the original ordering of handles can be re-created.
80 if (max_handles) {
81 extra_header_size =
82 sizeof(MachPortsExtraHeader) + (max_handles * sizeof(MachPortsEntry));
83 }
84 #endif
85 // Pad extra header data to be aliged to |kChannelMessageAlignment| bytes.
86 if (!IsAlignedForChannelMessage(extra_header_size)) {
87 extra_header_size += kChannelMessageAlignment -
88 (extra_header_size % kChannelMessageAlignment);
89 }
90 DCHECK(IsAlignedForChannelMessage(extra_header_size));
91 const size_t header_size =
92 is_legacy_message ? sizeof(LegacyHeader) : sizeof(Header);
93 DCHECK(extra_header_size == 0 || !is_legacy_message);
94
95 size_ = header_size + extra_header_size + payload_size;
96 data_ = static_cast<char*>(base::AlignedAlloc(size_,
97 kChannelMessageAlignment));
98 // Only zero out the header and not the payload. Since the payload is going to
99 // be memcpy'd, zeroing the payload is unnecessary work and a significant
100 // performance issue when dealing with large messages. Any sanitizer errors
101 // complaining about an uninitialized read in the payload area should be
102 // treated as an error and fixed.
103 memset(data_, 0, header_size + extra_header_size);
104
105 DCHECK_LE(size_, std::numeric_limits<uint32_t>::max());
106 legacy_header()->num_bytes = static_cast<uint32_t>(size_);
107
108 DCHECK_LE(header_size + extra_header_size,
109 std::numeric_limits<uint16_t>::max());
110 legacy_header()->message_type = message_type;
111
112 if (is_legacy_message) {
113 legacy_header()->num_handles = static_cast<uint16_t>(max_handles);
114 } else {
115 header()->num_header_bytes =
116 static_cast<uint16_t>(header_size + extra_header_size);
117 }
118
119 if (max_handles_ > 0) {
120 #if defined(OS_WIN)
121 handles_ = reinterpret_cast<HandleEntry*>(mutable_extra_header());
122 // Initialize all handles to invalid values.
123 for (size_t i = 0; i < max_handles_; ++i)
124 handles_[i].handle = base::win::HandleToUint32(INVALID_HANDLE_VALUE);
125 #elif defined(OS_MACOSX) && !defined(OS_IOS)
126 mach_ports_header_ =
127 reinterpret_cast<MachPortsExtraHeader*>(mutable_extra_header());
128 mach_ports_header_->num_ports = 0;
129 // Initialize all handles to invalid values.
130 for (size_t i = 0; i < max_handles_; ++i) {
131 mach_ports_header_->entries[i] =
132 {0, static_cast<uint32_t>(MACH_PORT_NULL)};
133 }
134 #endif
135 }
136 }
137
~Message()138 Channel::Message::~Message() {
139 base::AlignedFree(data_);
140 }
141
142 // static
Deserialize(const void * data,size_t data_num_bytes)143 Channel::MessagePtr Channel::Message::Deserialize(const void* data,
144 size_t data_num_bytes) {
145 if (data_num_bytes < sizeof(LegacyHeader))
146 return nullptr;
147
148 const LegacyHeader* legacy_header =
149 reinterpret_cast<const LegacyHeader*>(data);
150 if (legacy_header->num_bytes != data_num_bytes) {
151 DLOG(ERROR) << "Decoding invalid message: " << legacy_header->num_bytes
152 << " != " << data_num_bytes;
153 return nullptr;
154 }
155
156 const Header* header = nullptr;
157 if (legacy_header->message_type == MessageType::NORMAL)
158 header = reinterpret_cast<const Header*>(data);
159
160 uint32_t extra_header_size = 0;
161 size_t payload_size = 0;
162 const char* payload = nullptr;
163 if (!header) {
164 payload_size = data_num_bytes - sizeof(LegacyHeader);
165 payload = static_cast<const char*>(data) + sizeof(LegacyHeader);
166 } else {
167 if (header->num_bytes < header->num_header_bytes ||
168 header->num_header_bytes < sizeof(Header)) {
169 DLOG(ERROR) << "Decoding invalid message: " << header->num_bytes << " < "
170 << header->num_header_bytes;
171 return nullptr;
172 }
173 extra_header_size = header->num_header_bytes - sizeof(Header);
174 payload_size = data_num_bytes - header->num_header_bytes;
175 payload = static_cast<const char*>(data) + header->num_header_bytes;
176 }
177
178 #if defined(OS_WIN)
179 uint32_t max_handles = extra_header_size / sizeof(HandleEntry);
180 #elif defined(OS_MACOSX) && !defined(OS_IOS)
181 if (extra_header_size > 0 &&
182 extra_header_size < sizeof(MachPortsExtraHeader)) {
183 DLOG(ERROR) << "Decoding invalid message: " << extra_header_size << " < "
184 << sizeof(MachPortsExtraHeader);
185 return nullptr;
186 }
187 uint32_t max_handles =
188 extra_header_size == 0
189 ? 0
190 : (extra_header_size - sizeof(MachPortsExtraHeader)) /
191 sizeof(MachPortsEntry);
192 #else
193 const uint32_t max_handles = 0;
194 #endif // defined(OS_WIN)
195
196 const uint16_t num_handles =
197 header ? header->num_handles : legacy_header->num_handles;
198 if (num_handles > max_handles || max_handles > kMaxAttachedHandles) {
199 DLOG(ERROR) << "Decoding invalid message: " << num_handles << " > "
200 << max_handles;
201 return nullptr;
202 }
203
204 MessagePtr message(
205 new Message(payload_size, max_handles, legacy_header->message_type));
206 DCHECK_EQ(message->data_num_bytes(), data_num_bytes);
207
208 // Copy all payload bytes.
209 if (payload_size)
210 memcpy(message->mutable_payload(), payload, payload_size);
211
212 if (header) {
213 DCHECK_EQ(message->extra_header_size(), extra_header_size);
214 DCHECK_EQ(message->header()->num_header_bytes, header->num_header_bytes);
215
216 if (message->extra_header_size()) {
217 // Copy extra header bytes.
218 memcpy(message->mutable_extra_header(),
219 static_cast<const char*>(data) + sizeof(Header),
220 message->extra_header_size());
221 }
222 message->header()->num_handles = header->num_handles;
223 } else {
224 message->legacy_header()->num_handles = legacy_header->num_handles;
225 }
226
227 #if defined(OS_WIN)
228 ScopedPlatformHandleVectorPtr handles(new PlatformHandleVector(num_handles));
229 for (size_t i = 0; i < num_handles; i++) {
230 (*handles)[i].handle =
231 base::win::Uint32ToHandle(message->handles_[i].handle);
232 }
233 message->SetHandles(std::move(handles));
234 #endif
235
236 return message;
237 }
238
extra_header() const239 const void* Channel::Message::extra_header() const {
240 DCHECK(!is_legacy_message());
241 return data_ + sizeof(Header);
242 }
243
mutable_extra_header()244 void* Channel::Message::mutable_extra_header() {
245 DCHECK(!is_legacy_message());
246 return data_ + sizeof(Header);
247 }
248
extra_header_size() const249 size_t Channel::Message::extra_header_size() const {
250 return header()->num_header_bytes - sizeof(Header);
251 }
252
mutable_payload()253 void* Channel::Message::mutable_payload() {
254 if (is_legacy_message())
255 return static_cast<void*>(legacy_header() + 1);
256 return data_ + header()->num_header_bytes;
257 }
258
payload() const259 const void* Channel::Message::payload() const {
260 if (is_legacy_message())
261 return static_cast<const void*>(legacy_header() + 1);
262 return data_ + header()->num_header_bytes;
263 }
264
payload_size() const265 size_t Channel::Message::payload_size() const {
266 if (is_legacy_message())
267 return legacy_header()->num_bytes - sizeof(LegacyHeader);
268 return size_ - header()->num_header_bytes;
269 }
270
num_handles() const271 size_t Channel::Message::num_handles() const {
272 return is_legacy_message() ? legacy_header()->num_handles
273 : header()->num_handles;
274 }
275
has_handles() const276 bool Channel::Message::has_handles() const {
277 return (is_legacy_message() ? legacy_header()->num_handles
278 : header()->num_handles) > 0;
279 }
280
281 #if defined(OS_MACOSX) && !defined(OS_IOS)
has_mach_ports() const282 bool Channel::Message::has_mach_ports() const {
283 if (!has_handles())
284 return false;
285
286 for (const auto& handle : (*handle_vector_)) {
287 if (handle.type == PlatformHandle::Type::MACH ||
288 handle.type == PlatformHandle::Type::MACH_NAME) {
289 return true;
290 }
291 }
292 return false;
293 }
294 #endif
295
is_legacy_message() const296 bool Channel::Message::is_legacy_message() const {
297 return legacy_header()->message_type == MessageType::NORMAL_LEGACY;
298 }
299
legacy_header() const300 Channel::Message::LegacyHeader* Channel::Message::legacy_header() const {
301 return reinterpret_cast<LegacyHeader*>(data_);
302 }
303
header() const304 Channel::Message::Header* Channel::Message::header() const {
305 DCHECK(!is_legacy_message());
306 return reinterpret_cast<Header*>(data_);
307 }
308
SetHandles(ScopedPlatformHandleVectorPtr new_handles)309 void Channel::Message::SetHandles(ScopedPlatformHandleVectorPtr new_handles) {
310 if (is_legacy_message()) {
311 // Old semantics for ChromeOS and Android
312 if (legacy_header()->num_handles == 0) {
313 CHECK(!new_handles || new_handles->size() == 0);
314 return;
315 }
316 CHECK(new_handles && new_handles->size() == legacy_header()->num_handles);
317 std::swap(handle_vector_, new_handles);
318 return;
319 }
320
321 if (max_handles_ == 0) {
322 CHECK(!new_handles || new_handles->size() == 0);
323 return;
324 }
325
326 CHECK(new_handles && new_handles->size() <= max_handles_);
327 header()->num_handles = static_cast<uint16_t>(new_handles->size());
328 std::swap(handle_vector_, new_handles);
329 #if defined(OS_WIN)
330 memset(handles_, 0, extra_header_size());
331 for (size_t i = 0; i < handle_vector_->size(); i++)
332 handles_[i].handle = base::win::HandleToUint32((*handle_vector_)[i].handle);
333 #endif // defined(OS_WIN)
334
335 #if defined(OS_MACOSX) && !defined(OS_IOS)
336 size_t mach_port_index = 0;
337 if (mach_ports_header_) {
338 for (size_t i = 0; i < max_handles_; ++i) {
339 mach_ports_header_->entries[i] =
340 {0, static_cast<uint32_t>(MACH_PORT_NULL)};
341 }
342 for (size_t i = 0; i < handle_vector_->size(); i++) {
343 if ((*handle_vector_)[i].type == PlatformHandle::Type::MACH ||
344 (*handle_vector_)[i].type == PlatformHandle::Type::MACH_NAME) {
345 mach_port_t port = (*handle_vector_)[i].port;
346 mach_ports_header_->entries[mach_port_index].index = i;
347 mach_ports_header_->entries[mach_port_index].mach_port = port;
348 mach_port_index++;
349 }
350 }
351 mach_ports_header_->num_ports = static_cast<uint16_t>(mach_port_index);
352 }
353 #endif
354 }
355
TakeHandles()356 ScopedPlatformHandleVectorPtr Channel::Message::TakeHandles() {
357 #if defined(OS_MACOSX) && !defined(OS_IOS)
358 if (mach_ports_header_) {
359 for (size_t i = 0; i < max_handles_; ++i) {
360 mach_ports_header_->entries[i] =
361 {0, static_cast<uint32_t>(MACH_PORT_NULL)};
362 }
363 mach_ports_header_->num_ports = 0;
364 }
365 #endif
366 if (is_legacy_message())
367 legacy_header()->num_handles = 0;
368 else
369 header()->num_handles = 0;
370 return std::move(handle_vector_);
371 }
372
TakeHandlesForTransport()373 ScopedPlatformHandleVectorPtr Channel::Message::TakeHandlesForTransport() {
374 #if defined(OS_WIN)
375 // Not necessary on Windows.
376 NOTREACHED();
377 return nullptr;
378 #elif defined(OS_MACOSX) && !defined(OS_IOS)
379 if (handle_vector_) {
380 for (auto it = handle_vector_->begin(); it != handle_vector_->end(); ) {
381 if (it->type == PlatformHandle::Type::MACH ||
382 it->type == PlatformHandle::Type::MACH_NAME) {
383 // For Mach port names, we can can just leak them. They're not real
384 // ports anyways. For real ports, they're leaked because this is a child
385 // process and the remote process will take ownership.
386 it = handle_vector_->erase(it);
387 } else {
388 ++it;
389 }
390 }
391 }
392 return std::move(handle_vector_);
393 #else
394 return std::move(handle_vector_);
395 #endif
396 }
397
398 #if defined(OS_WIN)
399 // static
RewriteHandles(base::ProcessHandle from_process,base::ProcessHandle to_process,PlatformHandleVector * handles)400 bool Channel::Message::RewriteHandles(base::ProcessHandle from_process,
401 base::ProcessHandle to_process,
402 PlatformHandleVector* handles) {
403 bool success = true;
404 for (size_t i = 0; i < handles->size(); ++i) {
405 if (!(*handles)[i].is_valid()) {
406 DLOG(ERROR) << "Refusing to duplicate invalid handle.";
407 continue;
408 }
409 DCHECK_EQ((*handles)[i].owning_process, from_process);
410 BOOL result = DuplicateHandle(
411 from_process, (*handles)[i].handle, to_process,
412 &(*handles)[i].handle, 0, FALSE,
413 DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
414 if (result) {
415 (*handles)[i].owning_process = to_process;
416 } else {
417 success = false;
418
419 // If handle duplication fails, the source handle will already be closed
420 // due to DUPLICATE_CLOSE_SOURCE. Replace the handle in the message with
421 // an invalid handle.
422 (*handles)[i].handle = INVALID_HANDLE_VALUE;
423 (*handles)[i].owning_process = base::GetCurrentProcessHandle();
424 }
425 }
426 return success;
427 }
428 #endif
429
430 // Helper class for managing a Channel's read buffer allocations. This maintains
431 // a single contiguous buffer with the layout:
432 //
433 // [discarded bytes][occupied bytes][unoccupied bytes]
434 //
435 // The Reserve() method ensures that a certain capacity of unoccupied bytes are
436 // available. It does not claim that capacity and only allocates new capacity
437 // when strictly necessary.
438 //
439 // Claim() marks unoccupied bytes as occupied.
440 //
441 // Discard() marks occupied bytes as discarded, signifying that their contents
442 // can be forgotten or overwritten.
443 //
444 // Realign() moves occupied bytes to the front of the buffer so that those
445 // occupied bytes are properly aligned.
446 //
447 // The most common Channel behavior in practice should result in very few
448 // allocations and copies, as memory is claimed and discarded shortly after
449 // being reserved, and future reservations will immediately reuse discarded
450 // memory.
451 class Channel::ReadBuffer {
452 public:
ReadBuffer()453 ReadBuffer() {
454 size_ = kReadBufferSize;
455 data_ = static_cast<char*>(base::AlignedAlloc(size_,
456 kChannelMessageAlignment));
457 }
458
~ReadBuffer()459 ~ReadBuffer() {
460 DCHECK(data_);
461 base::AlignedFree(data_);
462 }
463
occupied_bytes() const464 const char* occupied_bytes() const { return data_ + num_discarded_bytes_; }
465
num_occupied_bytes() const466 size_t num_occupied_bytes() const {
467 return num_occupied_bytes_ - num_discarded_bytes_;
468 }
469
470 // Ensures the ReadBuffer has enough contiguous space allocated to hold
471 // |num_bytes| more bytes; returns the address of the first available byte.
Reserve(size_t num_bytes)472 char* Reserve(size_t num_bytes) {
473 if (num_occupied_bytes_ + num_bytes > size_) {
474 size_ = std::max(size_ * 2, num_occupied_bytes_ + num_bytes);
475 void* new_data = base::AlignedAlloc(size_, kChannelMessageAlignment);
476 memcpy(new_data, data_, num_occupied_bytes_);
477 base::AlignedFree(data_);
478 data_ = static_cast<char*>(new_data);
479 }
480
481 return data_ + num_occupied_bytes_;
482 }
483
484 // Marks the first |num_bytes| unoccupied bytes as occupied.
Claim(size_t num_bytes)485 void Claim(size_t num_bytes) {
486 DCHECK_LE(num_occupied_bytes_ + num_bytes, size_);
487 num_occupied_bytes_ += num_bytes;
488 }
489
490 // Marks the first |num_bytes| occupied bytes as discarded. This may result in
491 // shrinkage of the internal buffer, and it is not safe to assume the result
492 // of a previous Reserve() call is still valid after this.
Discard(size_t num_bytes)493 void Discard(size_t num_bytes) {
494 DCHECK_LE(num_discarded_bytes_ + num_bytes, num_occupied_bytes_);
495 num_discarded_bytes_ += num_bytes;
496
497 if (num_discarded_bytes_ == num_occupied_bytes_) {
498 // We can just reuse the buffer from the beginning in this common case.
499 num_discarded_bytes_ = 0;
500 num_occupied_bytes_ = 0;
501 }
502
503 if (num_discarded_bytes_ > kMaxUnusedReadBufferCapacity) {
504 // In the uncommon case that we have a lot of discarded data at the
505 // front of the buffer, simply move remaining data to a smaller buffer.
506 size_t num_preserved_bytes = num_occupied_bytes_ - num_discarded_bytes_;
507 size_ = std::max(num_preserved_bytes, kReadBufferSize);
508 char* new_data = static_cast<char*>(
509 base::AlignedAlloc(size_, kChannelMessageAlignment));
510 memcpy(new_data, data_ + num_discarded_bytes_, num_preserved_bytes);
511 base::AlignedFree(data_);
512 data_ = new_data;
513 num_discarded_bytes_ = 0;
514 num_occupied_bytes_ = num_preserved_bytes;
515 }
516
517 if (num_occupied_bytes_ == 0 && size_ > kMaxUnusedReadBufferCapacity) {
518 // Opportunistically shrink the read buffer back down to a small size if
519 // it's grown very large. We only do this if there are no remaining
520 // unconsumed bytes in the buffer to avoid copies in most the common
521 // cases.
522 size_ = kMaxUnusedReadBufferCapacity;
523 base::AlignedFree(data_);
524 data_ = static_cast<char*>(
525 base::AlignedAlloc(size_, kChannelMessageAlignment));
526 }
527 }
528
Realign()529 void Realign() {
530 size_t num_bytes = num_occupied_bytes();
531 memmove(data_, occupied_bytes(), num_bytes);
532 num_discarded_bytes_ = 0;
533 num_occupied_bytes_ = num_bytes;
534 }
535
536 private:
537 char* data_ = nullptr;
538
539 // The total size of the allocated buffer.
540 size_t size_ = 0;
541
542 // The number of discarded bytes at the beginning of the allocated buffer.
543 size_t num_discarded_bytes_ = 0;
544
545 // The total number of occupied bytes, including discarded bytes.
546 size_t num_occupied_bytes_ = 0;
547
548 DISALLOW_COPY_AND_ASSIGN(ReadBuffer);
549 };
550
Channel(Delegate * delegate)551 Channel::Channel(Delegate* delegate)
552 : delegate_(delegate), read_buffer_(new ReadBuffer) {
553 }
554
~Channel()555 Channel::~Channel() {
556 }
557
ShutDown()558 void Channel::ShutDown() {
559 delegate_ = nullptr;
560 ShutDownImpl();
561 }
562
GetReadBuffer(size_t * buffer_capacity)563 char* Channel::GetReadBuffer(size_t *buffer_capacity) {
564 DCHECK(read_buffer_);
565 size_t required_capacity = *buffer_capacity;
566 if (!required_capacity)
567 required_capacity = kReadBufferSize;
568
569 *buffer_capacity = required_capacity;
570 return read_buffer_->Reserve(required_capacity);
571 }
572
OnReadComplete(size_t bytes_read,size_t * next_read_size_hint)573 bool Channel::OnReadComplete(size_t bytes_read, size_t *next_read_size_hint) {
574 bool did_dispatch_message = false;
575 read_buffer_->Claim(bytes_read);
576 while (read_buffer_->num_occupied_bytes() >= sizeof(Message::LegacyHeader)) {
577 // Ensure the occupied data is properly aligned. If it isn't, a SIGBUS could
578 // happen on architectures that don't allow misaligned words access (i.e.
579 // anything other than x86). Only re-align when necessary to avoid copies.
580 if (!IsAlignedForChannelMessage(
581 reinterpret_cast<uintptr_t>(read_buffer_->occupied_bytes()))) {
582 read_buffer_->Realign();
583 }
584
585 // We have at least enough data available for a LegacyHeader.
586 const Message::LegacyHeader* legacy_header =
587 reinterpret_cast<const Message::LegacyHeader*>(
588 read_buffer_->occupied_bytes());
589
590 if (legacy_header->num_bytes < sizeof(Message::LegacyHeader) ||
591 legacy_header->num_bytes > kMaxChannelMessageSize) {
592 LOG(ERROR) << "Invalid message size: " << legacy_header->num_bytes;
593 return false;
594 }
595
596 if (read_buffer_->num_occupied_bytes() < legacy_header->num_bytes) {
597 // Not enough data available to read the full message. Hint to the
598 // implementation that it should try reading the full size of the message.
599 *next_read_size_hint =
600 legacy_header->num_bytes - read_buffer_->num_occupied_bytes();
601 return true;
602 }
603
604 const Message::Header* header = nullptr;
605 if (legacy_header->message_type != Message::MessageType::NORMAL_LEGACY) {
606 header = reinterpret_cast<const Message::Header*>(legacy_header);
607 }
608
609 size_t extra_header_size = 0;
610 const void* extra_header = nullptr;
611 size_t payload_size = 0;
612 void* payload = nullptr;
613 if (header) {
614 if (header->num_header_bytes < sizeof(Message::Header) ||
615 header->num_header_bytes > header->num_bytes) {
616 LOG(ERROR) << "Invalid message header size: "
617 << header->num_header_bytes;
618 return false;
619 }
620 extra_header_size = header->num_header_bytes - sizeof(Message::Header);
621 extra_header = extra_header_size ? header + 1 : nullptr;
622 payload_size = header->num_bytes - header->num_header_bytes;
623 payload = payload_size
624 ? reinterpret_cast<Message::Header*>(
625 const_cast<char*>(read_buffer_->occupied_bytes()) +
626 header->num_header_bytes)
627 : nullptr;
628 } else {
629 payload_size = legacy_header->num_bytes - sizeof(Message::LegacyHeader);
630 payload = payload_size
631 ? const_cast<Message::LegacyHeader*>(&legacy_header[1])
632 : nullptr;
633 }
634
635 const uint16_t num_handles =
636 header ? header->num_handles : legacy_header->num_handles;
637 ScopedPlatformHandleVectorPtr handles;
638 if (num_handles > 0) {
639 if (!GetReadPlatformHandles(num_handles, extra_header, extra_header_size,
640 &handles)) {
641 return false;
642 }
643
644 if (!handles) {
645 // Not enough handles available for this message.
646 break;
647 }
648 }
649
650 // We've got a complete message! Dispatch it and try another.
651 if (legacy_header->message_type != Message::MessageType::NORMAL_LEGACY &&
652 legacy_header->message_type != Message::MessageType::NORMAL) {
653 if (!OnControlMessage(legacy_header->message_type, payload, payload_size,
654 std::move(handles))) {
655 return false;
656 }
657 did_dispatch_message = true;
658 } else if (delegate_) {
659 delegate_->OnChannelMessage(payload, payload_size, std::move(handles));
660 did_dispatch_message = true;
661 }
662
663 read_buffer_->Discard(legacy_header->num_bytes);
664 }
665
666 *next_read_size_hint = did_dispatch_message ? 0 : kReadBufferSize;
667 return true;
668 }
669
OnError()670 void Channel::OnError() {
671 if (delegate_)
672 delegate_->OnChannelError();
673 }
674
OnControlMessage(Message::MessageType message_type,const void * payload,size_t payload_size,ScopedPlatformHandleVectorPtr handles)675 bool Channel::OnControlMessage(Message::MessageType message_type,
676 const void* payload,
677 size_t payload_size,
678 ScopedPlatformHandleVectorPtr handles) {
679 return false;
680 }
681
682 } // namespace edk
683 } // namespace mojo
684