ipc_message.cc (7741B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 4 // Use of this source code is governed by a BSD-style license that can be 5 // found in the LICENSE file. 6 7 #include "chrome/common/ipc_message.h" 8 9 #include "base/logging.h" 10 #include "mojo/core/ports/event.h" 11 12 #include <utility> 13 14 #include "nsISupportsImpl.h" 15 16 namespace IPC { 17 18 //------------------------------------------------------------------------------ 19 20 const mojo::core::ports::UserMessage::TypeInfo Message::kUserMessageTypeInfo{}; 21 22 Message::~Message() { MOZ_COUNT_DTOR(IPC::Message); } 23 24 Message::Message(routeid_t routing_id, msgid_t type, uint32_t segment_capacity, 25 HeaderFlags flags) 26 : UserMessage(&kUserMessageTypeInfo), 27 Pickle(sizeof(Header), segment_capacity) { 28 MOZ_COUNT_CTOR(IPC::Message); 29 header()->routing = routing_id; 30 header()->type = type; 31 header()->flags = flags; 32 header()->num_handles = 0; 33 header()->txid = -1; 34 header()->seqno = 0; 35 #if defined(XP_DARWIN) 36 header()->cookie = 0; 37 header()->num_send_rights = 0; 38 #endif 39 header()->event_footer_size = 0; 40 header()->_padding = 0; 41 } 42 43 Message::Message(const char* data, int data_len) 44 : UserMessage(&kUserMessageTypeInfo), 45 Pickle(sizeof(Header), data, data_len) { 46 MOZ_COUNT_CTOR(IPC::Message); 47 } 48 49 /*static*/ mozilla::UniquePtr<Message> Message::IPDLMessage( 50 routeid_t routing_id, msgid_t type, uint32_t segment_capacity, 51 HeaderFlags flags) { 52 return mozilla::MakeUnique<Message>(routing_id, type, segment_capacity, 53 flags); 54 } 55 56 /*static*/ mozilla::UniquePtr<Message> Message::ForSyncDispatchError( 57 NestedLevel level) { 58 auto m = mozilla::MakeUnique<Message>(0, 0, 0, HeaderFlags(level)); 59 auto& flags = m->header()->flags; 60 flags.SetSync(); 61 flags.SetReply(); 62 flags.SetReplyError(); 63 return m; 64 } 65 66 void Message::WriteFooter(const void* data, uint32_t data_len) { 67 if (data_len == 0) { 68 return; 69 } 70 71 WriteBytes(data, data_len); 72 } 73 74 bool Message::ReadFooter(void* buffer, uint32_t buffer_len, bool truncate) { 75 if (buffer_len == 0) { 76 return true; 77 } 78 79 if (NS_WARN_IF(AlignInt(header()->payload_size) != header()->payload_size) || 80 NS_WARN_IF(AlignInt(buffer_len) > header()->payload_size)) { 81 return false; 82 } 83 84 // Seek to the start of the footer, and read it in. We read in with a 85 // duplicate of the iterator so we can use it to truncate later. 86 uint32_t offset = header()->payload_size - AlignInt(buffer_len); 87 PickleIterator footer_iter(*this); 88 if (NS_WARN_IF(!IgnoreBytes(&footer_iter, offset))) { 89 return false; 90 } 91 92 PickleIterator read_iter(footer_iter); 93 bool ok = ReadBytesInto(&read_iter, buffer, buffer_len); 94 95 // If requested, truncate the buffer to the start of the footer. 96 if (truncate) { 97 Truncate(&footer_iter); 98 } 99 return ok; 100 } 101 102 bool Message::WriteFileHandle(mozilla::UniqueFileHandle handle) { 103 uint32_t handle_index = attached_handles_.Length(); 104 WriteUInt32(handle_index); 105 if (handle_index == MAX_DESCRIPTORS_PER_MESSAGE) { 106 return false; 107 } 108 attached_handles_.AppendElement(std::move(handle)); 109 return true; 110 } 111 112 bool Message::ConsumeFileHandle(PickleIterator* iter, 113 mozilla::UniqueFileHandle* handle) const { 114 uint32_t handle_index; 115 if (!ReadUInt32(iter, &handle_index)) { 116 return false; 117 } 118 if (handle_index >= attached_handles_.Length()) { 119 return false; 120 } 121 // NOTE: This mutates the underlying array, replacing the handle with an 122 // invalid handle. 123 *handle = std::exchange(attached_handles_[handle_index], nullptr); 124 return true; 125 } 126 127 void Message::SetAttachedFileHandles( 128 nsTArray<mozilla::UniqueFileHandle> handles) { 129 MOZ_DIAGNOSTIC_ASSERT(attached_handles_.IsEmpty()); 130 attached_handles_ = std::move(handles); 131 } 132 133 bool Message::has_any_attachments() const { 134 return !attached_ports_.IsEmpty() || !attached_handles_.IsEmpty() 135 #if defined(XP_DARWIN) 136 || !attached_send_rights_.IsEmpty() || 137 !attached_receive_rights_.IsEmpty() 138 #endif 139 ; 140 } 141 142 uint32_t Message::num_handles() const { return attached_handles_.Length(); } 143 144 void Message::WritePort(mozilla::ipc::ScopedPort port) { 145 uint32_t port_index = attached_ports_.Length(); 146 WriteUInt32(port_index); 147 attached_ports_.AppendElement(std::move(port)); 148 } 149 150 bool Message::ConsumePort(PickleIterator* iter, 151 mozilla::ipc::ScopedPort* port) const { 152 uint32_t port_index; 153 if (!ReadUInt32(iter, &port_index)) { 154 return false; 155 } 156 if (port_index >= attached_ports_.Length()) { 157 return false; 158 } 159 // NOTE: This mutates the underlying array, replacing the port with a consumed 160 // port. 161 *port = std::exchange(attached_ports_[port_index], {}); 162 return true; 163 } 164 165 void Message::SetAttachedPorts(nsTArray<mozilla::ipc::ScopedPort> ports) { 166 MOZ_DIAGNOSTIC_ASSERT(attached_ports_.IsEmpty()); 167 attached_ports_ = std::move(ports); 168 } 169 170 #if defined(XP_DARWIN) 171 bool Message::WriteMachSendRight(mozilla::UniqueMachSendRight port) { 172 uint32_t index = attached_send_rights_.Length(); 173 WriteUInt32(index); 174 if (index == MAX_DESCRIPTORS_PER_MESSAGE) { 175 return false; 176 } 177 attached_send_rights_.AppendElement(std::move(port)); 178 return true; 179 } 180 181 bool Message::ConsumeMachSendRight(PickleIterator* iter, 182 mozilla::UniqueMachSendRight* port) const { 183 uint32_t index; 184 if (!ReadUInt32(iter, &index)) { 185 return false; 186 } 187 if (index >= attached_send_rights_.Length()) { 188 return false; 189 } 190 // NOTE: This mutates the underlying array, replacing the send right with a 191 // null right. 192 *port = std::exchange(attached_send_rights_[index], nullptr); 193 return true; 194 } 195 196 uint32_t Message::num_send_rights() const { 197 return attached_send_rights_.Length(); 198 } 199 200 bool Message::WriteMachReceiveRight(mozilla::UniqueMachReceiveRight port) { 201 uint32_t index = attached_receive_rights_.Length(); 202 WriteUInt32(index); 203 if (index == MAX_DESCRIPTORS_PER_MESSAGE) { 204 return false; 205 } 206 attached_receive_rights_.AppendElement(std::move(port)); 207 return true; 208 } 209 210 bool Message::ConsumeMachReceiveRight( 211 PickleIterator* iter, mozilla::UniqueMachReceiveRight* port) const { 212 uint32_t index; 213 if (!ReadUInt32(iter, &index)) { 214 return false; 215 } 216 if (index >= attached_receive_rights_.Length()) { 217 return false; 218 } 219 // NOTE: This mutates the underlying array, replacing the receive right with a 220 // null right. 221 *port = std::exchange(attached_receive_rights_[index], nullptr); 222 return true; 223 } 224 225 uint32_t Message::num_receive_rights() const { 226 return attached_receive_rights_.Length(); 227 } 228 #endif 229 230 bool Message::WillBeRoutedExternally( 231 mojo::core::ports::UserMessageEvent& event) { 232 if (!attached_ports_.IsEmpty()) { 233 // Explicitly attach any ports which were attached to this Message to this 234 // UserMessageEvent before we route it externally so that they can be 235 // transferred correctly. These ports will be recovered if needed in 236 // `GetMessage`. 237 MOZ_DIAGNOSTIC_ASSERT( 238 event.num_ports() == 0, 239 "Must not have previously attached ports to the UserMessageEvent"); 240 event.ReservePorts(attached_ports_.Length()); 241 for (size_t i = 0; i < event.num_ports(); ++i) { 242 event.ports()[i] = attached_ports_[i].Release().name(); 243 } 244 attached_ports_.Clear(); 245 } 246 return true; 247 } 248 249 void Message::AssertAsLargeAsHeader() const { 250 MOZ_DIAGNOSTIC_ASSERT(size() >= sizeof(Header)); 251 MOZ_DIAGNOSTIC_ASSERT(CurrentSize() >= sizeof(Header)); 252 // Our buffers should agree with what our header specifies. 253 MOZ_DIAGNOSTIC_ASSERT(size() == CurrentSize()); 254 } 255 256 } // namespace IPC