summaryrefslogtreecommitdiffstats
path: root/mojo/public/cpp/bindings/associated_binding.h
blob: a135dfb2ee2189296029cbbc7f4bd342875fbcb0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_BINDING_H_
#define MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_BINDING_H_

#include <utility>

#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "mojo/public/cpp/bindings/associated_group.h"
#include "mojo/public/cpp/bindings/associated_interface_request.h"
#include "mojo/public/cpp/bindings/callback.h"
#include "mojo/public/cpp/bindings/lib/interface_endpoint_client.h"
#include "mojo/public/cpp/bindings/lib/multiplex_router.h"
#include "mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.h"

namespace mojo {

// Represents the implementation side of an associated interface. It is similar
// to Binding, except that it doesn't own a message pipe handle.
template <typename Interface>
class AssociatedBinding {
 public:
  using GenericInterface = typename Interface::GenericInterface;

  // Constructs an incomplete associated binding that will use the
  // implementation |impl|. It may be completed with a subsequent call to the
  // |Bind| method. Does not take ownership of |impl|, which must outlive this
  // object.
  explicit AssociatedBinding(Interface* impl) : impl_(impl) {
    stub_.set_sink(impl_);
  }

  // Constructs a completed associated binding of |impl|. The output |ptr_info|
  // should be passed through the message pipe endpoint referred to by
  // |associated_group| to setup the corresponding asssociated interface
  // pointer. |impl| must outlive this object.
  AssociatedBinding(Interface* impl,
                    AssociatedInterfacePtrInfo<GenericInterface>* ptr_info,
                    AssociatedGroup* associated_group)
      : AssociatedBinding(impl) {
    Bind(ptr_info, associated_group);
  }

  // Constructs a completed associated binding of |impl|. |impl| must outlive
  // the binding.
  AssociatedBinding(Interface* impl,
                    AssociatedInterfaceRequest<GenericInterface> request)
      : AssociatedBinding(impl) {
    Bind(std::move(request));
  }

  ~AssociatedBinding() {}

  // Creates an associated inteface and sets up this object as the
  // implementation side. The output |ptr_info| should be passed through the
  // message pipe endpoint referred to by |associated_group| to setup the
  // corresponding asssociated interface pointer.
  void Bind(AssociatedInterfacePtrInfo<GenericInterface>* ptr_info,
            AssociatedGroup* associated_group) {
    AssociatedInterfaceRequest<Interface> request;
    associated_group->CreateAssociatedInterface(AssociatedGroup::WILL_PASS_PTR,
                                                ptr_info, &request);
    Bind(std::move(request));
  }

  // Sets up this object as the implementation side of an associated interface.
  void Bind(AssociatedInterfaceRequest<GenericInterface> request) {
    internal::ScopedInterfaceEndpointHandle handle =
        internal::AssociatedInterfaceRequestHelper::PassHandle(&request);

    DCHECK(handle.is_local())
        << "The AssociatedInterfaceRequest is supposed to be used at the "
        << "other side of the message pipe.";

    if (!handle.is_valid() || !handle.is_local()) {
      endpoint_client_.reset();
      return;
    }

    endpoint_client_.reset(new internal::InterfaceEndpointClient(
        std::move(handle), &stub_,
        make_scoped_ptr(new typename Interface::RequestValidator_())));
    endpoint_client_->set_connection_error_handler(
        [this]() { connection_error_handler_.Run(); });

    stub_.serialization_context()->router = endpoint_client_->router();
  }

  // Closes the associated interface. Puts this object into a state where it can
  // be rebound.
  void Close() {
    DCHECK(endpoint_client_);
    endpoint_client_.reset();
    connection_error_handler_.reset();
  }

  // Unbinds and returns the associated interface request so it can be
  // used in another context, such as on another thread or with a different
  // implementation. Puts this object into a state where it can be rebound.
  AssociatedInterfaceRequest<GenericInterface> Unbind() {
    DCHECK(endpoint_client_);

    AssociatedInterfaceRequest<GenericInterface> request;
    internal::AssociatedInterfaceRequestHelper::SetHandle(
        &request, endpoint_client_->PassHandle());

    endpoint_client_.reset();
    connection_error_handler_.reset();

    return request.Pass();
  }

  // Sets an error handler that will be called if a connection error occurs.
  //
  // This method may only be called after this AssociatedBinding has been bound
  // to a message pipe. The error handler will be reset when this
  // AssociatedBinding is unbound or closed.
  void set_connection_error_handler(const Closure& error_handler) {
    DCHECK(is_bound());
    connection_error_handler_ = error_handler;
  }

  // Returns the interface implementation that was previously specified.
  Interface* impl() { return impl_; }

  // Indicates whether the associated binding has been completed.
  bool is_bound() const { return !!endpoint_client_; }

  // Returns the associated group that this object belongs to. Returns null if
  // the object is not bound.
  AssociatedGroup* associated_group() {
    return endpoint_client_ ? endpoint_client_->associated_group() : nullptr;
  }

 private:
  scoped_ptr<internal::InterfaceEndpointClient> endpoint_client_;

  typename Interface::Stub_ stub_;
  Interface* impl_;
  Closure connection_error_handler_;

  DISALLOW_COPY_AND_ASSIGN(AssociatedBinding);
};

}  // namespace mojo

#endif  // MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_BINDING_H_