1010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
2010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// found in the LICENSE file.
4010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
5010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "mojo/system/transport_data.h"
6010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
7010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include <string.h>
8010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
9010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "base/compiler_specific.h"
10010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "base/logging.h"
110de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)#include "mojo/system/channel.h"
12010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "mojo/system/constants.h"
13010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "mojo/system/message_in_transit.h"
14010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
15010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)namespace mojo {
16010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)namespace system {
17010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
180de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)// The maximum amount of space needed per platform handle.
190de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)// (|{Channel,RawChannel}::GetSerializedPlatformHandleSize()| should always
200de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)// return a value which is at most this. This is only used to calculate
210de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)// |TransportData::kMaxBufferSize|. This value should be a multiple of the
220de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)// alignment in order to simplify calculations, even though the actual amount of
230de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)// space needed need not be a multiple of the alignment.
240de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)const size_t kMaxSizePerPlatformHandle = 8;
251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccistatic_assert(kMaxSizePerPlatformHandle % MessageInTransit::kMessageAlignment ==
261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                  0,
271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci              "kMaxSizePerPlatformHandle not a multiple of alignment");
280de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
29010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)STATIC_CONST_MEMBER_DEFINITION const size_t
30010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    TransportData::kMaxSerializedDispatcherSize;
31010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)STATIC_CONST_MEMBER_DEFINITION const size_t
32010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    TransportData::kMaxSerializedDispatcherPlatformHandles;
33010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
340de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)// static
350de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)const size_t TransportData::kMaxPlatformHandles =
360de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    kMaxMessageNumHandles * kMaxSerializedDispatcherPlatformHandles;
370de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
38010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// In additional to the header, for each attached (Mojo) handle there'll be a
39010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// handle table entry and serialized dispatcher data.
400de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)// Note: This definition must follow the one for |kMaxPlatformHandles|;
410de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)// otherwise, we get a static initializer with gcc (but not clang).
42010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// static
43010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)const size_t TransportData::kMaxBufferSize =
440de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    sizeof(Header) +
455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    kMaxMessageNumHandles *
465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        (sizeof(HandleTableEntry) + kMaxSerializedDispatcherSize) +
470de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    kMaxPlatformHandles * kMaxSizePerPlatformHandle;
48010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
49010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)struct TransportData::PrivateStructForCompileAsserts {
501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  static_assert(sizeof(Header) % MessageInTransit::kMessageAlignment == 0,
511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                "sizeof(MessageInTransit::Header) not a multiple of alignment");
521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  static_assert(kMaxSerializedDispatcherSize %
531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                        MessageInTransit::kMessageAlignment ==
541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                    0,
551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                "kMaxSerializedDispatcherSize not a multiple of alignment");
561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  static_assert(sizeof(HandleTableEntry) %
571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                        MessageInTransit::kMessageAlignment ==
581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                    0,
591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                "sizeof(MessageInTransit::HandleTableEntry) not a multiple of "
601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                "alignment");
61010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)};
62010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
63010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)TransportData::TransportData(scoped_ptr<DispatcherVector> dispatchers,
64cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                             Channel* channel) {
65010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  DCHECK(dispatchers);
66010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  DCHECK(channel);
67010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
68010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  const size_t num_handles = dispatchers->size();
69010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  DCHECK_GT(num_handles, 0u);
70010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
71010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // The offset to the start of the (Mojo) handle table.
72010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  const size_t handle_table_start_offset = sizeof(Header);
73010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // The offset to the start of the serialized dispatcher data.
74010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  const size_t serialized_dispatcher_start_offset =
75010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      handle_table_start_offset + num_handles * sizeof(HandleTableEntry);
76010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // The estimated size of the secondary buffer. We compute this estimate below.
77010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // It must be at least as big as the (eventual) actual size.
78010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  size_t estimated_size = serialized_dispatcher_start_offset;
790de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  size_t estimated_num_platform_handles = 0;
80010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#if DCHECK_IS_ON
81010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  std::vector<size_t> all_max_sizes(num_handles);
82010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  std::vector<size_t> all_max_platform_handles(num_handles);
83010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#endif
84010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  for (size_t i = 0; i < num_handles; i++) {
85010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    if (Dispatcher* dispatcher = (*dispatchers)[i].get()) {
86010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      size_t max_size = 0;
87010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      size_t max_platform_handles = 0;
88010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      Dispatcher::TransportDataAccess::StartSerialize(
895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          dispatcher, channel, &max_size, &max_platform_handles);
90010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
91010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      DCHECK_LE(max_size, kMaxSerializedDispatcherSize);
92010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      estimated_size += MessageInTransit::RoundUpMessageAlignment(max_size);
93010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      DCHECK_LE(estimated_size, kMaxBufferSize);
94010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      DCHECK_LE(max_platform_handles, kMaxSerializedDispatcherPlatformHandles);
960de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)      estimated_num_platform_handles += max_platform_handles;
970de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)      DCHECK_LE(estimated_num_platform_handles, kMaxPlatformHandles);
98010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
99010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#if DCHECK_IS_ON
100010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      all_max_sizes[i] = max_size;
101010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      all_max_platform_handles[i] = max_platform_handles;
102010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#endif
103010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    }
104010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
105010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
1060de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  size_t size_per_platform_handle = 0;
1070de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  if (estimated_num_platform_handles > 0) {
1080de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    size_per_platform_handle = channel->GetSerializedPlatformHandleSize();
1090de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    DCHECK_LE(size_per_platform_handle, kMaxSizePerPlatformHandle);
1100de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    estimated_size += estimated_num_platform_handles * size_per_platform_handle;
1110de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    estimated_size = MessageInTransit::RoundUpMessageAlignment(estimated_size);
1120de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    DCHECK_LE(estimated_size, kMaxBufferSize);
1130de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  }
1140de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
115010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  buffer_.reset(static_cast<char*>(
116010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      base::AlignedAlloc(estimated_size, MessageInTransit::kMessageAlignment)));
117010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // Entirely clear out the secondary buffer, since then we won't have to worry
118010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // about clearing padding or unused space (e.g., if a dispatcher fails to
119010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // serialize).
120010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  memset(buffer_.get(), 0, estimated_size);
121010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
1220de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  if (estimated_num_platform_handles > 0) {
123010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    DCHECK(!platform_handles_);
124cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    platform_handles_.reset(new embedder::PlatformHandleVector());
125010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
126010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
127010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  Header* header = reinterpret_cast<Header*>(buffer_.get());
128010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  header->num_handles = static_cast<uint32_t>(num_handles);
1290de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  // (Okay to leave |platform_handle_table_offset|, |num_platform_handles|, and
1300de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  // |unused| be zero; we'll set the former two later if necessary.)
131010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
132010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  HandleTableEntry* handle_table = reinterpret_cast<HandleTableEntry*>(
133010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      buffer_.get() + handle_table_start_offset);
134010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  size_t current_offset = serialized_dispatcher_start_offset;
135010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  for (size_t i = 0; i < num_handles; i++) {
136010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    Dispatcher* dispatcher = (*dispatchers)[i].get();
137010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    if (!dispatcher) {
1381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      static_assert(Dispatcher::kTypeUnknown == 0,
1391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                    "Value of Dispatcher::kTypeUnknown must be 0");
140010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      continue;
141010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    }
142010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
143010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#if DCHECK_IS_ON
144010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    size_t old_platform_handles_size =
145010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        platform_handles_ ? platform_handles_->size() : 0;
146010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#endif
147010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
148010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    void* destination = buffer_.get() + current_offset;
149010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    size_t actual_size = 0;
150010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    if (Dispatcher::TransportDataAccess::EndSerializeAndClose(
1515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            dispatcher,
1525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            channel,
1535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            destination,
1545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            &actual_size,
155010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)            platform_handles_.get())) {
156010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      handle_table[i].type = static_cast<int32_t>(dispatcher->GetType());
157010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      handle_table[i].offset = static_cast<uint32_t>(current_offset);
158010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      handle_table[i].size = static_cast<uint32_t>(actual_size);
1595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// (Okay to not set |unused| since we cleared the entire buffer.)
160010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
161010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#if DCHECK_IS_ON
162010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      DCHECK_LE(actual_size, all_max_sizes[i]);
1635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      DCHECK_LE(platform_handles_
1645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    ? (platform_handles_->size() - old_platform_handles_size)
1655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    : 0,
166010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                all_max_platform_handles[i]);
167010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#endif
168010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    } else {
169010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      // Nothing to do on failure, since |buffer_| was cleared, and
170010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      // |kTypeUnknown| is zero. The handle was simply closed.
171010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      LOG(ERROR) << "Failed to serialize handle to remote message pipe";
172010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    }
173010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
174010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    current_offset += MessageInTransit::RoundUpMessageAlignment(actual_size);
175010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    DCHECK_LE(current_offset, estimated_size);
176010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    DCHECK_LE(platform_handles_ ? platform_handles_->size() : 0,
1770de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)              estimated_num_platform_handles);
1780de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  }
1790de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
1800de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  if (platform_handles_ && platform_handles_->size() > 0) {
1810de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    header->platform_handle_table_offset =
1820de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)        static_cast<uint32_t>(current_offset);
1830de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    header->num_platform_handles =
1840de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)        static_cast<uint32_t>(platform_handles_->size());
1850de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    current_offset += platform_handles_->size() * size_per_platform_handle;
1860de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    current_offset = MessageInTransit::RoundUpMessageAlignment(current_offset);
187010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
188010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
189010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // There's no aligned realloc, so it's no good way to release unused space (if
190010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // we overshot our estimated space requirements).
191010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  buffer_size_ = current_offset;
192010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
193010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // |dispatchers_| will be destroyed as it goes out of scope.
194010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
195010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
196cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#if defined(OS_POSIX)
197cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)TransportData::TransportData(
198cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    embedder::ScopedPlatformHandleVectorPtr platform_handles)
1995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    : buffer_size_(sizeof(Header)), platform_handles_(platform_handles.Pass()) {
200cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  buffer_.reset(static_cast<char*>(
201cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      base::AlignedAlloc(buffer_size_, MessageInTransit::kMessageAlignment)));
202cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  memset(buffer_.get(), 0, buffer_size_);
203cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
204cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#endif  // defined(OS_POSIX)
205cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
206010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)TransportData::~TransportData() {
207010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
208010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
209010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// static
210cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const char* TransportData::ValidateBuffer(
211cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    size_t serialized_platform_handle_size,
212cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const void* buffer,
213cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    size_t buffer_size) {
214010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  DCHECK(buffer);
215010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  DCHECK_GT(buffer_size, 0u);
216010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
217010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // Always make sure that the buffer size is sane; if it's not, someone's
218010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // messing with us.
219010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (buffer_size < sizeof(Header) || buffer_size > kMaxBufferSize ||
220010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      buffer_size % MessageInTransit::kMessageAlignment != 0)
221010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return "Invalid message secondary buffer size";
222010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
223010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  const Header* header = static_cast<const Header*>(buffer);
224010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  const size_t num_handles = header->num_handles;
225cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
226cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#if !defined(OS_POSIX)
227cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // On POSIX, we send control messages with platform handles (but no handles)
228cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // attached (see the comments for
229cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // |TransportData(embedder::ScopedPlatformHandleVectorPtr)|. (This check isn't
230cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // important security-wise anyway.)
231010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (num_handles == 0)
232010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return "Message has no handles attached, but secondary buffer present";
233cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#endif
234010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
235010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // Sanity-check |num_handles| (before multiplying it against anything).
236010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (num_handles > kMaxMessageNumHandles)
237010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return "Message handle payload too large";
238010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
239010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (buffer_size < sizeof(Header) + num_handles * sizeof(HandleTableEntry))
240010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return "Message secondary buffer too small";
241010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
242cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (header->num_platform_handles == 0) {
243cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // Then |platform_handle_table_offset| should also be zero.
244cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (header->platform_handle_table_offset != 0) {
2455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return "Message has no handles attached, but platform handle table "
2465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)             "present";
247cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
248cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  } else {
249cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // |num_handles| has already been validated, so the multiplication is okay.
250cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (header->num_platform_handles >
2515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        num_handles * kMaxSerializedDispatcherPlatformHandles)
252cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      return "Message has too many platform handles attached";
253cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
254cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    static const char kInvalidPlatformHandleTableOffset[] =
255cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        "Message has invalid platform handle table offset";
256cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // This doesn't check that the platform handle table doesn't alias other
257cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // stuff, but it doesn't matter, since it's all read-only.
258cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (header->platform_handle_table_offset %
2595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            MessageInTransit::kMessageAlignment !=
2605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        0)
261cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      return kInvalidPlatformHandleTableOffset;
262cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
263cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // ">" instead of ">=" since the size per handle may be zero.
264cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (header->platform_handle_table_offset > buffer_size)
265cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      return kInvalidPlatformHandleTableOffset;
266cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
267cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // We already checked |platform_handle_table_offset| and
268cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // |num_platform_handles|, so the addition and multiplication are okay.
269cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (header->platform_handle_table_offset +
270cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            header->num_platform_handles * serialized_platform_handle_size >
2715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        buffer_size)
272cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      return kInvalidPlatformHandleTableOffset;
273cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
274010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
275010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  const HandleTableEntry* handle_table =
276010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      reinterpret_cast<const HandleTableEntry*>(
277010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)          static_cast<const char*>(buffer) + sizeof(Header));
278010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  static const char kInvalidSerializedDispatcher[] =
279010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      "Message contains invalid serialized dispatcher";
280010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  for (size_t i = 0; i < num_handles; i++) {
281010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    size_t offset = handle_table[i].offset;
282010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    if (offset % MessageInTransit::kMessageAlignment != 0)
283010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      return kInvalidSerializedDispatcher;
284010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
285010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    size_t size = handle_table[i].size;
286010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    if (size > kMaxSerializedDispatcherSize || size > buffer_size)
287010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      return kInvalidSerializedDispatcher;
288010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
289010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    // Note: This is an overflow-safe check for |offset + size > buffer_size|
290010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    // (we know that |size <= buffer_size| from the previous check).
291010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    if (offset > buffer_size - size)
292010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      return kInvalidSerializedDispatcher;
293010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
294010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
2951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return nullptr;
296010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
297010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
298010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// static
299cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void TransportData::GetPlatformHandleTable(const void* transport_data_buffer,
300cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                           size_t* num_platform_handles,
301cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                           const void** platform_handle_table) {
302cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(transport_data_buffer);
303cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(num_platform_handles);
304cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(platform_handle_table);
305cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
306cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const Header* header = static_cast<const Header*>(transport_data_buffer);
307cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  *num_platform_handles = header->num_platform_handles;
308cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  *platform_handle_table = static_cast<const char*>(transport_data_buffer) +
3095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                           header->platform_handle_table_offset;
310cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
311cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
312cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// static
313cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)scoped_ptr<DispatcherVector> TransportData::DeserializeDispatchers(
314010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const void* buffer,
315010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    size_t buffer_size,
316cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    embedder::ScopedPlatformHandleVectorPtr platform_handles,
317010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    Channel* channel) {
318010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  DCHECK(buffer);
319010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  DCHECK_GT(buffer_size, 0u);
320010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  DCHECK(channel);
321010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
322010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  const Header* header = static_cast<const Header*>(buffer);
323010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  const size_t num_handles = header->num_handles;
324010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  scoped_ptr<DispatcherVector> dispatchers(new DispatcherVector(num_handles));
325010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
326010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  const HandleTableEntry* handle_table =
327010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      reinterpret_cast<const HandleTableEntry*>(
328010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)          static_cast<const char*>(buffer) + sizeof(Header));
329010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  for (size_t i = 0; i < num_handles; i++) {
330010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    size_t offset = handle_table[i].offset;
331010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    size_t size = handle_table[i].size;
332010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    // Should already have been checked by |ValidateBuffer()|:
333010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    DCHECK_EQ(offset % MessageInTransit::kMessageAlignment, 0u);
334010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    DCHECK_LE(offset, buffer_size);
335010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    DCHECK_LE(offset + size, buffer_size);
336010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
337010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const void* source = static_cast<const char*>(buffer) + offset;
338010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    (*dispatchers)[i] = Dispatcher::TransportDataAccess::Deserialize(
339cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        channel, handle_table[i].type, source, size, platform_handles.get());
340010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
341010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
342010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  return dispatchers.Pass();
343010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
344010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
345010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}  // namespace system
346010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}  // namespace mojo
347