// Copyright 2016 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "mojo/edk/system/message_for_transit.h" #include <vector> #include "mojo/edk/embedder/platform_handle_vector.h" namespace mojo { namespace edk { namespace { static_assert(sizeof(MessageForTransit::MessageHeader) % 8 == 0, "Invalid MessageHeader size."); static_assert(sizeof(MessageForTransit::DispatcherHeader) % 8 == 0, "Invalid DispatcherHeader size."); } // namespace MessageForTransit::~MessageForTransit() {} // static MojoResult MessageForTransit::Create( std::unique_ptr<MessageForTransit>* message, uint32_t num_bytes, const Dispatcher::DispatcherInTransit* dispatchers, uint32_t num_dispatchers) { // A structure for retaining information about every Dispatcher that will be // sent with this message. struct DispatcherInfo { uint32_t num_bytes; uint32_t num_ports; uint32_t num_handles; }; // This is only the base header size. It will grow as we accumulate the // size of serialized state for each dispatcher. size_t header_size = sizeof(MessageHeader) + num_dispatchers * sizeof(DispatcherHeader); size_t num_ports = 0; size_t num_handles = 0; std::vector<DispatcherInfo> dispatcher_info(num_dispatchers); for (size_t i = 0; i < num_dispatchers; ++i) { Dispatcher* d = dispatchers[i].dispatcher.get(); d->StartSerialize(&dispatcher_info[i].num_bytes, &dispatcher_info[i].num_ports, &dispatcher_info[i].num_handles); header_size += dispatcher_info[i].num_bytes; num_ports += dispatcher_info[i].num_ports; num_handles += dispatcher_info[i].num_handles; } // We now have enough information to fully allocate the message storage. std::unique_ptr<PortsMessage> msg = PortsMessage::NewUserMessage( header_size + num_bytes, num_ports, num_handles); if (!msg) return MOJO_RESULT_RESOURCE_EXHAUSTED; // Populate the message header with information about serialized dispatchers. // // The front of the message is always a MessageHeader followed by a // DispatcherHeader for each dispatcher to be sent. MessageHeader* header = static_cast<MessageHeader*>(msg->mutable_payload_bytes()); DispatcherHeader* dispatcher_headers = reinterpret_cast<DispatcherHeader*>(header + 1); // Serialized dispatcher state immediately follows the series of // DispatcherHeaders. char* dispatcher_data = reinterpret_cast<char*>(dispatcher_headers + num_dispatchers); header->num_dispatchers = num_dispatchers; // |header_size| is the total number of bytes preceding the message payload, // including all dispatcher headers and serialized dispatcher state. DCHECK_LE(header_size, std::numeric_limits<uint32_t>::max()); header->header_size = static_cast<uint32_t>(header_size); if (num_dispatchers > 0) { ScopedPlatformHandleVectorPtr handles( new PlatformHandleVector(num_handles)); size_t port_index = 0; size_t handle_index = 0; bool fail = false; for (size_t i = 0; i < num_dispatchers; ++i) { Dispatcher* d = dispatchers[i].dispatcher.get(); DispatcherHeader* dh = &dispatcher_headers[i]; const DispatcherInfo& info = dispatcher_info[i]; // Fill in the header for this dispatcher. dh->type = static_cast<int32_t>(d->GetType()); dh->num_bytes = info.num_bytes; dh->num_ports = info.num_ports; dh->num_platform_handles = info.num_handles; // Fill in serialized state, ports, and platform handles. We'll cancel // the send if the dispatcher implementation rejects for some reason. if (!d->EndSerialize(static_cast<void*>(dispatcher_data), msg->mutable_ports() + port_index, handles->data() + handle_index)) { fail = true; break; } dispatcher_data += info.num_bytes; port_index += info.num_ports; handle_index += info.num_handles; } if (fail) { // Release any platform handles we've accumulated. Their dispatchers // retain ownership when message creation fails, so these are not actually // leaking. handles->clear(); return MOJO_RESULT_INVALID_ARGUMENT; } // Take ownership of all the handles and move them into message storage. msg->SetHandles(std::move(handles)); } message->reset(new MessageForTransit(std::move(msg))); return MOJO_RESULT_OK; } MessageForTransit::MessageForTransit(std::unique_ptr<PortsMessage> message) : message_(std::move(message)) { } } // namespace edk } // namespace mojo