ipc_message.h (15085B)
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 #ifndef CHROME_COMMON_IPC_MESSAGE_H__ 8 #define CHROME_COMMON_IPC_MESSAGE_H__ 9 10 #include "base/basictypes.h" 11 #include "base/pickle.h" 12 #include "mojo/core/ports/user_message.h" 13 #include "mojo/core/ports/port_ref.h" 14 #include "mozilla/TimeStamp.h" 15 #include "mozilla/UniquePtrExtensions.h" 16 #include "mozilla/ipc/ScopedPort.h" 17 #include "nsTArray.h" 18 19 namespace mozilla { 20 21 #ifdef FUZZING_SNAPSHOT 22 namespace fuzzing { 23 class IPCFuzzController; 24 } 25 #endif 26 27 namespace ipc { 28 class MiniTransceiver; 29 } 30 } // namespace mozilla 31 32 namespace IPC { 33 34 //------------------------------------------------------------------------------ 35 36 // Generated by IPDL compiler 37 bool IPCMessageTypeIsSync(uint32_t aMessageType); 38 const char* StringFromIPCMessageType(uint32_t aMessageType); 39 40 class Channel; 41 class Message; 42 class MessageReader; 43 class MessageWriter; 44 struct LogData; 45 46 class Message : public mojo::core::ports::UserMessage, public Pickle { 47 public: 48 static const TypeInfo kUserMessageTypeInfo; 49 50 using routeid_t = int64_t; 51 using msgid_t = uint32_t; 52 using seqno_t = int64_t; 53 54 enum NestedLevel { 55 NOT_NESTED = 1, 56 NESTED_INSIDE_SYNC = 2, 57 NESTED_INSIDE_CPOW = 3 58 }; 59 60 enum PriorityValue { 61 NORMAL_PRIORITY = 0, 62 INPUT_PRIORITY = 1, 63 VSYNC_PRIORITY = 2, 64 MEDIUMHIGH_PRIORITY = 3, 65 CONTROL_PRIORITY = 4, 66 LOW_PRIORITY = 5, 67 }; 68 69 enum MessageCompression { 70 COMPRESSION_NONE, 71 COMPRESSION_ENABLED, 72 COMPRESSION_ALL 73 }; 74 75 enum Sync { 76 SYNC = 0, 77 ASYNC = 1, 78 }; 79 80 enum Constructor { 81 NOT_CONSTRUCTOR = 0, 82 CONSTRUCTOR = 1, 83 }; 84 85 enum Reply { 86 NOT_REPLY = 0, 87 REPLY = 1, 88 }; 89 90 enum LazySend { 91 EAGER_SEND = 0, 92 LAZY_SEND = 1, 93 }; 94 95 // The hard limit of handles or file descriptors allowed in a single message. 96 static constexpr size_t MAX_DESCRIPTORS_PER_MESSAGE = 32767; 97 98 class HeaderFlags { 99 friend class Message; 100 #ifdef FUZZING_SNAPSHOT 101 // IPCFuzzController calls various private API functions on the header. 102 friend class mozilla::fuzzing::IPCFuzzController; 103 #endif 104 105 enum { 106 NESTED_MASK = 0x0003, 107 PRIO_MASK = 0x001C, 108 SYNC_BIT = 0x0020, 109 REPLY_BIT = 0x0040, 110 REPLY_ERROR_BIT = 0x0080, 111 LAZY_SEND_BIT = 0x0100, 112 COMPRESS_BIT = 0x0200, 113 COMPRESSALL_BIT = 0x0400, 114 CONSTRUCTOR_BIT = 0x0800, 115 RELAY_BIT = 0x1000, 116 }; 117 118 public: 119 constexpr HeaderFlags() : mFlags(NOT_NESTED) {} 120 121 explicit constexpr HeaderFlags(NestedLevel level) : mFlags(level) {} 122 123 constexpr HeaderFlags(NestedLevel level, PriorityValue priority, 124 MessageCompression compression, LazySend lazy_send, 125 Constructor constructor, Sync sync, Reply reply) 126 : mFlags(level | (priority << 2) | 127 (compression == COMPRESSION_ENABLED ? COMPRESS_BIT 128 : compression == COMPRESSION_ALL ? COMPRESSALL_BIT 129 : 0) | 130 (lazy_send == LAZY_SEND ? LAZY_SEND_BIT : 0) | 131 (constructor == CONSTRUCTOR ? CONSTRUCTOR_BIT : 0) | 132 (sync == SYNC ? SYNC_BIT : 0) | 133 (reply == REPLY ? REPLY_BIT : 0)) {} 134 135 NestedLevel Level() const { 136 return static_cast<NestedLevel>(mFlags & NESTED_MASK); 137 } 138 139 PriorityValue Priority() const { 140 return static_cast<PriorityValue>((mFlags & PRIO_MASK) >> 2); 141 } 142 143 MessageCompression Compression() const { 144 return ((mFlags & COMPRESS_BIT) ? COMPRESSION_ENABLED 145 : (mFlags & COMPRESSALL_BIT) ? COMPRESSION_ALL 146 : COMPRESSION_NONE); 147 } 148 149 bool IsLazySend() const { return (mFlags & LAZY_SEND_BIT) != 0; } 150 151 bool IsConstructor() const { return (mFlags & CONSTRUCTOR_BIT) != 0; } 152 bool IsSync() const { return (mFlags & SYNC_BIT) != 0; } 153 bool IsReply() const { return (mFlags & REPLY_BIT) != 0; } 154 155 bool IsReplyError() const { return (mFlags & REPLY_ERROR_BIT) != 0; } 156 bool IsRelay() const { return (mFlags & RELAY_BIT) != 0; } 157 158 private: 159 void SetConstructor() { mFlags |= CONSTRUCTOR_BIT; } 160 void SetSync() { mFlags |= SYNC_BIT; } 161 void SetReply() { mFlags |= REPLY_BIT; } 162 void SetReplyError() { mFlags |= REPLY_ERROR_BIT; } 163 void SetRelay(bool relay) { 164 if (relay) { 165 mFlags |= RELAY_BIT; 166 } else { 167 mFlags &= ~RELAY_BIT; 168 } 169 } 170 171 uint32_t mFlags; 172 }; 173 174 virtual ~Message(); 175 176 // Initialize a message with a user-defined type, priority value, and 177 // destination WebView ID. 178 Message(routeid_t routing_id, msgid_t type, 179 uint32_t segment_capacity = 0, // 0 for the default capacity. 180 HeaderFlags flags = HeaderFlags()); 181 182 Message(const char* data, int data_len); 183 184 Message(const Message&) = delete; 185 Message(Message&&) = delete; 186 Message& operator=(const Message&) = delete; 187 Message& operator=(Message&&) = delete; 188 189 // Helper method for the common case (default segmentCapacity, recording 190 // the write latency of messages) of IPDL message creation. This helps 191 // move the malloc and some of the parameter setting out of autogenerated 192 // code. 193 static mozilla::UniquePtr<Message> IPDLMessage(routeid_t routing_id, 194 msgid_t type, 195 uint32_t segmentCapacity, 196 HeaderFlags flags); 197 198 // One-off constructors for special error-handling messages. 199 static mozilla::UniquePtr<Message> ForSyncDispatchError(NestedLevel level); 200 201 NestedLevel nested_level() const { return header()->flags.Level(); } 202 203 PriorityValue priority() const { return header()->flags.Priority(); } 204 205 bool is_constructor() const { return header()->flags.IsConstructor(); } 206 207 // True if this is a synchronous message. 208 bool is_sync() const { return header()->flags.IsSync(); } 209 210 MessageCompression compress_type() const { 211 return header()->flags.Compression(); 212 } 213 214 bool is_lazy_send() const { return header()->flags.IsLazySend(); } 215 216 bool is_reply() const { return header()->flags.IsReply(); } 217 218 bool is_reply_error() const { return header()->flags.IsReplyError(); } 219 220 msgid_t type() const { return header()->type; } 221 222 routeid_t routing_id() const { return header()->routing; } 223 224 void set_routing_id(routeid_t new_id) { header()->routing = new_id; } 225 226 seqno_t transaction_id() const { return header()->txid; } 227 228 void set_transaction_id(seqno_t txid) { header()->txid = txid; } 229 230 seqno_t seqno() const { return header()->seqno; } 231 232 void set_seqno(seqno_t aSeqno) { header()->seqno = aSeqno; } 233 234 const char* name() const { return StringFromIPCMessageType(type()); } 235 236 bool has_any_attachments() const; 237 238 uint32_t num_handles() const; 239 240 bool is_relay() const { return header()->flags.IsRelay(); } 241 void set_relay(bool new_relay) { header()->flags.SetRelay(new_relay); } 242 243 template <class T> 244 static bool Dispatch(const Message* msg, T* obj, void (T::*func)()) { 245 (obj->*func)(); 246 return true; 247 } 248 249 template <class T> 250 static bool Dispatch(const Message* msg, T* obj, void (T::*func)() const) { 251 (obj->*func)(); 252 return true; 253 } 254 255 template <class T> 256 static bool Dispatch(const Message* msg, T* obj, 257 void (T::*func)(const Message&)) { 258 (obj->*func)(*msg); 259 return true; 260 } 261 262 template <class T> 263 static bool Dispatch(const Message* msg, T* obj, 264 void (T::*func)(const Message&) const) { 265 (obj->*func)(*msg); 266 return true; 267 } 268 269 // We should not be sending messages that are smaller than our header size. 270 void AssertAsLargeAsHeader() const; 271 272 // UserMessage implementation 273 size_t GetSizeIfSerialized() const override { return size(); } 274 bool WillBeRoutedExternally(mojo::core::ports::UserMessageEvent&) override; 275 276 // Write the given footer bytes to the end of the current message. The 277 // footer's `data_len` will be padded to a multiple of 4 bytes. 278 void WriteFooter(const void* data, uint32_t data_len); 279 // Read a footer written with `WriteFooter` from the end of the message, given 280 // a buffer and the length of the footer. If `truncate` is true, the message 281 // will be truncated, removing the footer. 282 [[nodiscard]] bool ReadFooter(void* buffer, uint32_t buffer_len, 283 bool truncate); 284 285 uint32_t event_footer_size() const { return header()->event_footer_size; } 286 287 void set_event_footer_size(uint32_t size) { 288 header()->event_footer_size = size; 289 } 290 291 static int HeaderSize() { return sizeof(Header); } 292 293 // Figure out how big the message starting at range_start is. Returns 0 if 294 // there's no enough data to determine (i.e., if [range_start, range_end) does 295 // not contain enough of the message header to know the size). 296 static uint32_t MessageSize(const char* range_start, const char* range_end) { 297 return Pickle::MessageSize(HeaderSize(), range_start, range_end); 298 } 299 300 bool WriteFileHandle(mozilla::UniqueFileHandle handle); 301 302 // WARNING: This method is marked as `const` so it can be called when 303 // deserializing the message, but will mutate it, consuming the handle. 304 bool ConsumeFileHandle(PickleIterator* iter, 305 mozilla::UniqueFileHandle* handle) const; 306 307 // Called when receiving an IPC message to attach file handles which were 308 // received from IPC. Must only be called when there are no handles on this 309 // IPC::Message. 310 void SetAttachedFileHandles(nsTArray<mozilla::UniqueFileHandle> handles); 311 312 #if defined(XP_DARWIN) 313 void set_fd_cookie(uint32_t cookie) { header()->cookie = cookie; } 314 uint32_t fd_cookie() const { return header()->cookie; } 315 #endif 316 317 void WritePort(mozilla::ipc::ScopedPort port); 318 319 // This method consumes the port from the message, preventing the message's 320 // destructor from destroying the port and meaning that future attempts to 321 // read this port will instead produce an invalid port. 322 // 323 // WARNING: This method is marked as `const` so it can be called when 324 // deserializing the message, but will mutate the message. 325 bool ConsumePort(PickleIterator* iter, mozilla::ipc::ScopedPort* port) const; 326 327 // Called when loading an IPC message to attach ports which were recieved form 328 // IPC. Must only be called when there are no ports on this IPC::Message. 329 void SetAttachedPorts(nsTArray<mozilla::ipc::ScopedPort> ports); 330 331 #if defined(XP_DARWIN) 332 bool WriteMachSendRight(mozilla::UniqueMachSendRight port); 333 334 // WARNING: This method is marked as `const` so it can be called when 335 // deserializing the message, but will mutate it, consuming the send rights. 336 bool ConsumeMachSendRight(PickleIterator* iter, 337 mozilla::UniqueMachSendRight* port) const; 338 339 uint32_t num_send_rights() const; 340 341 bool WriteMachReceiveRight(mozilla::UniqueMachReceiveRight port); 342 343 // WARNING: This method is marked as `const` so it can be called when 344 // deserializing the message, but will mutate it, consuming the send rights. 345 bool ConsumeMachReceiveRight(PickleIterator* iter, 346 mozilla::UniqueMachReceiveRight* port) const; 347 348 uint32_t num_receive_rights() const; 349 #endif 350 351 #ifdef FUZZING_SNAPSHOT 352 bool IsFuzzMsg() const { return isFuzzMsg; } 353 void SetFuzzMsg() { isFuzzMsg = true; } 354 #endif 355 356 void NoteLargeBufferShmemFailure(uint32_t size) { 357 large_buffer_shmem_failure_size_ += size; 358 } 359 size_t LargeBufferShmemFailureSize() const { 360 return large_buffer_shmem_failure_size_; 361 } 362 363 friend class Channel; 364 friend class ChannelMach; 365 friend class ChannelPosix; 366 friend class ChannelWin; 367 friend class MessageReplyDeserializer; 368 friend class SyncMessage; 369 friend class mozilla::ipc::MiniTransceiver; 370 371 #if !defined(XP_DARWIN) && !defined(FUZZING_SNAPSHOT) 372 protected: 373 #endif 374 375 struct Header : Pickle::Header { 376 // Pickle::Header contains a 32-bit payload_size field 377 msgid_t type; // specifies the user-defined message type 378 HeaderFlags flags; // specifies control flags for the message 379 uint32_t event_footer_size; // Size of the message's event footer 380 381 routeid_t routing; // ID of the view that this message is destined for 382 seqno_t txid; // For sync messages, a transaction ID for message ordering. 383 seqno_t seqno; // Sequence number 384 385 uint32_t num_handles; // the number of handles included with this message 386 #if defined(XP_DARWIN) 387 uint32_t cookie; // cookie to ACK that the descriptors have been read. 388 uint32_t num_send_rights; // the number of mach send rights included with 389 // this message 390 #endif 391 uint32_t _padding; 392 }; 393 static_assert(std::has_unique_object_representations_v<Header>, 394 "Header must not contain padding bytes"); 395 396 Header* header() { return headerT<Header>(); } 397 const Header* header() const { return headerT<Header>(); } 398 399 // The set of file handles which are attached to this message. 400 // 401 // Mutable, as this array can be mutated during `ReadHandle` when 402 // deserializing a message. 403 mutable nsTArray<mozilla::UniqueFileHandle> attached_handles_; 404 405 // The set of mojo ports which are attached to this message. 406 // 407 // Mutable, as this array can be mutated during `ConsumePort` when 408 // deserializing a message. 409 mutable nsTArray<mozilla::ipc::ScopedPort> attached_ports_; 410 411 #if defined(XP_DARWIN) 412 // The set of mach send rights which are attached to this message. 413 // 414 // Mutable, as this array can be mutated during `ConsumeMachSendRight` when 415 // deserializing a message. 416 mutable nsTArray<mozilla::UniqueMachSendRight> attached_send_rights_; 417 418 // The set of mach receive rights which are attached to this message. 419 // 420 // Mutable, as this array can be mutated during `ConsumeMachReceiveRight` when 421 // deserializing a message. 422 mutable nsTArray<mozilla::UniqueMachReceiveRight> attached_receive_rights_; 423 424 // Mach voucher handle. This is kept alive to indicate that this Message is 425 // being processed, which may be used by the system to temporarily boost the 426 // QoS for this process. 427 mozilla::UniqueMachSendRight mach_voucher_; 428 #endif 429 430 // Total size of buffers which should have been sent in shared memory, but had 431 // to fall back to being sent inline due to shmem allocation or mapping 432 // failures. 433 uint32_t large_buffer_shmem_failure_size_ = 0; 434 435 #ifdef FUZZING_SNAPSHOT 436 bool isFuzzMsg = false; 437 #endif 438 }; 439 440 //------------------------------------------------------------------------------ 441 442 } // namespace IPC 443 444 enum SpecialRoutingIDs : IPC::Message::routeid_t { 445 // indicates that we don't have a routing ID yet. 446 MSG_ROUTING_NONE = INT64_MIN, 447 448 // indicates a general message not sent to a particular tab. 449 MSG_ROUTING_CONTROL = INT64_MAX 450 }; 451 452 #endif // CHROME_COMMON_IPC_MESSAGE_H__