| // Copyright 2017 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_CORE_USER_MESSAGE_IMPL_H_ |
| #define MOJO_CORE_USER_MESSAGE_IMPL_H_ |
| |
| #include <memory> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/macros.h" |
| #include "base/optional.h" |
| #include "mojo/core/channel.h" |
| #include "mojo/core/dispatcher.h" |
| #include "mojo/core/ports/event.h" |
| #include "mojo/core/ports/name.h" |
| #include "mojo/core/ports/port_ref.h" |
| #include "mojo/core/ports/user_message.h" |
| #include "mojo/core/system_impl_export.h" |
| #include "mojo/public/c/system/message_pipe.h" |
| #include "mojo/public/c/system/types.h" |
| |
| namespace mojo { |
| namespace core { |
| |
| // UserMessageImpl is the sole implementation of ports::UserMessage used to |
| // attach message data to any ports::UserMessageEvent. |
| // |
| // A UserMessageImpl may be either serialized or unserialized. Unserialized |
| // instances are serialized lazily only when necessary, i.e., if and when |
| // Serialize() is called to obtain a serialized message for wire transfer. |
| class MOJO_SYSTEM_IMPL_EXPORT UserMessageImpl : public ports::UserMessage { |
| public: |
| static const TypeInfo kUserMessageTypeInfo; |
| |
| // Determines how ExtractSerializedHandles should behave when it encounters an |
| // unrecoverable serialized handle. |
| enum ExtractBadHandlePolicy { |
| // Continue extracting handles upon encountering a bad handle. The bad |
| // handle will be extracted with an invalid handle value. |
| kSkip, |
| |
| // Abort the extraction process, leaving any valid serialized handles still |
| // in the message. |
| kAbort, |
| }; |
| |
| ~UserMessageImpl() override; |
| |
| // Creates a new ports::UserMessageEvent with an attached UserMessageImpl. |
| static std::unique_ptr<ports::UserMessageEvent> CreateEventForNewMessage(); |
| |
| // Creates a new ports::UserMessageEvent with an attached serialized |
| // UserMessageImpl. May fail iff one or more |dispatchers| fails to serialize |
| // (e.g. due to it being in an invalid state.) |
| // |
| // Upon success, MOJO_RESULT_OK is returned and the new UserMessageEvent is |
| // stored in |*out_event|. |
| static MojoResult CreateEventForNewSerializedMessage( |
| uint32_t num_bytes, |
| const Dispatcher::DispatcherInTransit* dispatchers, |
| uint32_t num_dispatchers, |
| std::unique_ptr<ports::UserMessageEvent>* out_event); |
| |
| // Creates a new UserMessageImpl from an existing serialized message buffer |
| // which was read from a Channel. Takes ownership of |channel_message|. |
| // |payload| and |payload_size| represent the range of bytes within |
| // |channel_message| which should be parsed by this call. |
| static std::unique_ptr<UserMessageImpl> CreateFromChannelMessage( |
| ports::UserMessageEvent* message_event, |
| Channel::MessagePtr channel_message, |
| void* payload, |
| size_t payload_size); |
| |
| // Extracts the serialized Channel::Message from the UserMessageEvent in |
| // |event|. |event| must have a serialized UserMessageImpl instance attached. |
| // |message_event| is serialized into the front of the message payload before |
| // returning. |
| static Channel::MessagePtr FinalizeEventMessage( |
| std::unique_ptr<ports::UserMessageEvent> event); |
| |
| bool HasContext() const { return context_ != 0; } |
| |
| uintptr_t context() const { return context_; } |
| |
| bool IsSerialized() const { |
| if (HasContext()) { |
| DCHECK(!channel_message_); |
| return false; |
| } |
| |
| return !!channel_message_; |
| } |
| |
| bool IsTransmittable() const { return !IsSerialized() || is_committed_; } |
| |
| void* user_payload() { |
| DCHECK(IsSerialized()); |
| return user_payload_; |
| } |
| |
| const void* user_payload() const { |
| DCHECK(IsSerialized()); |
| return user_payload_; |
| } |
| |
| size_t user_payload_size() const { |
| DCHECK(IsSerialized()); |
| return user_payload_size_; |
| } |
| |
| size_t user_payload_capacity() const; |
| |
| size_t num_handles() const; |
| |
| void set_source_node(const ports::NodeName& name) { source_node_ = name; } |
| const ports::NodeName& source_node() const { return source_node_; } |
| |
| MojoResult SetContext(uintptr_t context, |
| MojoMessageContextSerializer serializer, |
| MojoMessageContextDestructor destructor); |
| MojoResult AppendData(uint32_t additional_payload_size, |
| const MojoHandle* handles, |
| uint32_t num_handles); |
| MojoResult CommitSize(); |
| |
| // If this message is not already serialized, this serializes it. |
| MojoResult SerializeIfNecessary(); |
| |
| // Extracts handles from this (serialized) message. |
| // |
| // Returns |MOJO_RESULT_OK| |
| // if sucessful, |MOJO_RESULT_FAILED_PRECONDITION| if this isn't a serialized |
| // message, |MOJO_RESULT_NOT_FOUND| if all serialized handles have already |
| // been extracted, or |MOJO_RESULT_ABORTED| if one or more handles failed |
| // extraction. |
| // |
| // On success, |handles| is populated with |num_handles()| extracted handles, |
| // whose ownership is thereby transferred to the caller. |
| MojoResult ExtractSerializedHandles(ExtractBadHandlePolicy bad_handle_policy, |
| MojoHandle* handles); |
| |
| // Forces all handle serialization to fail. Serialization can fail in |
| // production for a few different reasons (e.g. file descriptor exhaustion |
| // when duping data pipe buffer handles) which may be difficult to control in |
| // testing environments. This forces the common serialization code path to |
| // always behave as if the underlying implementation signaled failure, |
| // allowing tests to exercise those cases. |
| static void FailHandleSerializationForTesting(bool fail); |
| |
| private: |
| // Creates an unserialized UserMessageImpl with an associated |context| and |
| // |thunks|. If the message is ever going to be routed to another node (see |
| // |WillBeRoutedExternally()| below), it will be serialized at that time using |
| // operations provided by |thunks|. |
| UserMessageImpl(ports::UserMessageEvent* message_event); |
| |
| // Creates a serialized UserMessageImpl backed by an existing Channel::Message |
| // object. |header| and |user_payload| must be pointers into |
| // |channel_message|'s own storage, and |user_payload_size| is the number of |
| // bytes comprising the user message contents at |user_payload|. |
| UserMessageImpl(ports::UserMessageEvent* message_event, |
| Channel::MessagePtr channel_message, |
| void* header, |
| size_t header_size, |
| void* user_payload, |
| size_t user_payload_size); |
| |
| // UserMessage: |
| bool WillBeRoutedExternally() override; |
| size_t GetSizeIfSerialized() const override; |
| |
| // The event which owns this serialized message. Not owned. |
| ports::UserMessageEvent* const message_event_; |
| |
| // Unserialized message state. |
| uintptr_t context_ = 0; |
| MojoMessageContextSerializer context_serializer_ = nullptr; |
| MojoMessageContextDestructor context_destructor_ = nullptr; |
| |
| // Serialized message contents. May be null if this is not a serialized |
| // message. |
| Channel::MessagePtr channel_message_; |
| |
| // Indicates whether any handles serialized within |channel_message_| have |
| // yet to be extracted. |
| bool has_serialized_handles_ = false; |
| |
| // Indicates whether the serialized message's contents (if any) have been |
| // committed yet. |
| bool is_committed_ = false; |
| |
| // Only valid if |channel_message_| is non-null. |header_| is the address |
| // of the UserMessageImpl's internal MessageHeader structure within the |
| // serialized message buffer. |user_payload_| is the address of the first byte |
| // after any serialized dispatchers, with the payload comprising the remaining |
| // |user_payload_size_| bytes of the message. |
| void* header_ = nullptr; |
| size_t header_size_ = 0; |
| void* user_payload_ = nullptr; |
| size_t user_payload_size_ = 0; |
| |
| // Handles which have been attached to the serialized message but which have |
| // not yet been serialized. |
| std::vector<Dispatcher::DispatcherInTransit> pending_handle_attachments_; |
| |
| // The node name from which this message was received, iff it came from |
| // out-of-process and the source is known. |
| ports::NodeName source_node_ = ports::kInvalidNodeName; |
| |
| DISALLOW_COPY_AND_ASSIGN(UserMessageImpl); |
| }; |
| |
| } // namespace core |
| } // namespace mojo |
| |
| #endif // MOJO_CORE_USER_MESSAGE_IMPL_H_ |