1 // Copyright 2019 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_PENDING_RECEIVER_H_
6 #define MOJO_PUBLIC_CPP_BINDINGS_PENDING_RECEIVER_H_
7 
8 #include <type_traits>
9 #include <utility>
10 
11 #include "base/macros.h"
12 #include "build/build_config.h"
13 #include "mojo/public/cpp/bindings/connection_group.h"
14 #include "mojo/public/cpp/bindings/interface_request.h"
15 #include "mojo/public/cpp/bindings/lib/bindings_internal.h"
16 #include "mojo/public/cpp/bindings/lib/pending_receiver_state.h"
17 #include "mojo/public/cpp/bindings/lib/serialization_context.h"
18 #include "mojo/public/cpp/system/message_pipe.h"
19 
20 namespace mojo {
21 
22 template <typename T>
23 struct PendingReceiverConverter;
24 
25 // A PendingReceiver receives and accumulates a queue of incoming Interface
26 // method calls made by a single corresponding Remote. PendingReceiver instances
27 // may be freely moved to another thread/sequence, or even transferred to
28 // another process via a Mojo interface call (see pending_receiver<T> syntax in
29 // mojom IDL).
30 //
31 // This object should eventually be consumed to bind a Receiver, which will then
32 // begin dispatching any queued and future incoming method calls to a local
33 // implementation of Interface. See Receiver documentation for more details.
34 //
35 // NOTE: This object is essentially semantic sugar wrapping a message pipe
36 // handle that is expected to receive Interface messages from a Remote. As such,
37 // consumers who know what they're doing (i.e. who are confident about what lies
38 // on the other end of a pipe) may freely convert between a PendingReceiver and
39 // a raw message pipe handle.
40 template <typename Interface>
41 class PendingReceiver {
42  public:
43   // Constructs an invalid PendingReceiver. This object is not entangled with
44   // any Remote and cannot be used to bind a Receiver.
45   //
46   // A valid PendingReceiver is commonly obtained by calling
47   // |Remote::BindNewPipeAndPassReceiver()| on an existing unbound Remote
48   // instance or less commonly by calling calling
49   // |PendingRemote::InitWithNewPipeAndPassReceiver()| on an existing but
50   // invalid PendingRemote instance.
51   PendingReceiver() = default;
52   PendingReceiver(PendingReceiver&&) noexcept = default;
53 
54   // Temporary implicit move constructor to aid in converting from use of
55   // InterfaceRequest<Interface> to PendingReceiver.
PendingReceiver(InterfaceRequest<Interface> && request)56   PendingReceiver(InterfaceRequest<Interface>&& request)
57       : PendingReceiver(request.PassMessagePipe()) {
58     set_connection_group(request.PassConnectionGroupRef());
59   }
60 
61   // Constructs a valid PendingReceiver from a valid raw message pipe handle.
PendingReceiver(ScopedMessagePipeHandle pipe)62   explicit PendingReceiver(ScopedMessagePipeHandle pipe)
63       : state_(std::move(pipe)) {}
64 
65   // Disabled on NaCl since it crashes old version of clang.
66 #if !defined(OS_NACL)
67   // Move conversion operator for custom receiver types. Only participates in
68   // overload resolution if a typesafe conversion is supported.
69   template <
70       typename T,
71       std::enable_if_t<std::is_same<
72           PendingReceiver<Interface>,
73           std::result_of_t<decltype (&PendingReceiverConverter<T>::template To<
74                                      Interface>)(T&&)>>::value>* = nullptr>
PendingReceiver(T && other)75   PendingReceiver(T&& other)
76       : PendingReceiver(PendingReceiverConverter<T>::template To<Interface>(
77             std::forward<T>(other))) {}
78 #endif  // !defined(OS_NACL)
79 
80   ~PendingReceiver() = default;
81 
82   PendingReceiver& operator=(PendingReceiver&&) noexcept = default;
83 
84   // Temporary implicit conversion operator to InterfaceRequest<Interface> to
85   // aid in converting usage to PendingReceiver.
86   operator InterfaceRequest<Interface>() && {
87     InterfaceRequest<Interface> request(PassPipe());
88     request.set_connection_group(PassConnectionGroupRef());
89     return request;
90   }
91 
92   // Indicates whether the PendingReceiver is valid, meaning it can ne used to
93   // bind a Receiver that wants to begin dispatching method calls made by the
94   // entangled Remote.
is_valid()95   bool is_valid() const { return state_.pipe.is_valid(); }
96   explicit operator bool() const { return is_valid(); }
97 
98   // Resets this PendingReceiver to an invalid state. If it was entangled with a
99   // Remote or PendingRemote, that object remains in a valid state and will
100   // eventually detect that its receiver is gone. Any calls it makes will
101   // effectively be dropped.
reset()102   void reset() { state_.reset(); }
103 
104   // Like above but provides a reason for the disconnection.
ResetWithReason(uint32_t reason,const std::string & description)105   void ResetWithReason(uint32_t reason, const std::string& description) {
106     InterfaceRequest<Interface>(PassPipe())
107         .ResetWithReason(reason, description);
108   }
109 
110   // Passes ownership of this PendingReceiver's message pipe handle. After this
111   // call, the PendingReceiver is no longer in a valid state and can no longer
112   // be used to bind a Receiver.
PassPipe()113   ScopedMessagePipeHandle PassPipe() WARN_UNUSED_RESULT {
114     return std::move(state_.pipe);
115   }
116 
117   // Assigns this PendingReceiver to the ConnectionGroup referenced by |ref|.
118   // Any Receiver which binds this PendingReceiver will inherit the Ref.
set_connection_group(ConnectionGroup::Ref ref)119   void set_connection_group(ConnectionGroup::Ref ref) {
120     state_.connection_group = std::move(ref);
121   }
122 
connection_group()123   const ConnectionGroup::Ref& connection_group() const {
124     return state_.connection_group;
125   }
126 
127   // Passes ownership of this PendingReceiver's ConnectionGroup Ref, removing it
128   // from its group.
PassConnectionGroupRef()129   ConnectionGroup::Ref PassConnectionGroupRef() {
130     return std::move(state_.connection_group);
131   }
132 
133   // For internal Mojo use only.
internal_state()134   internal::PendingReceiverState* internal_state() { return &state_; }
135 
136  private:
137   internal::PendingReceiverState state_;
138 
139   DISALLOW_COPY_AND_ASSIGN(PendingReceiver);
140 };
141 
COMPONENT_EXPORT(MOJO_CPP_BINDINGS)142 class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) NullReceiver {
143  public:
144   template <typename Interface>
145   operator PendingReceiver<Interface>() const {
146     return PendingReceiver<Interface>();
147   }
148 };
149 
150 }  // namespace mojo
151 
152 #endif  // MOJO_PUBLIC_CPP_BINDINGS_PENDING_RECEIVER_H_
153