• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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