transport_data.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
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;
250de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)COMPILE_ASSERT(kMaxSizePerPlatformHandle %
265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                       MessageInTransit::kMessageAlignment ==
275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                   0,
280de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)               kMaxSizePerPlatformHandle_not_a_multiple_of_alignment);
290de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
30010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)STATIC_CONST_MEMBER_DEFINITION const size_t
31010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    TransportData::kMaxSerializedDispatcherSize;
32010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)STATIC_CONST_MEMBER_DEFINITION const size_t
33010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    TransportData::kMaxSerializedDispatcherPlatformHandles;
34010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
350de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)// static
360de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)const size_t TransportData::kMaxPlatformHandles =
370de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    kMaxMessageNumHandles * kMaxSerializedDispatcherPlatformHandles;
380de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
39010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// In additional to the header, for each attached (Mojo) handle there'll be a
40010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// handle table entry and serialized dispatcher data.
410de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)// Note: This definition must follow the one for |kMaxPlatformHandles|;
420de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)// otherwise, we get a static initializer with gcc (but not clang).
43010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// static
44010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)const size_t TransportData::kMaxBufferSize =
450de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    sizeof(Header) +
465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    kMaxMessageNumHandles *
475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        (sizeof(HandleTableEntry) + kMaxSerializedDispatcherSize) +
480de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    kMaxPlatformHandles * kMaxSizePerPlatformHandle;
49010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
50010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)struct TransportData::PrivateStructForCompileAsserts {
51010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // The size of |Header| must be a multiple of the alignment.
52010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  COMPILE_ASSERT(sizeof(Header) % MessageInTransit::kMessageAlignment == 0,
53010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                 sizeof_MessageInTransit_Header_invalid);
54010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
55010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // The maximum serialized dispatcher size must be a multiple of the alignment.
56010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  COMPILE_ASSERT(kMaxSerializedDispatcherSize %
575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                         MessageInTransit::kMessageAlignment ==
585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                     0,
59010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                 kMaxSerializedDispatcherSize_not_a_multiple_of_alignment);
60010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
61010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // The size of |HandleTableEntry| must be a multiple of the alignment.
62010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  COMPILE_ASSERT(sizeof(HandleTableEntry) %
635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                         MessageInTransit::kMessageAlignment ==
645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                     0,
65010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                 sizeof_MessageInTransit_HandleTableEntry_invalid);
66010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)};
67010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
68010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)TransportData::TransportData(scoped_ptr<DispatcherVector> dispatchers,
69cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                             Channel* channel) {
70010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  DCHECK(dispatchers);
71010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  DCHECK(channel);
72010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
73010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  const size_t num_handles = dispatchers->size();
74010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  DCHECK_GT(num_handles, 0u);
75010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
76010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // The offset to the start of the (Mojo) handle table.
77010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  const size_t handle_table_start_offset = sizeof(Header);
78010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // The offset to the start of the serialized dispatcher data.
79010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  const size_t serialized_dispatcher_start_offset =
80010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      handle_table_start_offset + num_handles * sizeof(HandleTableEntry);
81010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // The estimated size of the secondary buffer. We compute this estimate below.
82010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // It must be at least as big as the (eventual) actual size.
83010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  size_t estimated_size = serialized_dispatcher_start_offset;
840de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  size_t estimated_num_platform_handles = 0;
85010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#if DCHECK_IS_ON
86010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  std::vector<size_t> all_max_sizes(num_handles);
87010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  std::vector<size_t> all_max_platform_handles(num_handles);
88010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#endif
89010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  for (size_t i = 0; i < num_handles; i++) {
90010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    if (Dispatcher* dispatcher = (*dispatchers)[i].get()) {
91010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      size_t max_size = 0;
92010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      size_t max_platform_handles = 0;
93010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      Dispatcher::TransportDataAccess::StartSerialize(
945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          dispatcher, channel, &max_size, &max_platform_handles);
95010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
96010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      DCHECK_LE(max_size, kMaxSerializedDispatcherSize);
97010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      estimated_size += MessageInTransit::RoundUpMessageAlignment(max_size);
98010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      DCHECK_LE(estimated_size, kMaxBufferSize);
99010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
1005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      DCHECK_LE(max_platform_handles, kMaxSerializedDispatcherPlatformHandles);
1010de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)      estimated_num_platform_handles += max_platform_handles;
1020de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)      DCHECK_LE(estimated_num_platform_handles, kMaxPlatformHandles);
103010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
104010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#if DCHECK_IS_ON
105010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      all_max_sizes[i] = max_size;
106010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      all_max_platform_handles[i] = max_platform_handles;
107010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#endif
108010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    }
109010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
110010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
1110de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  size_t size_per_platform_handle = 0;
1120de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  if (estimated_num_platform_handles > 0) {
1130de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    size_per_platform_handle = channel->GetSerializedPlatformHandleSize();
1140de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    DCHECK_LE(size_per_platform_handle, kMaxSizePerPlatformHandle);
1150de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    estimated_size += estimated_num_platform_handles * size_per_platform_handle;
1160de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    estimated_size = MessageInTransit::RoundUpMessageAlignment(estimated_size);
1170de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    DCHECK_LE(estimated_size, kMaxBufferSize);
1180de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  }
1190de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
120010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  buffer_.reset(static_cast<char*>(
121010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      base::AlignedAlloc(estimated_size, MessageInTransit::kMessageAlignment)));
122010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // Entirely clear out the secondary buffer, since then we won't have to worry
123010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // about clearing padding or unused space (e.g., if a dispatcher fails to
124010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // serialize).
125010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  memset(buffer_.get(), 0, estimated_size);
126010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
1270de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  if (estimated_num_platform_handles > 0) {
128010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    DCHECK(!platform_handles_);
129cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    platform_handles_.reset(new embedder::PlatformHandleVector());
130010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
131010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
132010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  Header* header = reinterpret_cast<Header*>(buffer_.get());
133010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  header->num_handles = static_cast<uint32_t>(num_handles);
1340de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  // (Okay to leave |platform_handle_table_offset|, |num_platform_handles|, and
1350de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  // |unused| be zero; we'll set the former two later if necessary.)
136010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
137010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  HandleTableEntry* handle_table = reinterpret_cast<HandleTableEntry*>(
138010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      buffer_.get() + handle_table_start_offset);
139010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  size_t current_offset = serialized_dispatcher_start_offset;
140010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  for (size_t i = 0; i < num_handles; i++) {
141010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    Dispatcher* dispatcher = (*dispatchers)[i].get();
142010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    if (!dispatcher) {
143010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      COMPILE_ASSERT(Dispatcher::kTypeUnknown == 0,
144010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                     value_of_Dispatcher_kTypeUnknown_must_be_zero);
145010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      continue;
146010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    }
147010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
148010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#if DCHECK_IS_ON
149010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    size_t old_platform_handles_size =
150010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        platform_handles_ ? platform_handles_->size() : 0;
151010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#endif
152010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
153010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    void* destination = buffer_.get() + current_offset;
154010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    size_t actual_size = 0;
155010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    if (Dispatcher::TransportDataAccess::EndSerializeAndClose(
1565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            dispatcher,
1575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            channel,
1585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            destination,
1595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            &actual_size,
160010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)            platform_handles_.get())) {
161010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      handle_table[i].type = static_cast<int32_t>(dispatcher->GetType());
162010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      handle_table[i].offset = static_cast<uint32_t>(current_offset);
163010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      handle_table[i].size = static_cast<uint32_t>(actual_size);
1645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// (Okay to not set |unused| since we cleared the entire buffer.)
165010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
166010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#if DCHECK_IS_ON
167010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      DCHECK_LE(actual_size, all_max_sizes[i]);
1685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      DCHECK_LE(platform_handles_
1695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    ? (platform_handles_->size() - old_platform_handles_size)
1705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    : 0,
171010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                all_max_platform_handles[i]);
172010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#endif
173010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    } else {
174010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      // Nothing to do on failure, since |buffer_| was cleared, and
175010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      // |kTypeUnknown| is zero. The handle was simply closed.
176010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      LOG(ERROR) << "Failed to serialize handle to remote message pipe";
177010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    }
178010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
179010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    current_offset += MessageInTransit::RoundUpMessageAlignment(actual_size);
180010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    DCHECK_LE(current_offset, estimated_size);
181010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    DCHECK_LE(platform_handles_ ? platform_handles_->size() : 0,
1820de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)              estimated_num_platform_handles);
1830de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  }
1840de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
1850de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  if (platform_handles_ && platform_handles_->size() > 0) {
1860de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    header->platform_handle_table_offset =
1870de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)        static_cast<uint32_t>(current_offset);
1880de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    header->num_platform_handles =
1890de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)        static_cast<uint32_t>(platform_handles_->size());
1900de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    current_offset += platform_handles_->size() * size_per_platform_handle;
1910de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    current_offset = MessageInTransit::RoundUpMessageAlignment(current_offset);
192010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
193010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
194010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // There's no aligned realloc, so it's no good way to release unused space (if
195010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // we overshot our estimated space requirements).
196010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  buffer_size_ = current_offset;
197010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
198010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // |dispatchers_| will be destroyed as it goes out of scope.
199010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
200010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
201cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#if defined(OS_POSIX)
202cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)TransportData::TransportData(
203cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    embedder::ScopedPlatformHandleVectorPtr platform_handles)
2045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    : buffer_size_(sizeof(Header)), platform_handles_(platform_handles.Pass()) {
205cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  buffer_.reset(static_cast<char*>(
206cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      base::AlignedAlloc(buffer_size_, MessageInTransit::kMessageAlignment)));
207cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  memset(buffer_.get(), 0, buffer_size_);
208cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
209cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#endif  // defined(OS_POSIX)
210cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
211010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)TransportData::~TransportData() {
212010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
213010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
214010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// static
215cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const char* TransportData::ValidateBuffer(
216cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    size_t serialized_platform_handle_size,
217cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const void* buffer,
218cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    size_t buffer_size) {
219010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  DCHECK(buffer);
220010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  DCHECK_GT(buffer_size, 0u);
221010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
222010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // Always make sure that the buffer size is sane; if it's not, someone's
223010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // messing with us.
224010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (buffer_size < sizeof(Header) || buffer_size > kMaxBufferSize ||
225010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      buffer_size % MessageInTransit::kMessageAlignment != 0)
226010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return "Invalid message secondary buffer size";
227010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
228010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  const Header* header = static_cast<const Header*>(buffer);
229010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  const size_t num_handles = header->num_handles;
230cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
231cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#if !defined(OS_POSIX)
232cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // On POSIX, we send control messages with platform handles (but no handles)
233cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // attached (see the comments for
234cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // |TransportData(embedder::ScopedPlatformHandleVectorPtr)|. (This check isn't
235cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // important security-wise anyway.)
236010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (num_handles == 0)
237010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return "Message has no handles attached, but secondary buffer present";
238cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#endif
239010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
240010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // Sanity-check |num_handles| (before multiplying it against anything).
241010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (num_handles > kMaxMessageNumHandles)
242010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return "Message handle payload too large";
243010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
244010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (buffer_size < sizeof(Header) + num_handles * sizeof(HandleTableEntry))
245010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return "Message secondary buffer too small";
246010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
247cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (header->num_platform_handles == 0) {
248cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // Then |platform_handle_table_offset| should also be zero.
249cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (header->platform_handle_table_offset != 0) {
2505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return "Message has no handles attached, but platform handle table "
2515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)             "present";
252cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
253cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  } else {
254cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // |num_handles| has already been validated, so the multiplication is okay.
255cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (header->num_platform_handles >
2565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        num_handles * kMaxSerializedDispatcherPlatformHandles)
257cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      return "Message has too many platform handles attached";
258cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
259cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    static const char kInvalidPlatformHandleTableOffset[] =
260cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        "Message has invalid platform handle table offset";
261cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // This doesn't check that the platform handle table doesn't alias other
262cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // stuff, but it doesn't matter, since it's all read-only.
263cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (header->platform_handle_table_offset %
2645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            MessageInTransit::kMessageAlignment !=
2655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        0)
266cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      return kInvalidPlatformHandleTableOffset;
267cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
268cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // ">" instead of ">=" since the size per handle may be zero.
269cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (header->platform_handle_table_offset > buffer_size)
270cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      return kInvalidPlatformHandleTableOffset;
271cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
272cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // We already checked |platform_handle_table_offset| and
273cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // |num_platform_handles|, so the addition and multiplication are okay.
274cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (header->platform_handle_table_offset +
275cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            header->num_platform_handles * serialized_platform_handle_size >
2765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        buffer_size)
277cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      return kInvalidPlatformHandleTableOffset;
278cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
279010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
280010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  const HandleTableEntry* handle_table =
281010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      reinterpret_cast<const HandleTableEntry*>(
282010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)          static_cast<const char*>(buffer) + sizeof(Header));
283010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  static const char kInvalidSerializedDispatcher[] =
284010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      "Message contains invalid serialized dispatcher";
285010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  for (size_t i = 0; i < num_handles; i++) {
286010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    size_t offset = handle_table[i].offset;
287010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    if (offset % MessageInTransit::kMessageAlignment != 0)
288010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      return kInvalidSerializedDispatcher;
289010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
290010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    size_t size = handle_table[i].size;
291010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    if (size > kMaxSerializedDispatcherSize || size > buffer_size)
292010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      return kInvalidSerializedDispatcher;
293010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
294010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    // Note: This is an overflow-safe check for |offset + size > buffer_size|
295010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    // (we know that |size <= buffer_size| from the previous check).
296010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    if (offset > buffer_size - size)
297010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      return kInvalidSerializedDispatcher;
298010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
299010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
300010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  return NULL;
301010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
302010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
303010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// static
304cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void TransportData::GetPlatformHandleTable(const void* transport_data_buffer,
305cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                           size_t* num_platform_handles,
306cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                           const void** platform_handle_table) {
307cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(transport_data_buffer);
308cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(num_platform_handles);
309cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(platform_handle_table);
310cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
311cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const Header* header = static_cast<const Header*>(transport_data_buffer);
312cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  *num_platform_handles = header->num_platform_handles;
313cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  *platform_handle_table = static_cast<const char*>(transport_data_buffer) +
3145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                           header->platform_handle_table_offset;
315cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
316cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
317cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// static
318cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)scoped_ptr<DispatcherVector> TransportData::DeserializeDispatchers(
319010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const void* buffer,
320010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    size_t buffer_size,
321cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    embedder::ScopedPlatformHandleVectorPtr platform_handles,
322010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    Channel* channel) {
323010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  DCHECK(buffer);
324010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  DCHECK_GT(buffer_size, 0u);
325010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  DCHECK(channel);
326010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
327010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  const Header* header = static_cast<const Header*>(buffer);
328010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  const size_t num_handles = header->num_handles;
329010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  scoped_ptr<DispatcherVector> dispatchers(new DispatcherVector(num_handles));
330010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
331010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  const HandleTableEntry* handle_table =
332010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      reinterpret_cast<const HandleTableEntry*>(
333010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)          static_cast<const char*>(buffer) + sizeof(Header));
334010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  for (size_t i = 0; i < num_handles; i++) {
335010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    size_t offset = handle_table[i].offset;
336010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    size_t size = handle_table[i].size;
337010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    // Should already have been checked by |ValidateBuffer()|:
338010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    DCHECK_EQ(offset % MessageInTransit::kMessageAlignment, 0u);
339010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    DCHECK_LE(offset, buffer_size);
340010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    DCHECK_LE(offset + size, buffer_size);
341010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
342010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const void* source = static_cast<const char*>(buffer) + offset;
343010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    (*dispatchers)[i] = Dispatcher::TransportDataAccess::Deserialize(
344cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        channel, handle_table[i].type, source, size, platform_handles.get());
345010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
346010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
347010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  return dispatchers.Pass();
348010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
349010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
350010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}  // namespace system
351010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}  // namespace mojo
352