// 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_
|