1 // Copyright 2017 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef MOJO_CORE_USER_MESSAGE_IMPL_H_ 6 #define MOJO_CORE_USER_MESSAGE_IMPL_H_ 7 8 #include <memory> 9 #include <utility> 10 #include <vector> 11 12 #include "base/macros.h" 13 #include "base/optional.h" 14 #include "mojo/core/channel.h" 15 #include "mojo/core/dispatcher.h" 16 #include "mojo/core/ports/event.h" 17 #include "mojo/core/ports/name.h" 18 #include "mojo/core/ports/port_ref.h" 19 #include "mojo/core/ports/user_message.h" 20 #include "mojo/core/system_impl_export.h" 21 #include "mojo/public/c/system/message_pipe.h" 22 #include "mojo/public/c/system/types.h" 23 24 namespace mojo { 25 namespace core { 26 27 // UserMessageImpl is the sole implementation of ports::UserMessage used to 28 // attach message data to any ports::UserMessageEvent. 29 // 30 // A UserMessageImpl may be either serialized or unserialized. Unserialized 31 // instances are serialized lazily only when necessary, i.e., if and when 32 // Serialize() is called to obtain a serialized message for wire transfer. 33 class MOJO_SYSTEM_IMPL_EXPORT UserMessageImpl : public ports::UserMessage { 34 public: 35 static const TypeInfo kUserMessageTypeInfo; 36 37 // Determines how ExtractSerializedHandles should behave when it encounters an 38 // unrecoverable serialized handle. 39 enum ExtractBadHandlePolicy { 40 // Continue extracting handles upon encountering a bad handle. The bad 41 // handle will be extracted with an invalid handle value. 42 kSkip, 43 44 // Abort the extraction process, leaving any valid serialized handles still 45 // in the message. 46 kAbort, 47 }; 48 49 ~UserMessageImpl() override; 50 51 // Creates a new ports::UserMessageEvent with an attached UserMessageImpl. 52 static std::unique_ptr<ports::UserMessageEvent> CreateEventForNewMessage(); 53 54 // Creates a new ports::UserMessageEvent with an attached serialized 55 // UserMessageImpl. May fail iff one or more |dispatchers| fails to serialize 56 // (e.g. due to it being in an invalid state.) 57 // 58 // Upon success, MOJO_RESULT_OK is returned and the new UserMessageEvent is 59 // stored in |*out_event|. 60 static MojoResult CreateEventForNewSerializedMessage( 61 uint32_t num_bytes, 62 const Dispatcher::DispatcherInTransit* dispatchers, 63 uint32_t num_dispatchers, 64 std::unique_ptr<ports::UserMessageEvent>* out_event); 65 66 // Creates a new UserMessageImpl from an existing serialized message buffer 67 // which was read from a Channel. Takes ownership of |channel_message|. 68 // |payload| and |payload_size| represent the range of bytes within 69 // |channel_message| which should be parsed by this call. 70 static std::unique_ptr<UserMessageImpl> CreateFromChannelMessage( 71 ports::UserMessageEvent* message_event, 72 Channel::MessagePtr channel_message, 73 void* payload, 74 size_t payload_size); 75 76 // Extracts the serialized Channel::Message from the UserMessageEvent in 77 // |event|. |event| must have a serialized UserMessageImpl instance attached. 78 // |message_event| is serialized into the front of the message payload before 79 // returning. 80 static Channel::MessagePtr FinalizeEventMessage( 81 std::unique_ptr<ports::UserMessageEvent> event); 82 HasContext()83 bool HasContext() const { return context_ != 0; } 84 context()85 uintptr_t context() const { return context_; } 86 IsSerialized()87 bool IsSerialized() const { 88 if (HasContext()) { 89 DCHECK(!channel_message_); 90 return false; 91 } 92 93 return !!channel_message_; 94 } 95 IsTransmittable()96 bool IsTransmittable() const { return !IsSerialized() || is_committed_; } 97 user_payload()98 void* user_payload() { 99 DCHECK(IsSerialized()); 100 return user_payload_; 101 } 102 user_payload()103 const void* user_payload() const { 104 DCHECK(IsSerialized()); 105 return user_payload_; 106 } 107 user_payload_size()108 size_t user_payload_size() const { 109 DCHECK(IsSerialized()); 110 return user_payload_size_; 111 } 112 113 size_t user_payload_capacity() const; 114 115 size_t num_handles() const; 116 set_source_node(const ports::NodeName & name)117 void set_source_node(const ports::NodeName& name) { source_node_ = name; } source_node()118 const ports::NodeName& source_node() const { return source_node_; } 119 120 MojoResult SetContext(uintptr_t context, 121 MojoMessageContextSerializer serializer, 122 MojoMessageContextDestructor destructor); 123 MojoResult AppendData(uint32_t additional_payload_size, 124 const MojoHandle* handles, 125 uint32_t num_handles); 126 MojoResult CommitSize(); 127 128 // If this message is not already serialized, this serializes it. 129 MojoResult SerializeIfNecessary(); 130 131 // Extracts handles from this (serialized) message. 132 // 133 // Returns |MOJO_RESULT_OK| 134 // if sucessful, |MOJO_RESULT_FAILED_PRECONDITION| if this isn't a serialized 135 // message, |MOJO_RESULT_NOT_FOUND| if all serialized handles have already 136 // been extracted, or |MOJO_RESULT_ABORTED| if one or more handles failed 137 // extraction. 138 // 139 // On success, |handles| is populated with |num_handles()| extracted handles, 140 // whose ownership is thereby transferred to the caller. 141 MojoResult ExtractSerializedHandles(ExtractBadHandlePolicy bad_handle_policy, 142 MojoHandle* handles); 143 144 // Forces all handle serialization to fail. Serialization can fail in 145 // production for a few different reasons (e.g. file descriptor exhaustion 146 // when duping data pipe buffer handles) which may be difficult to control in 147 // testing environments. This forces the common serialization code path to 148 // always behave as if the underlying implementation signaled failure, 149 // allowing tests to exercise those cases. 150 static void FailHandleSerializationForTesting(bool fail); 151 152 private: 153 // Creates an unserialized UserMessageImpl with an associated |context| and 154 // |thunks|. If the message is ever going to be routed to another node (see 155 // |WillBeRoutedExternally()| below), it will be serialized at that time using 156 // operations provided by |thunks|. 157 UserMessageImpl(ports::UserMessageEvent* message_event); 158 159 // Creates a serialized UserMessageImpl backed by an existing Channel::Message 160 // object. |header| and |user_payload| must be pointers into 161 // |channel_message|'s own storage, and |user_payload_size| is the number of 162 // bytes comprising the user message contents at |user_payload|. 163 UserMessageImpl(ports::UserMessageEvent* message_event, 164 Channel::MessagePtr channel_message, 165 void* header, 166 size_t header_size, 167 void* user_payload, 168 size_t user_payload_size); 169 170 // UserMessage: 171 bool WillBeRoutedExternally() override; 172 size_t GetSizeIfSerialized() const override; 173 174 // The event which owns this serialized message. Not owned. 175 ports::UserMessageEvent* const message_event_; 176 177 // Unserialized message state. 178 uintptr_t context_ = 0; 179 MojoMessageContextSerializer context_serializer_ = nullptr; 180 MojoMessageContextDestructor context_destructor_ = nullptr; 181 182 // Serialized message contents. May be null if this is not a serialized 183 // message. 184 Channel::MessagePtr channel_message_; 185 186 // Indicates whether any handles serialized within |channel_message_| have 187 // yet to be extracted. 188 bool has_serialized_handles_ = false; 189 190 // Indicates whether the serialized message's contents (if any) have been 191 // committed yet. 192 bool is_committed_ = false; 193 194 // Only valid if |channel_message_| is non-null. |header_| is the address 195 // of the UserMessageImpl's internal MessageHeader structure within the 196 // serialized message buffer. |user_payload_| is the address of the first byte 197 // after any serialized dispatchers, with the payload comprising the remaining 198 // |user_payload_size_| bytes of the message. 199 void* header_ = nullptr; 200 size_t header_size_ = 0; 201 void* user_payload_ = nullptr; 202 size_t user_payload_size_ = 0; 203 204 // Handles which have been attached to the serialized message but which have 205 // not yet been serialized. 206 std::vector<Dispatcher::DispatcherInTransit> pending_handle_attachments_; 207 208 // The node name from which this message was received, iff it came from 209 // out-of-process and the source is known. 210 ports::NodeName source_node_ = ports::kInvalidNodeName; 211 212 DISALLOW_COPY_AND_ASSIGN(UserMessageImpl); 213 }; 214 215 } // namespace core 216 } // namespace mojo 217 218 #endif // MOJO_CORE_USER_MESSAGE_IMPL_H_ 219