michael@0: // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. michael@0: // Use of this source code is governed by a BSD-style license that can be michael@0: // found in the LICENSE file. michael@0: michael@0: #ifndef CHROME_COMMON_IPC_MESSAGE_H__ michael@0: #define CHROME_COMMON_IPC_MESSAGE_H__ michael@0: michael@0: #include michael@0: michael@0: #include "base/basictypes.h" michael@0: #include "base/pickle.h" michael@0: michael@0: #ifdef MOZ_TASK_TRACER michael@0: #include "GeckoTaskTracer.h" michael@0: #endif michael@0: michael@0: #ifndef NDEBUG michael@0: #define IPC_MESSAGE_LOG_ENABLED michael@0: #endif michael@0: michael@0: #if defined(OS_POSIX) michael@0: #include "base/ref_counted.h" michael@0: #endif michael@0: michael@0: namespace base { michael@0: struct FileDescriptor; michael@0: } michael@0: michael@0: class FileDescriptorSet; michael@0: michael@0: namespace IPC { michael@0: michael@0: //------------------------------------------------------------------------------ michael@0: michael@0: class Channel; michael@0: class Message; michael@0: struct LogData; michael@0: michael@0: class Message : public Pickle { michael@0: public: michael@0: typedef uint32_t msgid_t; michael@0: michael@0: // Implemented by objects that can send IPC messages across a channel. michael@0: class Sender { michael@0: public: michael@0: virtual ~Sender() {} michael@0: michael@0: // Sends the given IPC message. The implementor takes ownership of the michael@0: // given Message regardless of whether or not this method succeeds. This michael@0: // is done to make this method easier to use. Returns true on success and michael@0: // false otherwise. michael@0: virtual bool Send(Message* msg) = 0; michael@0: }; michael@0: michael@0: enum PriorityValue { michael@0: PRIORITY_LOW = 1, michael@0: PRIORITY_NORMAL, michael@0: PRIORITY_HIGH michael@0: }; michael@0: michael@0: enum MessageCompression { michael@0: COMPRESSION_NONE, michael@0: COMPRESSION_ENABLED michael@0: }; michael@0: michael@0: virtual ~Message(); michael@0: michael@0: Message(); michael@0: michael@0: // Initialize a message with a user-defined type, priority value, and michael@0: // destination WebView ID. michael@0: Message(int32_t routing_id, msgid_t type, PriorityValue priority, michael@0: MessageCompression compression = COMPRESSION_NONE, michael@0: const char* const name="???"); michael@0: michael@0: // Initializes a message from a const block of data. The data is not copied; michael@0: // instead the data is merely referenced by this message. Only const methods michael@0: // should be used on the message when initialized this way. michael@0: Message(const char* data, int data_len); michael@0: michael@0: Message(const Message& other); michael@0: Message& operator=(const Message& other); michael@0: michael@0: PriorityValue priority() const { michael@0: return static_cast(header()->flags & PRIORITY_MASK); michael@0: } michael@0: michael@0: // True if this is a synchronous message. michael@0: bool is_sync() const { michael@0: return (header()->flags & SYNC_BIT) != 0; michael@0: } michael@0: michael@0: // True if this is a synchronous message. michael@0: bool is_interrupt() const { michael@0: return (header()->flags & INTERRUPT_BIT) != 0; michael@0: } michael@0: michael@0: // True if this is an urgent message. michael@0: bool is_urgent() const { michael@0: return (header()->flags & URGENT_BIT) != 0; michael@0: } michael@0: michael@0: // True if this is an RPC message. michael@0: bool is_rpc() const { michael@0: return (header()->flags & RPC_BIT) != 0; michael@0: } michael@0: michael@0: // True if compression is enabled for this message. michael@0: bool compress() const { michael@0: return (header()->flags & COMPRESS_BIT) != 0; michael@0: } michael@0: michael@0: // Set this on a reply to a synchronous message. michael@0: void set_reply() { michael@0: header()->flags |= REPLY_BIT; michael@0: } michael@0: michael@0: bool is_reply() const { michael@0: return (header()->flags & REPLY_BIT) != 0; michael@0: } michael@0: michael@0: // Set this on a reply to a synchronous message to indicate that no receiver michael@0: // was found. michael@0: void set_reply_error() { michael@0: header()->flags |= REPLY_ERROR_BIT; michael@0: } michael@0: michael@0: bool is_reply_error() const { michael@0: return (header()->flags & REPLY_ERROR_BIT) != 0; michael@0: } michael@0: michael@0: // Normally when a receiver gets a message and they're blocked on a michael@0: // synchronous message Send, they buffer a message. Setting this flag causes michael@0: // the receiver to be unblocked and the message to be dispatched immediately. michael@0: void set_unblock(bool unblock) { michael@0: if (unblock) { michael@0: header()->flags |= UNBLOCK_BIT; michael@0: } else { michael@0: header()->flags &= ~UNBLOCK_BIT; michael@0: } michael@0: } michael@0: michael@0: bool should_unblock() const { michael@0: return (header()->flags & UNBLOCK_BIT) != 0; michael@0: } michael@0: michael@0: // Tells the receiver that the caller is pumping messages while waiting michael@0: // for the result. michael@0: bool is_caller_pumping_messages() const { michael@0: return (header()->flags & PUMPING_MSGS_BIT) != 0; michael@0: } michael@0: michael@0: msgid_t type() const { michael@0: return header()->type; michael@0: } michael@0: michael@0: int32_t routing_id() const { michael@0: return header()->routing; michael@0: } michael@0: michael@0: void set_routing_id(int32_t new_id) { michael@0: header()->routing = new_id; michael@0: } michael@0: michael@0: int32_t transaction_id() const { michael@0: return header()->txid; michael@0: } michael@0: michael@0: void set_transaction_id(int32_t txid) { michael@0: header()->txid = txid; michael@0: } michael@0: michael@0: uint32_t interrupt_remote_stack_depth_guess() const { michael@0: return header()->interrupt_remote_stack_depth_guess; michael@0: } michael@0: michael@0: void set_interrupt_remote_stack_depth_guess(uint32_t depth) { michael@0: DCHECK(is_interrupt()); michael@0: header()->interrupt_remote_stack_depth_guess = depth; michael@0: } michael@0: michael@0: uint32_t interrupt_local_stack_depth() const { michael@0: return header()->interrupt_local_stack_depth; michael@0: } michael@0: michael@0: void set_interrupt_local_stack_depth(uint32_t depth) { michael@0: DCHECK(is_interrupt()); michael@0: header()->interrupt_local_stack_depth = depth; michael@0: } michael@0: michael@0: int32_t seqno() const { michael@0: return header()->seqno; michael@0: } michael@0: michael@0: void set_seqno(int32_t seqno) { michael@0: header()->seqno = seqno; michael@0: } michael@0: michael@0: const char* const name() const { michael@0: return name_; michael@0: } michael@0: michael@0: void set_name(const char* const name) { michael@0: name_ = name; michael@0: } michael@0: michael@0: template michael@0: static bool Dispatch(const Message* msg, T* obj, void (T::*func)()) { michael@0: (obj->*func)(); michael@0: return true; michael@0: } michael@0: michael@0: template michael@0: static bool Dispatch(const Message* msg, T* obj, void (T::*func)() const) { michael@0: (obj->*func)(); michael@0: return true; michael@0: } michael@0: michael@0: template michael@0: static bool Dispatch(const Message* msg, T* obj, michael@0: void (T::*func)(const Message&)) { michael@0: (obj->*func)(*msg); michael@0: return true; michael@0: } michael@0: michael@0: template michael@0: static bool Dispatch(const Message* msg, T* obj, michael@0: void (T::*func)(const Message&) const) { michael@0: (obj->*func)(*msg); michael@0: return true; michael@0: } michael@0: michael@0: // Used for async messages with no parameters. michael@0: static void Log(const Message* msg, std::wstring* l) { michael@0: } michael@0: michael@0: // Find the end of the message data that starts at range_start. Returns NULL michael@0: // if the entire message is not found in the given data range. michael@0: static const char* FindNext(const char* range_start, const char* range_end) { michael@0: return Pickle::FindNext(sizeof(Header), range_start, range_end); michael@0: } michael@0: michael@0: #if defined(OS_POSIX) michael@0: // On POSIX, a message supports reading / writing FileDescriptor objects. michael@0: // This is used to pass a file descriptor to the peer of an IPC channel. michael@0: michael@0: // Add a descriptor to the end of the set. Returns false iff the set is full. michael@0: bool WriteFileDescriptor(const base::FileDescriptor& descriptor); michael@0: // Get a file descriptor from the message. Returns false on error. michael@0: // iter: a Pickle iterator to the current location in the message. michael@0: bool ReadFileDescriptor(void** iter, base::FileDescriptor* descriptor) const; michael@0: michael@0: #if defined(OS_MACOSX) michael@0: void set_fd_cookie(uint32_t cookie) { michael@0: header()->cookie = cookie; michael@0: } michael@0: uint32_t fd_cookie() const { michael@0: return header()->cookie; michael@0: } michael@0: #endif michael@0: #endif michael@0: michael@0: #ifdef IPC_MESSAGE_LOG_ENABLED michael@0: // Adds the outgoing time from Time::Now() at the end of the message and sets michael@0: // a bit to indicate that it's been added. michael@0: void set_sent_time(int64_t time); michael@0: int64_t sent_time() const; michael@0: michael@0: void set_received_time(int64_t time) const; michael@0: int64_t received_time() const { return received_time_; } michael@0: void set_output_params(const std::wstring& op) const { output_params_ = op; } michael@0: const std::wstring& output_params() const { return output_params_; } michael@0: // The following four functions are needed so we can log sync messages with michael@0: // delayed replies. We stick the log data from the sent message into the michael@0: // reply message, so that when it's sent and we have the output parameters michael@0: // we can log it. As such, we set a flag on the sent message to not log it. michael@0: void set_sync_log_data(LogData* data) const { log_data_ = data; } michael@0: LogData* sync_log_data() const { return log_data_; } michael@0: void set_dont_log() const { dont_log_ = true; } michael@0: bool dont_log() const { return dont_log_; } michael@0: #endif michael@0: michael@0: friend class Channel; michael@0: friend class MessageReplyDeserializer; michael@0: friend class SyncMessage; michael@0: michael@0: void set_sync() { michael@0: header()->flags |= SYNC_BIT; michael@0: } michael@0: michael@0: void set_interrupt() { michael@0: header()->flags |= INTERRUPT_BIT; michael@0: } michael@0: michael@0: void set_urgent() { michael@0: header()->flags |= URGENT_BIT; michael@0: } michael@0: michael@0: void set_rpc() { michael@0: header()->flags |= RPC_BIT; michael@0: } michael@0: michael@0: #if !defined(OS_MACOSX) michael@0: protected: michael@0: #endif michael@0: michael@0: // flags michael@0: enum { michael@0: PRIORITY_MASK = 0x0003, michael@0: SYNC_BIT = 0x0004, michael@0: REPLY_BIT = 0x0008, michael@0: REPLY_ERROR_BIT = 0x0010, michael@0: UNBLOCK_BIT = 0x0020, michael@0: PUMPING_MSGS_BIT= 0x0040, michael@0: HAS_SENT_TIME_BIT = 0x0080, michael@0: INTERRUPT_BIT = 0x0100, michael@0: COMPRESS_BIT = 0x0200, michael@0: URGENT_BIT = 0x0400, michael@0: RPC_BIT = 0x0800 michael@0: }; michael@0: michael@0: struct Header : Pickle::Header { michael@0: int32_t routing; // ID of the view that this message is destined for michael@0: msgid_t type; // specifies the user-defined message type michael@0: uint32_t flags; // specifies control flags for the message michael@0: #if defined(OS_POSIX) michael@0: uint32_t num_fds; // the number of descriptors included with this message michael@0: # if defined(OS_MACOSX) michael@0: uint32_t cookie; // cookie to ACK that the descriptors have been read. michael@0: # endif michael@0: #endif michael@0: union { michael@0: // For Interrupt messages, a guess at what the *other* side's stack depth is. michael@0: uint32_t interrupt_remote_stack_depth_guess; michael@0: michael@0: // For RPC and Urgent messages, a transaction ID for message ordering. michael@0: int32_t txid; michael@0: }; michael@0: // The actual local stack depth. michael@0: uint32_t interrupt_local_stack_depth; michael@0: // Sequence number michael@0: int32_t seqno; michael@0: #ifdef MOZ_TASK_TRACER michael@0: uint64_t source_event_id; michael@0: uint64_t parent_task_id; michael@0: mozilla::tasktracer::SourceEventType source_event_type; michael@0: #endif michael@0: }; michael@0: michael@0: Header* header() { michael@0: return headerT
(); michael@0: } michael@0: const Header* header() const { michael@0: return headerT
(); michael@0: } michael@0: michael@0: void InitLoggingVariables(const char* const name="???"); michael@0: michael@0: #if defined(OS_POSIX) michael@0: // The set of file descriptors associated with this message. michael@0: scoped_refptr file_descriptor_set_; michael@0: michael@0: // Ensure that a FileDescriptorSet is allocated michael@0: void EnsureFileDescriptorSet(); michael@0: michael@0: FileDescriptorSet* file_descriptor_set() { michael@0: EnsureFileDescriptorSet(); michael@0: return file_descriptor_set_.get(); michael@0: } michael@0: const FileDescriptorSet* file_descriptor_set() const { michael@0: return file_descriptor_set_.get(); michael@0: } michael@0: #endif michael@0: michael@0: const char* name_; michael@0: michael@0: #ifdef IPC_MESSAGE_LOG_ENABLED michael@0: // Used for logging. michael@0: mutable int64_t received_time_; michael@0: mutable std::wstring output_params_; michael@0: mutable LogData* log_data_; michael@0: mutable bool dont_log_; michael@0: #endif michael@0: }; michael@0: michael@0: //------------------------------------------------------------------------------ michael@0: michael@0: } // namespace IPC michael@0: michael@0: enum SpecialRoutingIDs { michael@0: // indicates that we don't have a routing ID yet. michael@0: MSG_ROUTING_NONE = kint32min, michael@0: michael@0: // indicates a general message not sent to a particular tab. michael@0: MSG_ROUTING_CONTROL = kint32max michael@0: }; michael@0: michael@0: #define IPC_REPLY_ID 0xFFF0 // Special message id for replies michael@0: #define IPC_LOGGING_ID 0xFFF1 // Special message id for logging michael@0: michael@0: #endif // CHROME_COMMON_IPC_MESSAGE_H__