Home | History | Annotate | Download | only in bindings
      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.
     38   AssociatedInterfacePtr() {}
     39   AssociatedInterfacePtr(decltype(nullptr)) {}
     40 
     41   AssociatedInterfacePtr(AssociatedInterfacePtr&& other) {
     42     internal_state_.Swap(&other.internal_state_);
     43   }
     44 
     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.
     55   AssociatedInterfacePtr& operator=(decltype(nullptr)) {
     56     reset();
     57     return *this;
     58   }
     59 
     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 
     83   bool is_bound() const { return internal_state_.is_bound(); }
     84 
     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.
     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.
     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.
    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.
    116   void FlushForTesting() { internal_state_.FlushForTesting(); }
    117 
    118   // Closes the associated interface (if any) and returns the pointer to the
    119   // unbound state.
    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.
    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).
    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.
    140   void set_connection_error_handler(base::OnceClosure error_handler) {
    141     internal_state_.set_connection_error_handler(std::move(error_handler));
    142   }
    143 
    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.
    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.
    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>
    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>
    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