| // Copyright 2013 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 MOJO_SYSTEM_MESSAGE_IN_TRANSIT_H_ |
| #define MOJO_SYSTEM_MESSAGE_IN_TRANSIT_H_ |
| |
| #include <stdint.h> |
| |
| #include <vector> |
| |
| #include "base/macros.h" |
| #include "base/memory/aligned_memory.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "mojo/embedder/platform_handle.h" |
| #include "mojo/system/dispatcher.h" |
| #include "mojo/system/system_impl_export.h" |
| |
| namespace mojo { |
| namespace system { |
| |
| class Channel; |
| |
| // This class is used to represent data in transit. It is thread-unsafe. |
| // |
| // |MessageInTransit| buffers: |
| // |
| // A |MessageInTransit| can be serialized by writing the main buffer and then, |
| // if it has one, the secondary buffer. Both buffers are |
| // |kMessageAlignment|-byte aligned and a multiple of |kMessageAlignment| bytes |
| // in size. |
| // |
| // The main buffer consists of the header (of type |Header|, which is an |
| // internal detail of this class) followed immediately by the message data |
| // (accessed by |bytes()| and of size |num_bytes()|, and also |
| // |kMessageAlignment|-byte aligned), and then any padding needed to make the |
| // main buffer a multiple of |kMessageAlignment| bytes in size. |
| // |
| // The secondary buffer consists first of a table of |HandleTableEntry|s (each |
| // of which is already a multiple of |kMessageAlignment| in size), followed by |
| // data needed for the |HandleTableEntry|s: A |HandleTableEntry| consists of an |
| // offset (in bytes, relative to the start of the secondary buffer; we guarantee |
| // that it's a multiple of |kMessageAlignment|), and a size (in bytes). |
| class MOJO_SYSTEM_IMPL_EXPORT MessageInTransit { |
| public: |
| typedef uint16_t Type; |
| // Messages that are forwarded to |MessagePipeEndpoint|s. |
| static const Type kTypeMessagePipeEndpoint = 0; |
| // Messages that are forwarded to |MessagePipe|s. |
| static const Type kTypeMessagePipe = 1; |
| // Messages that are consumed by the channel. |
| static const Type kTypeChannel = 2; |
| |
| typedef uint16_t Subtype; |
| // Subtypes for type |kTypeMessagePipeEndpoint|: |
| static const Subtype kSubtypeMessagePipeEndpointData = 0; |
| // Subtypes for type |kTypeMessagePipe|: |
| // Nothing currently. |
| // Subtypes for type |kTypeChannel|: |
| static const Subtype kSubtypeChannelRunMessagePipeEndpoint = 0; |
| static const Subtype kSubtypeChannelRemoveMessagePipeEndpoint = 1; |
| static const Subtype kSubtypeChannelRemoveMessagePipeEndpointAck = 2; |
| |
| typedef uint32_t EndpointId; |
| // Never a valid endpoint ID. |
| static const EndpointId kInvalidEndpointId = 0; |
| |
| // Messages (the header and data) must always be aligned to a multiple of this |
| // quantity (which must be a power of 2). |
| static const size_t kMessageAlignment = 8; |
| |
| // The maximum size of a single serialized dispatcher. This must be a multiple |
| // of |kMessageAlignment|. |
| static const size_t kMaxSerializedDispatcherSize = 10000; |
| |
| // The maximum number of platform handles to attach for a single serialized |
| // dispatcher. |
| static const size_t kMaxSerializedDispatcherPlatformHandles = 2; |
| |
| // Forward-declare |Header| so that |View| can use it: |
| private: |
| struct Header; |
| public: |
| // This represents a view of serialized message data in a raw buffer. |
| class MOJO_SYSTEM_IMPL_EXPORT View { |
| public: |
| // Constructs a view from the given buffer of the given size. (The size must |
| // be as provided by |MessageInTransit::GetNextMessageSize()|.) The buffer |
| // must remain alive/unmodified through the lifetime of this object. |
| // |buffer| should be |kMessageAlignment|-byte aligned. |
| View(size_t message_size, const void* buffer); |
| |
| // Checks the following things versus pre-determined limits: |
| // - |num_bytes()| and |main_buffer_size()|, |
| // - |num_handles()| and |secondary_buffer_size()|, |
| // - the entries in the handle entry table (that the sizes and offsets are |
| // valid). |
| // Note: It does not check the serialized dispatcher data itself. |
| // |
| // It returns true (and leaves |error_message| alone) if this object appears |
| // to be a valid message (according to the above) and false, pointing |
| // |*error_message| to a suitable error message, if not. |
| bool IsValid(const char** error_message) const; |
| |
| // API parallel to that for |MessageInTransit| itself (mostly getters for |
| // header data). |
| const void* main_buffer() const { return buffer_; } |
| size_t main_buffer_size() const { |
| return RoundUpMessageAlignment(sizeof(Header) + header()->num_bytes); |
| } |
| const void* secondary_buffer() const { |
| return (total_size() > main_buffer_size()) ? |
| static_cast<const char*>(buffer_) + main_buffer_size() : NULL; |
| } |
| size_t secondary_buffer_size() const { |
| return total_size() - main_buffer_size(); |
| } |
| size_t total_size() const { return header()->total_size; } |
| uint32_t num_bytes() const { return header()->num_bytes; } |
| const void* bytes() const { |
| return static_cast<const char*>(buffer_) + sizeof(Header); |
| } |
| uint32_t num_handles() const { return header()->num_handles; } |
| Type type() const { return header()->type; } |
| Subtype subtype() const { return header()->subtype; } |
| EndpointId source_id() const { return header()->source_id; } |
| EndpointId destination_id() const { return header()->destination_id; } |
| |
| private: |
| const Header* header() const { return static_cast<const Header*>(buffer_); } |
| |
| const void* const buffer_; |
| |
| // Though this struct is trivial, disallow copy and assign, since it doesn't |
| // own its data. (If you're copying/assigning this, you're probably doing |
| // something wrong.) |
| DISALLOW_COPY_AND_ASSIGN(View); |
| }; |
| |
| // |bytes| is optional; if null, the message data will be zero-initialized. |
| MessageInTransit(Type type, |
| Subtype subtype, |
| uint32_t num_bytes, |
| uint32_t num_handles, |
| const void* bytes); |
| // Constructs a |MessageInTransit| from a |View|. |
| explicit MessageInTransit(const View& message_view); |
| |
| ~MessageInTransit(); |
| |
| // Gets the size of the next message from |buffer|, which has |buffer_size| |
| // bytes currently available, returning true and setting |*next_message_size| |
| // on success. |buffer| should be aligned on a |kMessageAlignment| boundary |
| // (and on success, |*next_message_size| will be a multiple of |
| // |kMessageAlignment|). |
| // TODO(vtl): In |RawChannelPosix|, the alignment requirements are currently |
| // satisified on a faith-based basis. |
| static bool GetNextMessageSize(const void* buffer, |
| size_t buffer_size, |
| size_t* next_message_size); |
| |
| // Makes this message "own" the given set of dispatchers. The dispatchers must |
| // not be referenced from anywhere else (in particular, not from the handle |
| // table), i.e., each dispatcher must have a reference count of 1. This |
| // message must not already have dispatchers. |
| void SetDispatchers( |
| scoped_ptr<std::vector<scoped_refptr<Dispatcher> > > dispatchers); |
| |
| // Serializes any dispatchers to the secondary buffer. This message must not |
| // already have a secondary buffer (so this must only be called once). The |
| // caller must ensure (e.g., by holding on to a reference) that |channel| |
| // stays alive through the call. |
| void SerializeAndCloseDispatchers(Channel* channel); |
| |
| // Deserializes any dispatchers from the secondary buffer. This message must |
| // not have any dispatchers attached. |
| // TODO(vtl): Having to copy the secondary buffer (in the constructor from a |
| // |View|) is suboptimal. Maybe this should just be done in the constructor? |
| void DeserializeDispatchers(Channel* channel); |
| |
| // Gets the main buffer and its size (in number of bytes), respectively. |
| const void* main_buffer() const { return main_buffer_.get(); } |
| size_t main_buffer_size() const { return main_buffer_size_; } |
| |
| // Gets the secondary buffer and its size (in number of bytes), respectively. |
| const void* secondary_buffer() const { return secondary_buffer_.get(); } |
| size_t secondary_buffer_size() const { return secondary_buffer_size_; } |
| |
| // Gets the total size of the message (see comment in |Header|, below). |
| size_t total_size() const { return header()->total_size; } |
| |
| // Gets the size of the message data. |
| uint32_t num_bytes() const { return header()->num_bytes; } |
| |
| // Gets the message data (of size |num_bytes()| bytes). |
| const void* bytes() const { return main_buffer_.get() + sizeof(Header); } |
| void* bytes() { return main_buffer_.get() + sizeof(Header); } |
| |
| uint32_t num_handles() const { return header()->num_handles; } |
| |
| Type type() const { return header()->type; } |
| Subtype subtype() const { return header()->subtype; } |
| EndpointId source_id() const { return header()->source_id; } |
| EndpointId destination_id() const { return header()->destination_id; } |
| |
| void set_source_id(EndpointId source_id) { header()->source_id = source_id; } |
| void set_destination_id(EndpointId destination_id) { |
| header()->destination_id = destination_id; |
| } |
| |
| // Gets the dispatchers attached to this message; this may return null if |
| // there are none. Note that the caller may mutate the set of dispatchers |
| // (e.g., take ownership of all the dispatchers, leaving the vector empty). |
| std::vector<scoped_refptr<Dispatcher> >* dispatchers() { |
| return dispatchers_.get(); |
| } |
| |
| // Returns true if this message has dispatchers attached. |
| bool has_dispatchers() const { |
| return dispatchers_ && !dispatchers_->empty(); |
| } |
| |
| // Gets the platform-specific handles attached to this message; this may |
| // return null if there are none. Note that the caller may mutate the set of |
| // platform-specific handles. |
| std::vector<embedder::PlatformHandle>* platform_handles() { |
| return platform_handles_.get(); |
| } |
| |
| // Returns true if this message has platform-specific handles attached. |
| bool has_platform_handles() const { |
| return platform_handles_ && !platform_handles_->empty(); |
| } |
| |
| // Rounds |n| up to a multiple of |kMessageAlignment|. |
| static inline size_t RoundUpMessageAlignment(size_t n) { |
| return (n + kMessageAlignment - 1) & ~(kMessageAlignment - 1); |
| } |
| |
| private: |
| // To allow us to make assertions about |Header| in the .cc file. |
| struct PrivateStructForCompileAsserts; |
| |
| // Header for the data (main buffer). Must be a multiple of |
| // |kMessageAlignment| bytes in size. Must be POD. |
| struct Header { |
| // Total size of the message, including the header, the message data |
| // ("bytes") including padding (to make it a multiple of |kMessageAlignment| |
| // bytes), and serialized handle information. Note that this may not be the |
| // correct value if dispatchers are attached but |
| // |SerializeAndCloseDispatchers()| has not been called. |
| uint32_t total_size; |
| Type type; // 2 bytes. |
| Subtype subtype; // 2 bytes. |
| EndpointId source_id; // 4 bytes. |
| EndpointId destination_id; // 4 bytes. |
| // Size of actual message data. |
| uint32_t num_bytes; |
| // Number of handles "attached". |
| uint32_t num_handles; |
| }; |
| |
| struct HandleTableEntry { |
| int32_t type; // From |Dispatcher::Type| (|kTypeUnknown| for "invalid"). |
| uint32_t offset; // Relative to the start of the secondary buffer. |
| uint32_t size; // (Not including any padding.) |
| uint32_t unused; |
| }; |
| |
| // The maximum possible size of a valid secondary buffer. |
| static const size_t kMaxSecondaryBufferSize; |
| |
| // The maximum total number of platform handles that may be attached. |
| static const size_t kMaxPlatformHandles; |
| |
| // Validates the secondary buffer. Returns null on success, or a |
| // human-readable error message (meant for logging/debugging) on error. |
| static const char* ValidateSecondaryBuffer(size_t num_handles, |
| const void* secondary_buffer, |
| size_t secondary_buffer_size); |
| |
| const Header* header() const { |
| return reinterpret_cast<const Header*>(main_buffer_.get()); |
| } |
| Header* header() { return reinterpret_cast<Header*>(main_buffer_.get()); } |
| |
| void UpdateTotalSize(); |
| |
| const size_t main_buffer_size_; |
| const scoped_ptr<char, base::AlignedFreeDeleter> main_buffer_; // Never null. |
| |
| size_t secondary_buffer_size_; |
| scoped_ptr<char, base::AlignedFreeDeleter> secondary_buffer_; // May be null. |
| |
| // Any dispatchers that may be attached to this message. These dispatchers |
| // should be "owned" by this message, i.e., have a ref count of exactly 1. (We |
| // allow a dispatcher entry to be null, in case it couldn't be duplicated for |
| // some reason.) |
| scoped_ptr<std::vector<scoped_refptr<Dispatcher> > > dispatchers_; |
| |
| // Any platform-specific handles attached to this message (for inter-process |
| // transport). The vector (if any) owns the handles that it contains (and is |
| // responsible for closing them). |
| // TODO(vtl): With C++11, change it to a vector of |ScopedPlatformHandles|. |
| scoped_ptr<std::vector<embedder::PlatformHandle> > platform_handles_; |
| |
| DISALLOW_COPY_AND_ASSIGN(MessageInTransit); |
| }; |
| |
| } // namespace system |
| } // namespace mojo |
| |
| #endif // MOJO_SYSTEM_MESSAGE_IN_TRANSIT_H_ |