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_BINDING_H_
6#define MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_BINDING_H_
7
8#include <memory>
9#include <utility>
10
11#include "base/bind.h"
12#include "base/callback.h"
13#include "base/macros.h"
14#include "base/memory/ptr_util.h"
15#include "base/memory/ref_counted.h"
16#include "base/single_thread_task_runner.h"
17#include "base/threading/thread_task_runner_handle.h"
18#include "mojo/public/cpp/bindings/associated_group.h"
19#include "mojo/public/cpp/bindings/associated_group_controller.h"
20#include "mojo/public/cpp/bindings/associated_interface_request.h"
21#include "mojo/public/cpp/bindings/interface_endpoint_client.h"
22#include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
23
24namespace mojo {
25
26// Represents the implementation side of an associated interface. It is similar
27// to Binding, except that it doesn't own a message pipe handle.
28//
29// When you bind this class to a request, optionally you can specify a
30// base::SingleThreadTaskRunner. This task runner must belong to the same
31// thread. It will be used to dispatch incoming method calls and connection
32// error notification. It is useful when you attach multiple task runners to a
33// single thread for the purposes of task scheduling. Please note that incoming
34// synchrounous method calls may not be run from this task runner, when they
35// reenter outgoing synchrounous calls on the same thread.
36template <typename Interface>
37class AssociatedBinding {
38 public:
39  // Constructs an incomplete associated binding that will use the
40  // implementation |impl|. It may be completed with a subsequent call to the
41  // |Bind| method. Does not take ownership of |impl|, which must outlive this
42  // object.
43  explicit AssociatedBinding(Interface* impl) : impl_(impl) {
44    stub_.set_sink(impl_);
45  }
46
47  // Constructs a completed associated binding of |impl|. The output |ptr_info|
48  // should be passed through the message pipe endpoint referred to by
49  // |associated_group| to setup the corresponding asssociated interface
50  // pointer. |impl| must outlive this object.
51  AssociatedBinding(Interface* impl,
52                    AssociatedInterfacePtrInfo<Interface>* ptr_info,
53                    AssociatedGroup* associated_group,
54                    scoped_refptr<base::SingleThreadTaskRunner> runner =
55                        base::ThreadTaskRunnerHandle::Get())
56      : AssociatedBinding(impl) {
57    Bind(ptr_info, associated_group, std::move(runner));
58  }
59
60  // Constructs a completed associated binding of |impl|. |impl| must outlive
61  // the binding.
62  AssociatedBinding(Interface* impl,
63                    AssociatedInterfaceRequest<Interface> request,
64                    scoped_refptr<base::SingleThreadTaskRunner> runner =
65                        base::ThreadTaskRunnerHandle::Get())
66      : AssociatedBinding(impl) {
67    Bind(std::move(request), std::move(runner));
68  }
69
70  ~AssociatedBinding() {}
71
72  // Creates an associated inteface and sets up this object as the
73  // implementation side. The output |ptr_info| should be passed through the
74  // message pipe endpoint referred to by |associated_group| to setup the
75  // corresponding asssociated interface pointer.
76  void Bind(AssociatedInterfacePtrInfo<Interface>* ptr_info,
77            AssociatedGroup* associated_group,
78            scoped_refptr<base::SingleThreadTaskRunner> runner =
79                base::ThreadTaskRunnerHandle::Get()) {
80    AssociatedInterfaceRequest<Interface> request;
81    associated_group->CreateAssociatedInterface(AssociatedGroup::WILL_PASS_PTR,
82                                                ptr_info, &request);
83    Bind(std::move(request), std::move(runner));
84  }
85
86  // Sets up this object as the implementation side of an associated interface.
87  void Bind(AssociatedInterfaceRequest<Interface> request,
88            scoped_refptr<base::SingleThreadTaskRunner> runner =
89                base::ThreadTaskRunnerHandle::Get()) {
90    ScopedInterfaceEndpointHandle handle = request.PassHandle();
91
92    DCHECK(handle.is_local())
93        << "The AssociatedInterfaceRequest is supposed to be used at the "
94        << "other side of the message pipe.";
95
96    if (!handle.is_valid() || !handle.is_local()) {
97      endpoint_client_.reset();
98      return;
99    }
100
101    endpoint_client_.reset(new InterfaceEndpointClient(
102        std::move(handle), &stub_,
103        base::WrapUnique(new typename Interface::RequestValidator_()),
104        Interface::HasSyncMethods_, std::move(runner)));
105    endpoint_client_->set_connection_error_handler(
106        base::Bind(&AssociatedBinding::RunConnectionErrorHandler,
107                   base::Unretained(this)));
108
109    stub_.serialization_context()->group_controller =
110        endpoint_client_->group_controller();
111  }
112
113  // Closes the associated interface. Puts this object into a state where it can
114  // be rebound.
115  void Close() {
116    DCHECK(endpoint_client_);
117    endpoint_client_.reset();
118    connection_error_handler_.Reset();
119  }
120
121  // Unbinds and returns the associated interface request so it can be
122  // used in another context, such as on another thread or with a different
123  // implementation. Puts this object into a state where it can be rebound.
124  AssociatedInterfaceRequest<Interface> Unbind() {
125    DCHECK(endpoint_client_);
126
127    AssociatedInterfaceRequest<Interface> request;
128    request.Bind(endpoint_client_->PassHandle());
129
130    endpoint_client_.reset();
131    connection_error_handler_.Reset();
132
133    return request;
134  }
135
136  // Sets an error handler that will be called if a connection error occurs.
137  //
138  // This method may only be called after this AssociatedBinding has been bound
139  // to a message pipe. The error handler will be reset when this
140  // AssociatedBinding is unbound or closed.
141  void set_connection_error_handler(const base::Closure& error_handler) {
142    DCHECK(is_bound());
143    connection_error_handler_ = error_handler;
144  }
145
146  // Returns the interface implementation that was previously specified.
147  Interface* impl() { return impl_; }
148
149  // Indicates whether the associated binding has been completed.
150  bool is_bound() const { return !!endpoint_client_; }
151
152  // Returns the associated group that this object belongs to. Returns null if
153  // the object is not bound.
154  AssociatedGroup* associated_group() {
155    return endpoint_client_ ? endpoint_client_->associated_group() : nullptr;
156  }
157
158 private:
159  void RunConnectionErrorHandler() {
160    if (!connection_error_handler_.is_null())
161      connection_error_handler_.Run();
162  }
163
164  std::unique_ptr<InterfaceEndpointClient> endpoint_client_;
165
166  typename Interface::Stub_ stub_;
167  Interface* impl_;
168  base::Closure connection_error_handler_;
169
170  DISALLOW_COPY_AND_ASSIGN(AssociatedBinding);
171};
172
173}  // namespace mojo
174
175#endif  // MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_BINDING_H_
176