// Copyright (c) 2012 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. #ifndef IPC_IPC_MESSAGE_H_ #define IPC_IPC_MESSAGE_H_ #include <stddef.h> #include <stdint.h> #include <string> #include "base/gtest_prod_util.h" #include "base/memory/ref_counted.h" #include "base/pickle.h" #include "base/trace_event/trace_event.h" #include "build/build_config.h" #include "ipc/ipc_export.h" #if !defined(NDEBUG) #define IPC_MESSAGE_LOG_ENABLED #endif namespace IPC { namespace internal { class ChannelReader; } // namespace internal //------------------------------------------------------------------------------ struct LogData; class MessageAttachmentSet; class IPC_EXPORT Message : public base::Pickle { public: enum PriorityValue { PRIORITY_LOW = 1, PRIORITY_NORMAL, PRIORITY_HIGH }; // Bit values used in the flags field. // Upper 24 bits of flags store a reference number, so this enum is limited to // 8 bits. enum { PRIORITY_MASK = 0x03, // Low 2 bits of store the priority value. SYNC_BIT = 0x04, REPLY_BIT = 0x08, REPLY_ERROR_BIT = 0x10, UNBLOCK_BIT = 0x20, PUMPING_MSGS_BIT = 0x40, HAS_SENT_TIME_BIT = 0x80, }; ~Message() override; Message(); // Initialize a message with a user-defined type, priority value, and // destination WebView ID. Message(int32_t routing_id, uint32_t type, PriorityValue priority); // Initializes a message from a const block of data. The data is not copied; // instead the data is merely referenced by this message. Only const methods // should be used on the message when initialized this way. Message(const char* data, int data_len); Message(const Message& other); Message& operator=(const Message& other); PriorityValue priority() const { return static_cast<PriorityValue>(header()->flags & PRIORITY_MASK); } // True if this is a synchronous message. void set_sync() { header()->flags |= SYNC_BIT; } bool is_sync() const { return (header()->flags & SYNC_BIT) != 0; } // Set this on a reply to a synchronous message. void set_reply() { header()->flags |= REPLY_BIT; } bool is_reply() const { return (header()->flags & REPLY_BIT) != 0; } // Set this on a reply to a synchronous message to indicate that no receiver // was found. void set_reply_error() { header()->flags |= REPLY_ERROR_BIT; } bool is_reply_error() const { return (header()->flags & REPLY_ERROR_BIT) != 0; } // Normally when a receiver gets a message and they're blocked on a // synchronous message Send, they buffer a message. Setting this flag causes // the receiver to be unblocked and the message to be dispatched immediately. void set_unblock(bool unblock) { if (unblock) { header()->flags |= UNBLOCK_BIT; } else { header()->flags &= ~UNBLOCK_BIT; } } bool should_unblock() const { return (header()->flags & UNBLOCK_BIT) != 0; } // Tells the receiver that the caller is pumping messages while waiting // for the result. bool is_caller_pumping_messages() const { return (header()->flags & PUMPING_MSGS_BIT) != 0; } void set_dispatch_error() const { dispatch_error_ = true; } bool dispatch_error() const { return dispatch_error_; } uint32_t type() const { return header()->type; } int32_t routing_id() const { return header()->routing; } void set_routing_id(int32_t new_id) { header()->routing = new_id; } uint32_t flags() const { return header()->flags; } // Sets all the given header values. The message should be empty at this // call. void SetHeaderValues(int32_t routing, uint32_t type, uint32_t flags); template<class T, class S, class P> static bool Dispatch(const Message* msg, T* obj, S* sender, P* parameter, void (T::*func)()) { (obj->*func)(); return true; } template<class T, class S, class P> static bool Dispatch(const Message* msg, T* obj, S* sender, P* parameter, void (T::*func)(P*)) { (obj->*func)(parameter); return true; } // Used for async messages with no parameters. static void Log(std::string* name, const Message* msg, std::string* l) { } // The static method FindNext() returns several pieces of information, which // are aggregated into an instance of this struct. struct IPC_EXPORT NextMessageInfo { NextMessageInfo(); ~NextMessageInfo(); // Total message size. Always valid if |message_found| is true. // If |message_found| is false but we could determine message size // from the header, this field is non-zero. Otherwise it's zero. size_t message_size; // Whether an entire message was found in the given memory range. bool message_found; // Only filled in if |message_found| is true. // The start address is passed into FindNext() by the caller, so isn't // repeated in this struct. The end address of the pickle should be used to // construct a base::Pickle. const char* pickle_end; // Only filled in if |message_found| is true. // The end address of the message should be used to determine the start // address of the next message. const char* message_end; }; // |info| is an output parameter and must not be nullptr. static void FindNext(const char* range_start, const char* range_end, NextMessageInfo* info); // WriteAttachment appends |attachment| to the end of the set. It returns // false iff the set is full. bool WriteAttachment( scoped_refptr<base::Pickle::Attachment> attachment) override; // ReadAttachment parses an attachment given the parsing state |iter| and // writes it to |*attachment|. It returns true on success. bool ReadAttachment( base::PickleIterator* iter, scoped_refptr<base::Pickle::Attachment>* attachment) const override; // Returns true if there are any attachment in this message. bool HasAttachments() const override; #ifdef IPC_MESSAGE_LOG_ENABLED // Adds the outgoing time from Time::Now() at the end of the message and sets // a bit to indicate that it's been added. void set_sent_time(int64_t time); int64_t sent_time() const; void set_received_time(int64_t time) const; int64_t received_time() const { return received_time_; } void set_output_params(const std::string& op) const { output_params_ = op; } const std::string& output_params() const { return output_params_; } // The following four functions are needed so we can log sync messages with // delayed replies. We stick the log data from the sent message into the // reply message, so that when it's sent and we have the output parameters // we can log it. As such, we set a flag on the sent message to not log it. void set_sync_log_data(LogData* data) const { log_data_ = data; } LogData* sync_log_data() const { return log_data_; } void set_dont_log() const { dont_log_ = true; } bool dont_log() const { return dont_log_; } #endif protected: friend class Channel; friend class ChannelMojo; friend class ChannelNacl; friend class ChannelPosix; friend class ChannelWin; friend class internal::ChannelReader; friend class MessageReplyDeserializer; friend class SyncMessage; #pragma pack(push, 4) struct Header : base::Pickle::Header { int32_t routing; // ID of the view that this message is destined for uint32_t type; // specifies the user-defined message type uint32_t flags; // specifies control flags for the message #if defined(OS_POSIX) uint16_t num_fds; // the number of descriptors included with this message uint16_t pad; // explicitly initialize this to appease valgrind #endif }; #pragma pack(pop) Header* header() { return headerT<Header>(); } const Header* header() const { return headerT<Header>(); } void Init(); // Used internally to support IPC::Listener::OnBadMessageReceived. mutable bool dispatch_error_; // The set of file descriptors associated with this message. scoped_refptr<MessageAttachmentSet> attachment_set_; // Ensure that a MessageAttachmentSet is allocated void EnsureMessageAttachmentSet(); MessageAttachmentSet* attachment_set() { EnsureMessageAttachmentSet(); return attachment_set_.get(); } const MessageAttachmentSet* attachment_set() const { return attachment_set_.get(); } #ifdef IPC_MESSAGE_LOG_ENABLED // Used for logging. mutable int64_t received_time_; mutable std::string output_params_; mutable LogData* log_data_; mutable bool dont_log_; #endif FRIEND_TEST_ALL_PREFIXES(IPCMessageTest, FindNext); FRIEND_TEST_ALL_PREFIXES(IPCMessageTest, FindNextOverflow); }; //------------------------------------------------------------------------------ } // namespace IPC enum SpecialRoutingIDs { // indicates that we don't have a routing ID yet. MSG_ROUTING_NONE = -2, // indicates a general message not sent to a particular tab. MSG_ROUTING_CONTROL = INT32_MAX, }; #define IPC_REPLY_ID 0xFFFFFFF0 // Special message id for replies #define IPC_LOGGING_ID 0xFFFFFFF1 // Special message id for logging #endif // IPC_IPC_MESSAGE_H_