• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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