/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ // Copyright (c) 2006-2008 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 "chrome/common/ipc_message.h" #include "base/logging.h" #include "build/build_config.h" #include "mojo/core/ports/event.h" #include #include "nsISupportsImpl.h" namespace IPC { //------------------------------------------------------------------------------ const mojo::core::ports::UserMessage::TypeInfo Message::kUserMessageTypeInfo{}; Message::~Message() { MOZ_COUNT_DTOR(IPC::Message); } Message::Message(int32_t routing_id, msgid_t type, uint32_t segment_capacity, HeaderFlags flags) : UserMessage(&kUserMessageTypeInfo), Pickle(sizeof(Header), segment_capacity) { MOZ_COUNT_CTOR(IPC::Message); header()->routing = routing_id; header()->type = type; header()->flags = flags; header()->num_handles = 0; header()->txid = -1; header()->seqno = 0; #if defined(OS_MACOSX) header()->cookie = 0; header()->num_send_rights = 0; #endif header()->event_footer_size = 0; } Message::Message(const char* data, int data_len) : UserMessage(&kUserMessageTypeInfo), Pickle(sizeof(Header), data, data_len) { MOZ_COUNT_CTOR(IPC::Message); } /*static*/ mozilla::UniquePtr Message::IPDLMessage( int32_t routing_id, msgid_t type, uint32_t segment_capacity, HeaderFlags flags) { return mozilla::MakeUnique(routing_id, type, segment_capacity, flags); } /*static*/ mozilla::UniquePtr Message::ForSyncDispatchError( NestedLevel level) { auto m = mozilla::MakeUnique(0, 0, 0, HeaderFlags(level)); auto& flags = m->header()->flags; flags.SetSync(); flags.SetReply(); flags.SetReplyError(); return m; } void Message::WriteFooter(const void* data, uint32_t data_len) { if (data_len == 0) { return; } WriteBytes(data, data_len); } bool Message::ReadFooter(void* buffer, uint32_t buffer_len, bool truncate) { if (buffer_len == 0) { return true; } if (NS_WARN_IF(AlignInt(header()->payload_size) != header()->payload_size) || NS_WARN_IF(AlignInt(buffer_len) > header()->payload_size)) { return false; } // Seek to the start of the footer, and read it in. We read in with a // duplicate of the iterator so we can use it to truncate later. uint32_t offset = header()->payload_size - AlignInt(buffer_len); PickleIterator footer_iter(*this); if (NS_WARN_IF(!IgnoreBytes(&footer_iter, offset))) { return false; } PickleIterator read_iter(footer_iter); bool ok = ReadBytesInto(&read_iter, buffer, buffer_len); // If requested, truncate the buffer to the start of the footer. if (truncate) { Truncate(&footer_iter); } return ok; } bool Message::WriteFileHandle(mozilla::UniqueFileHandle handle) { uint32_t handle_index = attached_handles_.Length(); WriteUInt32(handle_index); if (handle_index == MAX_DESCRIPTORS_PER_MESSAGE) { return false; } attached_handles_.AppendElement(std::move(handle)); return true; } bool Message::ConsumeFileHandle(PickleIterator* iter, mozilla::UniqueFileHandle* handle) const { uint32_t handle_index; if (!ReadUInt32(iter, &handle_index)) { return false; } if (handle_index >= attached_handles_.Length()) { return false; } // NOTE: This mutates the underlying array, replacing the handle with an // invalid handle. *handle = std::exchange(attached_handles_[handle_index], nullptr); return true; } void Message::SetAttachedFileHandles( nsTArray handles) { MOZ_DIAGNOSTIC_ASSERT(attached_handles_.IsEmpty()); attached_handles_ = std::move(handles); } uint32_t Message::num_handles() const { return attached_handles_.Length(); } void Message::WritePort(mozilla::ipc::ScopedPort port) { uint32_t port_index = attached_ports_.Length(); WriteUInt32(port_index); attached_ports_.AppendElement(std::move(port)); } bool Message::ConsumePort(PickleIterator* iter, mozilla::ipc::ScopedPort* port) const { uint32_t port_index; if (!ReadUInt32(iter, &port_index)) { return false; } if (port_index >= attached_ports_.Length()) { return false; } // NOTE: This mutates the underlying array, replacing the port with a consumed // port. *port = std::exchange(attached_ports_[port_index], {}); return true; } void Message::SetAttachedPorts(nsTArray ports) { MOZ_DIAGNOSTIC_ASSERT(attached_ports_.IsEmpty()); attached_ports_ = std::move(ports); } #if defined(OS_MACOSX) bool Message::WriteMachSendRight(mozilla::UniqueMachSendRight port) { uint32_t index = attached_send_rights_.Length(); WriteUInt32(index); if (index == MAX_DESCRIPTORS_PER_MESSAGE) { return false; } attached_send_rights_.AppendElement(std::move(port)); return true; } bool Message::ConsumeMachSendRight(PickleIterator* iter, mozilla::UniqueMachSendRight* port) const { uint32_t index; if (!ReadUInt32(iter, &index)) { return false; } if (index >= attached_send_rights_.Length()) { return false; } // NOTE: This mutates the underlying array, replacing the send right with a // null right. *port = std::exchange(attached_send_rights_[index], nullptr); return true; } uint32_t Message::num_send_rights() const { return attached_send_rights_.Length(); } #endif bool Message::WillBeRoutedExternally( mojo::core::ports::UserMessageEvent& event) { if (!attached_ports_.IsEmpty()) { // Explicitly attach any ports which were attached to this Message to this // UserMessageEvent before we route it externally so that they can be // transferred correctly. These ports will be recovered if needed in // `GetMessage`. MOZ_DIAGNOSTIC_ASSERT( event.num_ports() == 0, "Must not have previously attached ports to the UserMessageEvent"); event.ReservePorts(attached_ports_.Length()); for (size_t i = 0; i < event.num_ports(); ++i) { event.ports()[i] = attached_ports_[i].Release().name(); } attached_ports_.Clear(); } return true; } void Message::AssertAsLargeAsHeader() const { MOZ_DIAGNOSTIC_ASSERT(size() >= sizeof(Header)); MOZ_DIAGNOSTIC_ASSERT(CurrentSize() >= sizeof(Header)); // Our buffers should agree with what our header specifies. MOZ_DIAGNOSTIC_ASSERT(size() == CurrentSize()); } } // namespace IPC