1645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// Copyright 2016 The Chromium Authors. All rights reserved.
2645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// Use of this source code is governed by a BSD-style license that can be
3645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// found in the LICENSE file.
4645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
5645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "mojo/edk/system/channel.h"
6645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
7cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli#include <stddef.h>
8645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include <string.h>
9645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
10645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include <algorithm>
11645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include <limits>
12645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include <utility>
13645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
14645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "base/macros.h"
15645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "base/memory/aligned_memory.h"
16645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "base/process/process_handle.h"
17645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "mojo/edk/embedder/platform_handle.h"
18645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
19645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#if defined(OS_MACOSX) && !defined(OS_IOS)
20645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "base/mac/mach_logging.h"
21645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#elif defined(OS_WIN)
22645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "base/win/win_util.h"
23645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#endif
24645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
25645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chaveznamespace mojo {
26645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chaveznamespace edk {
27645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
28645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chaveznamespace {
29645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
30cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civellistatic_assert(
31cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    IsAlignedForChannelMessage(sizeof(Channel::Message::LegacyHeader)),
32cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    "Invalid LegacyHeader size.");
33645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
34cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civellistatic_assert(IsAlignedForChannelMessage(sizeof(Channel::Message::Header)),
35cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli              "Invalid Header size.");
36cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli
37cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civellistatic_assert(sizeof(Channel::Message::LegacyHeader) == 8,
38cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli              "LegacyHeader must be 8 bytes on ChromeOS and Android");
39cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli
40cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civellistatic_assert(offsetof(Channel::Message::LegacyHeader, num_bytes) ==
41cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli                  offsetof(Channel::Message::Header, num_bytes),
42cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli              "num_bytes should be at the same offset in both Header structs.");
43cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civellistatic_assert(offsetof(Channel::Message::LegacyHeader, message_type) ==
44cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli                  offsetof(Channel::Message::Header, message_type),
45cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli              "message_type should be at the same offset in both Header "
46cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli              "structs.");
47645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
48645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}  // namespace
49645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
50645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezconst size_t kReadBufferSize = 4096;
51cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelliconst size_t kMaxUnusedReadBufferCapacity = 4096;
52645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezconst size_t kMaxChannelMessageSize = 256 * 1024 * 1024;
53645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezconst size_t kMaxAttachedHandles = 128;
54645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
55cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay CivelliChannel::Message::Message(size_t payload_size, size_t max_handles)
56cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli#if defined(MOJO_EDK_LEGACY_PROTOCOL)
57cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    : Message(payload_size, max_handles, MessageType::NORMAL_LEGACY) {
58cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli}
59cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli#else
60cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    : Message(payload_size, max_handles, MessageType::NORMAL) {
61cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli}
62cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli#endif
63cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli
64645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector ChavezChannel::Message::Message(size_t payload_size,
65645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                          size_t max_handles,
66cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli                          MessageType message_type)
67645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    : max_handles_(max_handles) {
68645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK_LE(max_handles_, kMaxAttachedHandles);
69645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
70cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  const bool is_legacy_message = (message_type == MessageType::NORMAL_LEGACY);
71645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  size_t extra_header_size = 0;
72645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#if defined(OS_WIN)
73645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // On Windows we serialize HANDLEs into the extra header space.
74645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  extra_header_size = max_handles_ * sizeof(HandleEntry);
75645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#elif defined(OS_MACOSX) && !defined(OS_IOS)
76645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // On OSX, some of the platform handles may be mach ports, which are
77645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // serialised into the message buffer. Since there could be a mix of fds and
78645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // mach ports, we store the mach ports as an <index, port> pair (of uint32_t),
79645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // so that the original ordering of handles can be re-created.
80645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (max_handles) {
81645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    extra_header_size =
82645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        sizeof(MachPortsExtraHeader) + (max_handles * sizeof(MachPortsEntry));
83645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
84645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#endif
85645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // Pad extra header data to be aliged to |kChannelMessageAlignment| bytes.
86cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  if (!IsAlignedForChannelMessage(extra_header_size)) {
87645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    extra_header_size += kChannelMessageAlignment -
88645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                         (extra_header_size % kChannelMessageAlignment);
89645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
90cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  DCHECK(IsAlignedForChannelMessage(extra_header_size));
91cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  const size_t header_size =
92cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli      is_legacy_message ? sizeof(LegacyHeader) : sizeof(Header);
93cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  DCHECK(extra_header_size == 0 || !is_legacy_message);
94645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
95cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  size_ = header_size + extra_header_size + payload_size;
96645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  data_ = static_cast<char*>(base::AlignedAlloc(size_,
97645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                                                kChannelMessageAlignment));
98645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // Only zero out the header and not the payload. Since the payload is going to
99645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // be memcpy'd, zeroing the payload is unnecessary work and a significant
100645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // performance issue when dealing with large messages. Any sanitizer errors
101645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // complaining about an uninitialized read in the payload area should be
102645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // treated as an error and fixed.
103cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  memset(data_, 0, header_size + extra_header_size);
104645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
105645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK_LE(size_, std::numeric_limits<uint32_t>::max());
106cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  legacy_header()->num_bytes = static_cast<uint32_t>(size_);
107645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
108cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  DCHECK_LE(header_size + extra_header_size,
109645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            std::numeric_limits<uint16_t>::max());
110cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  legacy_header()->message_type = message_type;
111cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli
112cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  if (is_legacy_message) {
113cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    legacy_header()->num_handles = static_cast<uint16_t>(max_handles);
114cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  } else {
115cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    header()->num_header_bytes =
116cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli        static_cast<uint16_t>(header_size + extra_header_size);
117cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  }
118645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
119645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (max_handles_ > 0) {
120645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#if defined(OS_WIN)
121645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    handles_ = reinterpret_cast<HandleEntry*>(mutable_extra_header());
122645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // Initialize all handles to invalid values.
123645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    for (size_t i = 0; i < max_handles_; ++i)
124645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      handles_[i].handle = base::win::HandleToUint32(INVALID_HANDLE_VALUE);
125645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#elif defined(OS_MACOSX) && !defined(OS_IOS)
126645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    mach_ports_header_ =
127645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        reinterpret_cast<MachPortsExtraHeader*>(mutable_extra_header());
128645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    mach_ports_header_->num_ports = 0;
129645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // Initialize all handles to invalid values.
130645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    for (size_t i = 0; i < max_handles_; ++i) {
131645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      mach_ports_header_->entries[i] =
132645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez          {0, static_cast<uint32_t>(MACH_PORT_NULL)};
133645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
134645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#endif
135645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
136645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
137645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
138645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector ChavezChannel::Message::~Message() {
139645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  base::AlignedFree(data_);
140645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
141645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
142645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// static
143645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector ChavezChannel::MessagePtr Channel::Message::Deserialize(const void* data,
144645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                                                  size_t data_num_bytes) {
145cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  if (data_num_bytes < sizeof(LegacyHeader))
146645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return nullptr;
147645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
148cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  const LegacyHeader* legacy_header =
149cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli      reinterpret_cast<const LegacyHeader*>(data);
150cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  if (legacy_header->num_bytes != data_num_bytes) {
151cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    DLOG(ERROR) << "Decoding invalid message: " << legacy_header->num_bytes
152645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                << " != " << data_num_bytes;
153645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return nullptr;
154645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
155645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
156cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  const Header* header = nullptr;
157cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  if (legacy_header->message_type == MessageType::NORMAL)
158cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    header = reinterpret_cast<const Header*>(data);
159cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli
160cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  uint32_t extra_header_size = 0;
161cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  size_t payload_size = 0;
162cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  const char* payload = nullptr;
163cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  if (!header) {
164cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    payload_size = data_num_bytes - sizeof(LegacyHeader);
165cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    payload = static_cast<const char*>(data) + sizeof(LegacyHeader);
166cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  } else {
167cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    if (header->num_bytes < header->num_header_bytes ||
168cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli        header->num_header_bytes < sizeof(Header)) {
169cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli      DLOG(ERROR) << "Decoding invalid message: " << header->num_bytes << " < "
170cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli                  << header->num_header_bytes;
171cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli      return nullptr;
172cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    }
173cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    extra_header_size = header->num_header_bytes - sizeof(Header);
174cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    payload_size = data_num_bytes - header->num_header_bytes;
175cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    payload = static_cast<const char*>(data) + header->num_header_bytes;
176645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
177645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
178645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#if defined(OS_WIN)
179645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  uint32_t max_handles = extra_header_size / sizeof(HandleEntry);
180645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#elif defined(OS_MACOSX) && !defined(OS_IOS)
181cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  if (extra_header_size > 0 &&
182cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli      extra_header_size < sizeof(MachPortsExtraHeader)) {
183645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    DLOG(ERROR) << "Decoding invalid message: " << extra_header_size << " < "
184645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                << sizeof(MachPortsExtraHeader);
185645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return nullptr;
186645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
187cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  uint32_t max_handles =
188cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli      extra_header_size == 0
189cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli          ? 0
190cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli          : (extra_header_size - sizeof(MachPortsExtraHeader)) /
191cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli                sizeof(MachPortsEntry);
192645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#else
193645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  const uint32_t max_handles = 0;
194645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#endif  // defined(OS_WIN)
195645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
196cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  const uint16_t num_handles =
197cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli      header ? header->num_handles : legacy_header->num_handles;
198cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  if (num_handles > max_handles || max_handles > kMaxAttachedHandles) {
199cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    DLOG(ERROR) << "Decoding invalid message: " << num_handles << " > "
200cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli                << max_handles;
201645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return nullptr;
202645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
203645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
204cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  MessagePtr message(
205cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli      new Message(payload_size, max_handles, legacy_header->message_type));
206645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK_EQ(message->data_num_bytes(), data_num_bytes);
207645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
208645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // Copy all payload bytes.
209645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (payload_size)
210645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    memcpy(message->mutable_payload(), payload, payload_size);
211645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
212cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  if (header) {
213cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    DCHECK_EQ(message->extra_header_size(), extra_header_size);
214cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    DCHECK_EQ(message->header()->num_header_bytes, header->num_header_bytes);
215645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
216cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    if (message->extra_header_size()) {
217cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli      // Copy extra header bytes.
218cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli      memcpy(message->mutable_extra_header(),
219cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli             static_cast<const char*>(data) + sizeof(Header),
220cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli             message->extra_header_size());
221cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    }
222cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    message->header()->num_handles = header->num_handles;
223cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  } else {
224cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    message->legacy_header()->num_handles = legacy_header->num_handles;
225645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
226645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
227645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#if defined(OS_WIN)
228cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  ScopedPlatformHandleVectorPtr handles(new PlatformHandleVector(num_handles));
229cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  for (size_t i = 0; i < num_handles; i++) {
230cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    (*handles)[i].handle =
231cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli        base::win::Uint32ToHandle(message->handles_[i].handle);
232645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
233645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  message->SetHandles(std::move(handles));
234645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#endif
235645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
236645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  return message;
237645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
238645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
239cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelliconst void* Channel::Message::extra_header() const {
240cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  DCHECK(!is_legacy_message());
241cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  return data_ + sizeof(Header);
242cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli}
243cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli
244cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civellivoid* Channel::Message::mutable_extra_header() {
245cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  DCHECK(!is_legacy_message());
246cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  return data_ + sizeof(Header);
247cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli}
248cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli
249cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civellisize_t Channel::Message::extra_header_size() const {
250cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  return header()->num_header_bytes - sizeof(Header);
251cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli}
252cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli
253cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civellivoid* Channel::Message::mutable_payload() {
254cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  if (is_legacy_message())
255cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    return static_cast<void*>(legacy_header() + 1);
256cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  return data_ + header()->num_header_bytes;
257cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli}
258cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli
259cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelliconst void* Channel::Message::payload() const {
260cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  if (is_legacy_message())
261cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    return static_cast<const void*>(legacy_header() + 1);
262cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  return data_ + header()->num_header_bytes;
263cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli}
264cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli
265645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezsize_t Channel::Message::payload_size() const {
266cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  if (is_legacy_message())
267cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    return legacy_header()->num_bytes - sizeof(LegacyHeader);
268cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  return size_ - header()->num_header_bytes;
269cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli}
270cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli
271cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civellisize_t Channel::Message::num_handles() const {
272cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  return is_legacy_message() ? legacy_header()->num_handles
273cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli                             : header()->num_handles;
274cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli}
275cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli
276cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civellibool Channel::Message::has_handles() const {
277cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  return (is_legacy_message() ? legacy_header()->num_handles
278cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli                              : header()->num_handles) > 0;
279645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
280645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
281645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#if defined(OS_MACOSX) && !defined(OS_IOS)
282645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezbool Channel::Message::has_mach_ports() const {
283645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (!has_handles())
284645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return false;
285645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
286645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  for (const auto& handle : (*handle_vector_)) {
287645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (handle.type == PlatformHandle::Type::MACH ||
288645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        handle.type == PlatformHandle::Type::MACH_NAME) {
289645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      return true;
290645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
291645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
292645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  return false;
293645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
294645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#endif
295645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
296cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civellibool Channel::Message::is_legacy_message() const {
297cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  return legacy_header()->message_type == MessageType::NORMAL_LEGACY;
298cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli}
299cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli
300cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay CivelliChannel::Message::LegacyHeader* Channel::Message::legacy_header() const {
301cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  return reinterpret_cast<LegacyHeader*>(data_);
302cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli}
303cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli
304cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay CivelliChannel::Message::Header* Channel::Message::header() const {
305cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  DCHECK(!is_legacy_message());
306cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  return reinterpret_cast<Header*>(data_);
307cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli}
308cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli
309645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezvoid Channel::Message::SetHandles(ScopedPlatformHandleVectorPtr new_handles) {
310cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  if (is_legacy_message()) {
311cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    // Old semantics for ChromeOS and Android
312cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    if (legacy_header()->num_handles == 0) {
313cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli      CHECK(!new_handles || new_handles->size() == 0);
314cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli      return;
315cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    }
316cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    CHECK(new_handles && new_handles->size() == legacy_header()->num_handles);
317cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    std::swap(handle_vector_, new_handles);
318645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return;
319645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
320645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
321645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (max_handles_ == 0) {
322645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    CHECK(!new_handles || new_handles->size() == 0);
323645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return;
324645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
325645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
326645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  CHECK(new_handles && new_handles->size() <= max_handles_);
327cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  header()->num_handles = static_cast<uint16_t>(new_handles->size());
328645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  std::swap(handle_vector_, new_handles);
329645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#if defined(OS_WIN)
330645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  memset(handles_, 0, extra_header_size());
331645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  for (size_t i = 0; i < handle_vector_->size(); i++)
332645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    handles_[i].handle = base::win::HandleToUint32((*handle_vector_)[i].handle);
333645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#endif  // defined(OS_WIN)
334645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
335645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#if defined(OS_MACOSX) && !defined(OS_IOS)
336645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  size_t mach_port_index = 0;
337645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (mach_ports_header_) {
338645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    for (size_t i = 0; i < max_handles_; ++i) {
339645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      mach_ports_header_->entries[i] =
340645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez          {0, static_cast<uint32_t>(MACH_PORT_NULL)};
341645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
342645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    for (size_t i = 0; i < handle_vector_->size(); i++) {
343645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      if ((*handle_vector_)[i].type == PlatformHandle::Type::MACH ||
344645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez          (*handle_vector_)[i].type == PlatformHandle::Type::MACH_NAME) {
345645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        mach_port_t port = (*handle_vector_)[i].port;
346645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        mach_ports_header_->entries[mach_port_index].index = i;
347645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        mach_ports_header_->entries[mach_port_index].mach_port = port;
348645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        mach_port_index++;
349645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      }
350645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
351645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    mach_ports_header_->num_ports = static_cast<uint16_t>(mach_port_index);
352645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
353645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#endif
354645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
355645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
356645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector ChavezScopedPlatformHandleVectorPtr Channel::Message::TakeHandles() {
357645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#if defined(OS_MACOSX) && !defined(OS_IOS)
358645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (mach_ports_header_) {
359645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    for (size_t i = 0; i < max_handles_; ++i) {
360645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      mach_ports_header_->entries[i] =
361645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez          {0, static_cast<uint32_t>(MACH_PORT_NULL)};
362645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
363645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    mach_ports_header_->num_ports = 0;
364645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
36521a249e4d9cb0b2ec6f0ff84ed5f7939ea67ac52Luis Hector Chavez#endif
366cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  if (is_legacy_message())
367cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    legacy_header()->num_handles = 0;
368cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  else
369cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    header()->num_handles = 0;
370cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  return std::move(handle_vector_);
371645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
372645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
373645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector ChavezScopedPlatformHandleVectorPtr Channel::Message::TakeHandlesForTransport() {
374645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#if defined(OS_WIN)
375645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // Not necessary on Windows.
376645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  NOTREACHED();
377645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  return nullptr;
378645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#elif defined(OS_MACOSX) && !defined(OS_IOS)
379645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (handle_vector_) {
380645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    for (auto it = handle_vector_->begin(); it != handle_vector_->end(); ) {
381645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      if (it->type == PlatformHandle::Type::MACH ||
382645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez          it->type == PlatformHandle::Type::MACH_NAME) {
383645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        // For Mach port names, we can can just leak them. They're not real
384645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        // ports anyways. For real ports, they're leaked because this is a child
385645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        // process and the remote process will take ownership.
386645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        it = handle_vector_->erase(it);
387645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      } else {
388645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        ++it;
389645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      }
390645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
391645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
392645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  return std::move(handle_vector_);
393645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#else
394645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  return std::move(handle_vector_);
395645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#endif
396645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
397645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
398645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#if defined(OS_WIN)
399645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// static
400645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezbool Channel::Message::RewriteHandles(base::ProcessHandle from_process,
401645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                                      base::ProcessHandle to_process,
402645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                                      PlatformHandleVector* handles) {
403645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  bool success = true;
404645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  for (size_t i = 0; i < handles->size(); ++i) {
405645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (!(*handles)[i].is_valid()) {
406645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      DLOG(ERROR) << "Refusing to duplicate invalid handle.";
407645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      continue;
408645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
409645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    DCHECK_EQ((*handles)[i].owning_process, from_process);
410645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    BOOL result = DuplicateHandle(
411645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        from_process, (*handles)[i].handle, to_process,
412645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        &(*handles)[i].handle, 0, FALSE,
413645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
414645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (result) {
415645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      (*handles)[i].owning_process = to_process;
416645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    } else {
417645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      success = false;
418645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
419645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      // If handle duplication fails, the source handle will already be closed
420645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      // due to DUPLICATE_CLOSE_SOURCE. Replace the handle in the message with
421645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      // an invalid handle.
422645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      (*handles)[i].handle = INVALID_HANDLE_VALUE;
423645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      (*handles)[i].owning_process = base::GetCurrentProcessHandle();
424645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
425645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
426645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  return success;
427645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
428645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#endif
429645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
430645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// Helper class for managing a Channel's read buffer allocations. This maintains
431645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// a single contiguous buffer with the layout:
432645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez//
433645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez//   [discarded bytes][occupied bytes][unoccupied bytes]
434645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez//
435645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// The Reserve() method ensures that a certain capacity of unoccupied bytes are
436645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// available. It does not claim that capacity and only allocates new capacity
437645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// when strictly necessary.
438645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez//
439645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// Claim() marks unoccupied bytes as occupied.
440645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez//
441645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// Discard() marks occupied bytes as discarded, signifying that their contents
442645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// can be forgotten or overwritten.
443645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez//
444645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// Realign() moves occupied bytes to the front of the buffer so that those
445645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// occupied bytes are properly aligned.
446645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez//
447645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// The most common Channel behavior in practice should result in very few
448645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// allocations and copies, as memory is claimed and discarded shortly after
449645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// being reserved, and future reservations will immediately reuse discarded
450645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// memory.
451645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezclass Channel::ReadBuffer {
452645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez public:
453645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  ReadBuffer() {
454645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    size_ = kReadBufferSize;
455645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    data_ = static_cast<char*>(base::AlignedAlloc(size_,
456645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                                                  kChannelMessageAlignment));
457645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
458645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
459645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  ~ReadBuffer() {
460645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    DCHECK(data_);
461645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    base::AlignedFree(data_);
462645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
463645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
464645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  const char* occupied_bytes() const { return data_ + num_discarded_bytes_; }
465645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
466645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  size_t num_occupied_bytes() const {
467645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return num_occupied_bytes_ - num_discarded_bytes_;
468645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
469645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
470645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // Ensures the ReadBuffer has enough contiguous space allocated to hold
471645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // |num_bytes| more bytes; returns the address of the first available byte.
472645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  char* Reserve(size_t num_bytes) {
473645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (num_occupied_bytes_ + num_bytes > size_) {
474645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      size_ = std::max(size_ * 2, num_occupied_bytes_ + num_bytes);
475645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      void* new_data = base::AlignedAlloc(size_, kChannelMessageAlignment);
476645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      memcpy(new_data, data_, num_occupied_bytes_);
477645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      base::AlignedFree(data_);
478645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      data_ = static_cast<char*>(new_data);
479645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
480645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
481645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return data_ + num_occupied_bytes_;
482645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
483645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
484645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // Marks the first |num_bytes| unoccupied bytes as occupied.
485645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  void Claim(size_t num_bytes) {
486645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    DCHECK_LE(num_occupied_bytes_ + num_bytes, size_);
487645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    num_occupied_bytes_ += num_bytes;
488645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
489645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
490645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // Marks the first |num_bytes| occupied bytes as discarded. This may result in
491645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // shrinkage of the internal buffer, and it is not safe to assume the result
492645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // of a previous Reserve() call is still valid after this.
493645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  void Discard(size_t num_bytes) {
494645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    DCHECK_LE(num_discarded_bytes_ + num_bytes, num_occupied_bytes_);
495645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    num_discarded_bytes_ += num_bytes;
496645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
497645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (num_discarded_bytes_ == num_occupied_bytes_) {
498645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      // We can just reuse the buffer from the beginning in this common case.
499645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      num_discarded_bytes_ = 0;
500645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      num_occupied_bytes_ = 0;
501645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
502645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
503645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (num_discarded_bytes_ > kMaxUnusedReadBufferCapacity) {
504645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      // In the uncommon case that we have a lot of discarded data at the
505645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      // front of the buffer, simply move remaining data to a smaller buffer.
506645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      size_t num_preserved_bytes = num_occupied_bytes_ - num_discarded_bytes_;
507645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      size_ = std::max(num_preserved_bytes, kReadBufferSize);
508645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      char* new_data = static_cast<char*>(
509645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez          base::AlignedAlloc(size_, kChannelMessageAlignment));
510645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      memcpy(new_data, data_ + num_discarded_bytes_, num_preserved_bytes);
511645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      base::AlignedFree(data_);
512645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      data_ = new_data;
513645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      num_discarded_bytes_ = 0;
514645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      num_occupied_bytes_ = num_preserved_bytes;
515645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
516645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
517645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (num_occupied_bytes_ == 0 && size_ > kMaxUnusedReadBufferCapacity) {
518645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      // Opportunistically shrink the read buffer back down to a small size if
519645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      // it's grown very large. We only do this if there are no remaining
520645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      // unconsumed bytes in the buffer to avoid copies in most the common
521645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      // cases.
522645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      size_ = kMaxUnusedReadBufferCapacity;
523645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      base::AlignedFree(data_);
524645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      data_ = static_cast<char*>(
525645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez          base::AlignedAlloc(size_, kChannelMessageAlignment));
526645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
527645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
528645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
529645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  void Realign() {
530645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    size_t num_bytes = num_occupied_bytes();
531645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    memmove(data_, occupied_bytes(), num_bytes);
532645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    num_discarded_bytes_ = 0;
533645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    num_occupied_bytes_ = num_bytes;
534645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
535645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
536645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez private:
537645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  char* data_ = nullptr;
538645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
539645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // The total size of the allocated buffer.
540645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  size_t size_ = 0;
541645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
542645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // The number of discarded bytes at the beginning of the allocated buffer.
543645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  size_t num_discarded_bytes_ = 0;
544645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
545645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // The total number of occupied bytes, including discarded bytes.
546645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  size_t num_occupied_bytes_ = 0;
547645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
548645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DISALLOW_COPY_AND_ASSIGN(ReadBuffer);
549645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez};
550645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
551645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector ChavezChannel::Channel(Delegate* delegate)
552645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    : delegate_(delegate), read_buffer_(new ReadBuffer) {
553645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
554645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
555645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector ChavezChannel::~Channel() {
556645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
557645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
558645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezvoid Channel::ShutDown() {
559645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  delegate_ = nullptr;
560645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  ShutDownImpl();
561645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
562645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
563645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezchar* Channel::GetReadBuffer(size_t *buffer_capacity) {
564645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK(read_buffer_);
565645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  size_t required_capacity = *buffer_capacity;
566645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (!required_capacity)
567645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    required_capacity = kReadBufferSize;
568645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
569645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  *buffer_capacity = required_capacity;
570645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  return read_buffer_->Reserve(required_capacity);
571645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
572645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
573645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezbool Channel::OnReadComplete(size_t bytes_read, size_t *next_read_size_hint) {
574645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  bool did_dispatch_message = false;
575645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  read_buffer_->Claim(bytes_read);
576cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli  while (read_buffer_->num_occupied_bytes() >= sizeof(Message::LegacyHeader)) {
577645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // Ensure the occupied data is properly aligned. If it isn't, a SIGBUS could
578645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // happen on architectures that don't allow misaligned words access (i.e.
579645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // anything other than x86). Only re-align when necessary to avoid copies.
580cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    if (!IsAlignedForChannelMessage(
581cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli            reinterpret_cast<uintptr_t>(read_buffer_->occupied_bytes()))) {
582645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      read_buffer_->Realign();
583cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    }
584cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli
585cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    // We have at least enough data available for a LegacyHeader.
586cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    const Message::LegacyHeader* legacy_header =
587cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli        reinterpret_cast<const Message::LegacyHeader*>(
588cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli            read_buffer_->occupied_bytes());
589645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
590cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    if (legacy_header->num_bytes < sizeof(Message::LegacyHeader) ||
591cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli        legacy_header->num_bytes > kMaxChannelMessageSize) {
592cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli      LOG(ERROR) << "Invalid message size: " << legacy_header->num_bytes;
593645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      return false;
594645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
595645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
596cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    if (read_buffer_->num_occupied_bytes() < legacy_header->num_bytes) {
597645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      // Not enough data available to read the full message. Hint to the
598645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      // implementation that it should try reading the full size of the message.
599645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      *next_read_size_hint =
600cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli          legacy_header->num_bytes - read_buffer_->num_occupied_bytes();
601645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      return true;
602645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
603645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
604cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    const Message::Header* header = nullptr;
605cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    if (legacy_header->message_type != Message::MessageType::NORMAL_LEGACY) {
606cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli      header = reinterpret_cast<const Message::Header*>(legacy_header);
607cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    }
608cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli
609645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    size_t extra_header_size = 0;
610645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    const void* extra_header = nullptr;
611cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    size_t payload_size = 0;
612cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    void* payload = nullptr;
613cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    if (header) {
614cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli      if (header->num_header_bytes < sizeof(Message::Header) ||
615cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli          header->num_header_bytes > header->num_bytes) {
616cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli        LOG(ERROR) << "Invalid message header size: "
617cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli                   << header->num_header_bytes;
618cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli        return false;
619cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli      }
620cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli      extra_header_size = header->num_header_bytes - sizeof(Message::Header);
621cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli      extra_header = extra_header_size ? header + 1 : nullptr;
622cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli      payload_size = header->num_bytes - header->num_header_bytes;
623cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli      payload = payload_size
624cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli                    ? reinterpret_cast<Message::Header*>(
625cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli                          const_cast<char*>(read_buffer_->occupied_bytes()) +
626cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli                          header->num_header_bytes)
627cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli                    : nullptr;
628cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    } else {
629cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli      payload_size = legacy_header->num_bytes - sizeof(Message::LegacyHeader);
630cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli      payload = payload_size
631cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli                    ? const_cast<Message::LegacyHeader*>(&legacy_header[1])
632cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli                    : nullptr;
633645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
634645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
635cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    const uint16_t num_handles =
636cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli        header ? header->num_handles : legacy_header->num_handles;
637645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    ScopedPlatformHandleVectorPtr handles;
638cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    if (num_handles > 0) {
639cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli      if (!GetReadPlatformHandles(num_handles, extra_header, extra_header_size,
640cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli                                  &handles)) {
641645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return false;
642645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      }
643645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
644645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      if (!handles) {
645645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        // Not enough handles available for this message.
646645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        break;
647645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      }
648645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
649645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
650645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // We've got a complete message! Dispatch it and try another.
651cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    if (legacy_header->message_type != Message::MessageType::NORMAL_LEGACY &&
652cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli        legacy_header->message_type != Message::MessageType::NORMAL) {
653cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli      if (!OnControlMessage(legacy_header->message_type, payload, payload_size,
654645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                            std::move(handles))) {
655645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return false;
656645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      }
657645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      did_dispatch_message = true;
658645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    } else if (delegate_) {
659645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      delegate_->OnChannelMessage(payload, payload_size, std::move(handles));
660645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      did_dispatch_message = true;
661645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
662645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
663cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civelli    read_buffer_->Discard(legacy_header->num_bytes);
664645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
665645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
666645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  *next_read_size_hint = did_dispatch_message ? 0 : kReadBufferSize;
667645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  return true;
668645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
669645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
670645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezvoid Channel::OnError() {
671645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (delegate_)
672645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    delegate_->OnChannelError();
673645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
674645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
675cfc1eaa913db3974e56c87b5489bda0a2bf36d93Jay Civellibool Channel::OnControlMessage(Message::MessageType message_type,
676645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                               const void* payload,
677645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                               size_t payload_size,
678645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                               ScopedPlatformHandleVectorPtr handles) {
679645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  return false;
680645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
681645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
682645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}  // namespace edk
683645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}  // namespace mojo
684