1 // Copyright 2015 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_PUBLIC_CPP_BINDINGS_ASSOCIATED_INTERFACE_PTR_H_
6 #define MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_INTERFACE_PTR_H_
7
8 #include <stdint.h>
9
10 #include <string>
11 #include <utility>
12
13 #include "base/callback.h"
14 #include "base/logging.h"
15 #include "base/macros.h"
16 #include "base/memory/ref_counted.h"
17 #include "base/sequenced_task_runner.h"
18 #include "mojo/public/cpp/bindings/associated_interface_ptr_info.h"
19 #include "mojo/public/cpp/bindings/associated_interface_request.h"
20 #include "mojo/public/cpp/bindings/bindings_export.h"
21 #include "mojo/public/cpp/bindings/connection_error_callback.h"
22 #include "mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h"
23 #include "mojo/public/cpp/bindings/lib/multiplex_router.h"
24 #include "mojo/public/cpp/system/message_pipe.h"
25
26 namespace mojo {
27
28 // Represents the client side of an associated interface. It is similar to
29 // InterfacePtr, except that it doesn't own a message pipe handle.
30 template <typename Interface>
31 class AssociatedInterfacePtr {
32 public:
33 using InterfaceType = Interface;
34 using PtrInfoType = AssociatedInterfacePtrInfo<Interface>;
35 using Proxy = typename Interface::Proxy_;
36
37 // Constructs an unbound AssociatedInterfacePtr.
AssociatedInterfacePtr()38 AssociatedInterfacePtr() {}
AssociatedInterfacePtr(decltype (nullptr))39 AssociatedInterfacePtr(decltype(nullptr)) {}
40
AssociatedInterfacePtr(AssociatedInterfacePtr && other)41 AssociatedInterfacePtr(AssociatedInterfacePtr&& other) {
42 internal_state_.Swap(&other.internal_state_);
43 }
44
AssociatedInterfacePtr(PtrInfoType && info)45 explicit AssociatedInterfacePtr(PtrInfoType&& info) { Bind(std::move(info)); }
46
47 AssociatedInterfacePtr& operator=(AssociatedInterfacePtr&& other) {
48 reset();
49 internal_state_.Swap(&other.internal_state_);
50 return *this;
51 }
52
53 // Assigning nullptr to this class causes it to closes the associated
54 // interface (if any) and returns the pointer to the unbound state.
decltype(nullptr)55 AssociatedInterfacePtr& operator=(decltype(nullptr)) {
56 reset();
57 return *this;
58 }
59
~AssociatedInterfacePtr()60 ~AssociatedInterfacePtr() {}
61
62 // Sets up this object as the client side of an associated interface.
63 // Calling with an invalid |info| has the same effect as reset(). In this
64 // case, the AssociatedInterfacePtr is not considered as bound.
65 //
66 // Optionally, |runner| is a SequencedTaskRunner bound to the current sequence
67 // on which all callbacks and connection error notifications will be
68 // dispatched. It is only useful to specify this to use a different
69 // SequencedTaskRunner than SequencedTaskRunnerHandle::Get().
70 //
71 // NOTE: The corresponding AssociatedInterfaceRequest must be sent over
72 // another interface before using this object to make calls. Please see the
73 // comments of MakeRequest(AssociatedInterfacePtr<Interface>*) for more
74 // details.
75 void Bind(AssociatedInterfacePtrInfo<Interface> info,
76 scoped_refptr<base::SequencedTaskRunner> runner = nullptr) {
77 reset();
78
79 if (info.is_valid())
80 internal_state_.Bind(std::move(info), std::move(runner));
81 }
82
is_bound()83 bool is_bound() const { return internal_state_.is_bound(); }
84
get()85 Proxy* get() const { return internal_state_.instance(); }
86
87 // Functions like a pointer to Interface. Must already be bound.
88 Proxy* operator->() const { return get(); }
89 Proxy& operator*() const { return *get(); }
90
91 // Returns the version number of the interface that the remote side supports.
version()92 uint32_t version() const { return internal_state_.version(); }
93
94 // Queries the max version that the remote side supports. On completion, the
95 // result will be returned as the input of |callback|. The version number of
96 // this object will also be updated.
QueryVersion(const base::Callback<void (uint32_t)> & callback)97 void QueryVersion(const base::Callback<void(uint32_t)>& callback) {
98 internal_state_.QueryVersion(callback);
99 }
100
101 // If the remote side doesn't support the specified version, it will close the
102 // associated interface asynchronously. This does nothing if it's already
103 // known that the remote side supports the specified version, i.e., if
104 // |version <= this->version()|.
105 //
106 // After calling RequireVersion() with a version not supported by the remote
107 // side, all subsequent calls to interface methods will be ignored.
RequireVersion(uint32_t version)108 void RequireVersion(uint32_t version) {
109 internal_state_.RequireVersion(version);
110 }
111
112 // Sends a message on the underlying message pipe and runs the current
113 // message loop until its response is received. This can be used in tests to
114 // verify that no message was sent on a message pipe in response to some
115 // stimulus.
FlushForTesting()116 void FlushForTesting() { internal_state_.FlushForTesting(); }
117
118 // Closes the associated interface (if any) and returns the pointer to the
119 // unbound state.
reset()120 void reset() {
121 State doomed;
122 internal_state_.Swap(&doomed);
123 }
124
125 // Similar to the method above, but also specifies a disconnect reason.
ResetWithReason(uint32_t custom_reason,const std::string & description)126 void ResetWithReason(uint32_t custom_reason, const std::string& description) {
127 if (internal_state_.is_bound())
128 internal_state_.CloseWithReason(custom_reason, description);
129 reset();
130 }
131
132 // Indicates whether an error has been encountered. If true, method calls made
133 // on this interface will be dropped (and may already have been dropped).
encountered_error()134 bool encountered_error() const { return internal_state_.encountered_error(); }
135
136 // Registers a handler to receive error notifications.
137 //
138 // This method may only be called after the AssociatedInterfacePtr has been
139 // bound.
set_connection_error_handler(base::OnceClosure error_handler)140 void set_connection_error_handler(base::OnceClosure error_handler) {
141 internal_state_.set_connection_error_handler(std::move(error_handler));
142 }
143
set_connection_error_with_reason_handler(ConnectionErrorWithReasonCallback error_handler)144 void set_connection_error_with_reason_handler(
145 ConnectionErrorWithReasonCallback error_handler) {
146 internal_state_.set_connection_error_with_reason_handler(
147 std::move(error_handler));
148 }
149
150 // Unbinds and returns the associated interface pointer information which
151 // could be used to setup an AssociatedInterfacePtr again. This method may be
152 // used to move the proxy to a different sequence.
153 //
154 // It is an error to call PassInterface() while there are pending responses.
155 // TODO: fix this restriction, it's not always obvious when there is a
156 // pending response.
PassInterface()157 AssociatedInterfacePtrInfo<Interface> PassInterface() {
158 DCHECK(!internal_state_.has_pending_callbacks());
159 State state;
160 internal_state_.Swap(&state);
161
162 return state.PassInterface();
163 }
164
165 // DO NOT USE. Exposed only for internal use and for testing.
internal_state()166 internal::AssociatedInterfacePtrState<Interface>* internal_state() {
167 return &internal_state_;
168 }
169
170 // Allow AssociatedInterfacePtr<> to be used in boolean expressions.
171 explicit operator bool() const { return internal_state_.is_bound(); }
172
173 private:
174 typedef internal::AssociatedInterfacePtrState<Interface> State;
175 mutable State internal_state_;
176
177 DISALLOW_COPY_AND_ASSIGN(AssociatedInterfacePtr);
178 };
179
180 // Creates an associated interface. The returned request is supposed to be sent
181 // over another interface (either associated or non-associated).
182 //
183 // NOTE: |ptr| must NOT be used to make calls before the request is sent.
184 // Violating that will lead to crash. On the other hand, as soon as the request
185 // is sent, |ptr| is usable. There is no need to wait until the request is bound
186 // to an implementation at the remote side.
187 template <typename Interface>
188 AssociatedInterfaceRequest<Interface> MakeRequest(
189 AssociatedInterfacePtr<Interface>* ptr,
190 scoped_refptr<base::SequencedTaskRunner> runner = nullptr) {
191 AssociatedInterfacePtrInfo<Interface> ptr_info;
192 auto request = MakeRequest(&ptr_info);
193 ptr->Bind(std::move(ptr_info), std::move(runner));
194 return request;
195 }
196
197 // Creates an associated interface. One of the two endpoints is supposed to be
198 // sent over another interface (either associated or non-associated); while the
199 // other is used locally.
200 //
201 // NOTE: If |ptr_info| is used locally and bound to an AssociatedInterfacePtr,
202 // the interface pointer must NOT be used to make calls before the request is
203 // sent. Please see NOTE of the previous function for more details.
204 template <typename Interface>
MakeRequest(AssociatedInterfacePtrInfo<Interface> * ptr_info)205 AssociatedInterfaceRequest<Interface> MakeRequest(
206 AssociatedInterfacePtrInfo<Interface>* ptr_info) {
207 ScopedInterfaceEndpointHandle handle0;
208 ScopedInterfaceEndpointHandle handle1;
209 ScopedInterfaceEndpointHandle::CreatePairPendingAssociation(&handle0,
210 &handle1);
211
212 ptr_info->set_handle(std::move(handle0));
213 ptr_info->set_version(0);
214
215 return AssociatedInterfaceRequest<Interface>(std::move(handle1));
216 }
217
218 // Like MakeRequest() above, but it creates a dedicated message pipe. The
219 // returned request can be bound directly to an implementation, without being
220 // first passed through a message pipe endpoint.
221 //
222 // This function has two main uses:
223 //
224 // * In testing, where the returned request is bound to e.g. a mock and there
225 // are no other interfaces involved.
226 //
227 // * When discarding messages sent on an interface, which can be done by
228 // discarding the returned request.
229 template <typename Interface>
MakeRequestAssociatedWithDedicatedPipe(AssociatedInterfacePtr<Interface> * ptr)230 AssociatedInterfaceRequest<Interface> MakeRequestAssociatedWithDedicatedPipe(
231 AssociatedInterfacePtr<Interface>* ptr) {
232 MessagePipe pipe;
233 scoped_refptr<internal::MultiplexRouter> router0 =
234 new internal::MultiplexRouter(
235 std::move(pipe.handle0), internal::MultiplexRouter::MULTI_INTERFACE,
236 false, base::SequencedTaskRunnerHandle::Get());
237 scoped_refptr<internal::MultiplexRouter> router1 =
238 new internal::MultiplexRouter(
239 std::move(pipe.handle1), internal::MultiplexRouter::MULTI_INTERFACE,
240 true, base::SequencedTaskRunnerHandle::Get());
241
242 ScopedInterfaceEndpointHandle endpoint0, endpoint1;
243 ScopedInterfaceEndpointHandle::CreatePairPendingAssociation(&endpoint0,
244 &endpoint1);
245 InterfaceId id = router1->AssociateInterface(std::move(endpoint0));
246 endpoint0 = router0->CreateLocalEndpointHandle(id);
247
248 ptr->Bind(AssociatedInterfacePtrInfo<Interface>(std::move(endpoint0),
249 Interface::Version_));
250 return AssociatedInterfaceRequest<Interface>(std::move(endpoint1));
251 }
252
253 // |handle| is supposed to be the request of an associated interface. This
254 // method associates the interface with a dedicated, disconnected message pipe.
255 // That way, the corresponding associated interface pointer of |handle| can
256 // safely make calls (although those calls are silently dropped).
257 MOJO_CPP_BINDINGS_EXPORT void AssociateWithDisconnectedPipe(
258 ScopedInterfaceEndpointHandle handle);
259
260 } // namespace mojo
261
262 #endif // MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_INTERFACE_PTR_H_
263