• 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/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 
Message(size_t payload_size,size_t max_handles)61 Channel::Message::Message(size_t payload_size, size_t max_handles)
62     : Message(payload_size, payload_size, max_handles) {}
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     : Message(payload_size, payload_size, max_handles, message_type) {}
68 
Message(size_t capacity,size_t payload_size,size_t max_handles)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 
Message(size_t capacity,size_t payload_size,size_t max_handles,MessageType message_type)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 
~Message()160 Channel::Message::~Message() {
161   base::AlignedFree(data_);
162 }
163 
164 // static
Deserialize(const void * data,size_t data_num_bytes,base::ProcessHandle from_process)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 
capacity() const272 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 
ExtendPayload(size_t new_payload_size)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 
extra_header() const306 const void* Channel::Message::extra_header() const {
307   DCHECK(!is_legacy_message());
308   return data_ + sizeof(Header);
309 }
310 
mutable_extra_header()311 void* Channel::Message::mutable_extra_header() {
312   DCHECK(!is_legacy_message());
313   return data_ + sizeof(Header);
314 }
315 
extra_header_size() const316 size_t Channel::Message::extra_header_size() const {
317   return header()->num_header_bytes - sizeof(Header);
318 }
319 
mutable_payload()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 
payload() const326 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 
payload_size() const332 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 
num_handles() const338 size_t Channel::Message::num_handles() const {
339   return is_legacy_message() ? legacy_header()->num_handles
340                              : header()->num_handles;
341 }
342 
has_handles() const343 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)
has_mach_ports() const349 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 
is_legacy_message() const361 bool Channel::Message::is_legacy_message() const {
362   return legacy_header()->message_type == MessageType::NORMAL_LEGACY;
363 }
364 
legacy_header() const365 Channel::Message::LegacyHeader* Channel::Message::legacy_header() const {
366   return reinterpret_cast<LegacyHeader*>(data_);
367 }
368 
header() const369 Channel::Message::Header* Channel::Message::header() const {
370   DCHECK(!is_legacy_message());
371   return reinterpret_cast<Header*>(data_);
372 }
373 
SetHandles(std::vector<PlatformHandle> new_handles)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 
SetHandles(std::vector<PlatformHandleInTransit> new_handles)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 
TakeHandles()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>
TakeHandlesForTransport()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:
ReadBuffer()504   ReadBuffer() {
505     size_ = kReadBufferSize;
506     data_ =
507         static_cast<char*>(base::AlignedAlloc(size_, kChannelMessageAlignment));
508   }
509 
~ReadBuffer()510   ~ReadBuffer() {
511     DCHECK(data_);
512     base::AlignedFree(data_);
513   }
514 
occupied_bytes() const515   const char* occupied_bytes() const { return data_ + num_discarded_bytes_; }
516 
num_occupied_bytes() const517   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.
Reserve(size_t num_bytes)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.
Claim(size_t num_bytes)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.
Discard(size_t num_bytes)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 
Realign()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 
Channel(Delegate * delegate)602 Channel::Channel(Delegate* delegate)
603     : delegate_(delegate), read_buffer_(new ReadBuffer) {}
604 
~Channel()605 Channel::~Channel() {}
606 
ShutDown()607 void Channel::ShutDown() {
608   ShutDownImpl();
609   delegate_ = nullptr;
610 }
611 
GetReadBuffer(size_t * buffer_capacity)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 
OnReadComplete(size_t bytes_read,size_t * next_read_size_hint)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 
OnError(Error error)725 void Channel::OnError(Error error) {
726   if (delegate_)
727     delegate_->OnChannelError(error);
728 }
729 
OnControlMessage(Message::MessageType message_type,const void * payload,size_t payload_size,std::vector<PlatformHandle> handles)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