1// Copyright 2014 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_LIB_INTERFACE_PTR_STATE_H_
6#define MOJO_PUBLIC_CPP_BINDINGS_LIB_INTERFACE_PTR_STATE_H_
7
8#include <stdint.h>
9
10#include <algorithm>  // For |std::swap()|.
11#include <memory>
12#include <utility>
13
14#include "base/bind.h"
15#include "base/callback_forward.h"
16#include "base/logging.h"
17#include "base/macros.h"
18#include "base/memory/ptr_util.h"
19#include "base/memory/ref_counted.h"
20#include "base/single_thread_task_runner.h"
21#include "mojo/public/cpp/bindings/associated_group.h"
22#include "mojo/public/cpp/bindings/interface_endpoint_client.h"
23#include "mojo/public/cpp/bindings/interface_id.h"
24#include "mojo/public/cpp/bindings/interface_ptr_info.h"
25#include "mojo/public/cpp/bindings/lib/control_message_proxy.h"
26#include "mojo/public/cpp/bindings/lib/filter_chain.h"
27#include "mojo/public/cpp/bindings/lib/multiplex_router.h"
28#include "mojo/public/cpp/bindings/lib/router.h"
29#include "mojo/public/cpp/bindings/message_header_validator.h"
30#include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
31
32namespace mojo {
33namespace internal {
34
35template <typename Interface, bool use_multiplex_router>
36class InterfacePtrState;
37
38// Uses a single-threaded, dedicated router. If |Interface| doesn't have any
39// methods to pass associated interface pointers or requests, there won't be
40// multiple interfaces running on the underlying message pipe. In that case, we
41// can use this specialization to reduce cost.
42template <typename Interface>
43class InterfacePtrState<Interface, false> {
44 public:
45  InterfacePtrState() : proxy_(nullptr), router_(nullptr), version_(0u) {}
46
47  ~InterfacePtrState() {
48    // Destruction order matters here. We delete |proxy_| first, even though
49    // |router_| may have a reference to it, so that destructors for any request
50    // callbacks still pending can interact with the InterfacePtr.
51    delete proxy_;
52    delete router_;
53  }
54
55  Interface* instance() {
56    ConfigureProxyIfNecessary();
57
58    // This will be null if the object is not bound.
59    return proxy_;
60  }
61
62  uint32_t version() const { return version_; }
63
64  void QueryVersion(const base::Callback<void(uint32_t)>& callback) {
65    ConfigureProxyIfNecessary();
66
67    // Do a static cast in case the interface contains methods with the same
68    // name. It is safe to capture |this| because the callback won't be run
69    // after this object goes away.
70    static_cast<ControlMessageProxy*>(proxy_)->QueryVersion(
71        base::Bind(&InterfacePtrState::OnQueryVersion, base::Unretained(this),
72                   callback));
73  }
74
75  void RequireVersion(uint32_t version) {
76    ConfigureProxyIfNecessary();
77
78    if (version <= version_)
79      return;
80
81    version_ = version;
82    // Do a static cast in case the interface contains methods with the same
83    // name.
84    static_cast<ControlMessageProxy*>(proxy_)->RequireVersion(version);
85  }
86
87  void Swap(InterfacePtrState* other) {
88    using std::swap;
89    swap(other->proxy_, proxy_);
90    swap(other->router_, router_);
91    handle_.swap(other->handle_);
92    runner_.swap(other->runner_);
93    swap(other->version_, version_);
94  }
95
96  void Bind(InterfacePtrInfo<Interface> info,
97            scoped_refptr<base::SingleThreadTaskRunner> runner) {
98    DCHECK(!proxy_);
99    DCHECK(!router_);
100    DCHECK(!handle_.is_valid());
101    DCHECK_EQ(0u, version_);
102    DCHECK(info.is_valid());
103
104    handle_ = info.PassHandle();
105    version_ = info.version();
106    runner_ = std::move(runner);
107  }
108
109  bool HasAssociatedInterfaces() const { return false; }
110
111  // After this method is called, the object is in an invalid state and
112  // shouldn't be reused.
113  InterfacePtrInfo<Interface> PassInterface() {
114    return InterfacePtrInfo<Interface>(
115        router_ ? router_->PassMessagePipe() : std::move(handle_), version_);
116  }
117
118  bool is_bound() const { return handle_.is_valid() || router_; }
119
120  bool encountered_error() const {
121    return router_ ? router_->encountered_error() : false;
122  }
123
124  void set_connection_error_handler(const base::Closure& error_handler) {
125    ConfigureProxyIfNecessary();
126
127    DCHECK(router_);
128    router_->set_connection_error_handler(error_handler);
129  }
130
131  // Returns true if bound and awaiting a response to a message.
132  bool has_pending_callbacks() const {
133    return router_ && router_->has_pending_responders();
134  }
135
136  AssociatedGroup* associated_group() { return nullptr; }
137
138  void EnableTestingMode() {
139    ConfigureProxyIfNecessary();
140    router_->EnableTestingMode();
141  }
142
143 private:
144  using Proxy = typename Interface::Proxy_;
145
146  void ConfigureProxyIfNecessary() {
147    // The proxy has been configured.
148    if (proxy_) {
149      DCHECK(router_);
150      return;
151    }
152    // The object hasn't been bound.
153    if (!handle_.is_valid())
154      return;
155
156    FilterChain filters;
157    filters.Append<MessageHeaderValidator>(Interface::Name_);
158    filters.Append<typename Interface::ResponseValidator_>();
159
160    router_ = new Router(std::move(handle_), std::move(filters), false,
161                         std::move(runner_));
162
163    proxy_ = new Proxy(router_);
164  }
165
166  void OnQueryVersion(const base::Callback<void(uint32_t)>& callback,
167                      uint32_t version) {
168    version_ = version;
169    callback.Run(version);
170  }
171
172  Proxy* proxy_;
173  Router* router_;
174
175  // |proxy_| and |router_| are not initialized until read/write with the
176  // message pipe handle is needed. |handle_| is valid between the Bind() call
177  // and the initialization of |proxy_| and |router_|.
178  ScopedMessagePipeHandle handle_;
179  scoped_refptr<base::SingleThreadTaskRunner> runner_;
180
181  uint32_t version_;
182
183  DISALLOW_COPY_AND_ASSIGN(InterfacePtrState);
184};
185
186// Uses a multiplexing router. If |Interface| has methods to pass associated
187// interface pointers or requests, this specialization should be used.
188template <typename Interface>
189class InterfacePtrState<Interface, true> {
190 public:
191  InterfacePtrState() : version_(0u) {}
192
193  ~InterfacePtrState() {
194    endpoint_client_.reset();
195    proxy_.reset();
196    if (router_)
197      router_->CloseMessagePipe();
198  }
199
200  Interface* instance() {
201    ConfigureProxyIfNecessary();
202
203    // This will be null if the object is not bound.
204    return proxy_.get();
205  }
206
207  uint32_t version() const { return version_; }
208
209  void QueryVersion(const base::Callback<void(uint32_t)>& callback) {
210    ConfigureProxyIfNecessary();
211
212
213    // Do a static cast in case the interface contains methods with the same
214    // name. It is safe to capture |this| because the callback won't be run
215    // after this object goes away.
216    static_cast<ControlMessageProxy*>(proxy_.get())->QueryVersion(
217        base::Bind(&InterfacePtrState::OnQueryVersion, base::Unretained(this),
218                   callback));
219  }
220
221  void RequireVersion(uint32_t version) {
222    ConfigureProxyIfNecessary();
223
224    if (version <= version_)
225      return;
226
227    version_ = version;
228    // Do a static cast in case the interface contains methods with the same
229    // name.
230    static_cast<ControlMessageProxy*>(proxy_.get())->RequireVersion(version);
231  }
232
233  void Swap(InterfacePtrState* other) {
234    using std::swap;
235    swap(other->router_, router_);
236    swap(other->endpoint_client_, endpoint_client_);
237    swap(other->proxy_, proxy_);
238    handle_.swap(other->handle_);
239    runner_.swap(other->runner_);
240    swap(other->version_, version_);
241  }
242
243  void Bind(InterfacePtrInfo<Interface> info,
244            scoped_refptr<base::SingleThreadTaskRunner> runner) {
245    DCHECK(!router_);
246    DCHECK(!endpoint_client_);
247    DCHECK(!proxy_);
248    DCHECK(!handle_.is_valid());
249    DCHECK_EQ(0u, version_);
250    DCHECK(info.is_valid());
251
252    handle_ = info.PassHandle();
253    version_ = info.version();
254    runner_ = std::move(runner);
255  }
256
257  bool HasAssociatedInterfaces() const {
258    return router_ ? router_->HasAssociatedEndpoints() : false;
259  }
260
261  // After this method is called, the object is in an invalid state and
262  // shouldn't be reused.
263  InterfacePtrInfo<Interface> PassInterface() {
264    endpoint_client_.reset();
265    proxy_.reset();
266    return InterfacePtrInfo<Interface>(
267        router_ ? router_->PassMessagePipe() : std::move(handle_), version_);
268  }
269
270  bool is_bound() const { return handle_.is_valid() || endpoint_client_; }
271
272  bool encountered_error() const {
273    return endpoint_client_ ? endpoint_client_->encountered_error() : false;
274  }
275
276  void set_connection_error_handler(const base::Closure& error_handler) {
277    ConfigureProxyIfNecessary();
278
279    DCHECK(endpoint_client_);
280    endpoint_client_->set_connection_error_handler(error_handler);
281  }
282
283  // Returns true if bound and awaiting a response to a message.
284  bool has_pending_callbacks() const {
285    return endpoint_client_ && endpoint_client_->has_pending_responders();
286  }
287
288  AssociatedGroup* associated_group() {
289    ConfigureProxyIfNecessary();
290    return endpoint_client_->associated_group();
291  }
292
293  void EnableTestingMode() {
294    ConfigureProxyIfNecessary();
295    router_->EnableTestingMode();
296  }
297
298 private:
299  using Proxy = typename Interface::Proxy_;
300
301  void ConfigureProxyIfNecessary() {
302    // The proxy has been configured.
303    if (proxy_) {
304      DCHECK(router_);
305      DCHECK(endpoint_client_);
306      return;
307    }
308    // The object hasn't been bound.
309    if (!handle_.is_valid())
310      return;
311
312    router_ = new MultiplexRouter(true, std::move(handle_), runner_);
313    router_->SetMasterInterfaceName(Interface::Name_);
314    endpoint_client_.reset(new InterfaceEndpointClient(
315        router_->CreateLocalEndpointHandle(kMasterInterfaceId), nullptr,
316        base::WrapUnique(new typename Interface::ResponseValidator_()), false,
317        std::move(runner_)));
318    proxy_.reset(new Proxy(endpoint_client_.get()));
319    proxy_->serialization_context()->group_controller =
320        endpoint_client_->group_controller();
321  }
322
323  void OnQueryVersion(const base::Callback<void(uint32_t)>& callback,
324                      uint32_t version) {
325    version_ = version;
326    callback.Run(version);
327  }
328
329  scoped_refptr<MultiplexRouter> router_;
330
331  std::unique_ptr<InterfaceEndpointClient> endpoint_client_;
332  std::unique_ptr<Proxy> proxy_;
333
334  // |router_| (as well as other members above) is not initialized until
335  // read/write with the message pipe handle is needed. |handle_| is valid
336  // between the Bind() call and the initialization of |router_|.
337  ScopedMessagePipeHandle handle_;
338  scoped_refptr<base::SingleThreadTaskRunner> runner_;
339
340  uint32_t version_;
341
342  DISALLOW_COPY_AND_ASSIGN(InterfacePtrState);
343};
344
345}  // namespace internal
346}  // namespace mojo
347
348#endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_INTERFACE_PTR_STATE_H_
349