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