Home | History | Annotate | Download | only in system
      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 
     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 
     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 
    138 Channel::Message::~Message() {
    139   base::AlignedFree(data_);
    140 }
    141 
    142 // static
    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 
    239 const void* Channel::Message::extra_header() const {
    240   DCHECK(!is_legacy_message());
    241   return data_ + sizeof(Header);
    242 }
    243 
    244 void* Channel::Message::mutable_extra_header() {
    245   DCHECK(!is_legacy_message());
    246   return data_ + sizeof(Header);
    247 }
    248 
    249 size_t Channel::Message::extra_header_size() const {
    250   return header()->num_header_bytes - sizeof(Header);
    251 }
    252 
    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 
    259 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 
    265 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 
    271 size_t Channel::Message::num_handles() const {
    272   return is_legacy_message() ? legacy_header()->num_handles
    273                              : header()->num_handles;
    274 }
    275 
    276 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)
    282 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 
    296 bool Channel::Message::is_legacy_message() const {
    297   return legacy_header()->message_type == MessageType::NORMAL_LEGACY;
    298 }
    299 
    300 Channel::Message::LegacyHeader* Channel::Message::legacy_header() const {
    301   return reinterpret_cast<LegacyHeader*>(data_);
    302 }
    303 
    304 Channel::Message::Header* Channel::Message::header() const {
    305   DCHECK(!is_legacy_message());
    306   return reinterpret_cast<Header*>(data_);
    307 }
    308 
    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 
    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 
    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
    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:
    453   ReadBuffer() {
    454     size_ = kReadBufferSize;
    455     data_ = static_cast<char*>(base::AlignedAlloc(size_,
    456                                                   kChannelMessageAlignment));
    457   }
    458 
    459   ~ReadBuffer() {
    460     DCHECK(data_);
    461     base::AlignedFree(data_);
    462   }
    463 
    464   const char* occupied_bytes() const { return data_ + num_discarded_bytes_; }
    465 
    466   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.
    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.
    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.
    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 
    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 
    551 Channel::Channel(Delegate* delegate)
    552     : delegate_(delegate), read_buffer_(new ReadBuffer) {
    553 }
    554 
    555 Channel::~Channel() {
    556 }
    557 
    558 void Channel::ShutDown() {
    559   delegate_ = nullptr;
    560   ShutDownImpl();
    561 }
    562 
    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 
    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 
    670 void Channel::OnError() {
    671   if (delegate_)
    672     delegate_->OnChannelError();
    673 }
    674 
    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