Home | History | Annotate | Download | only in bindings
      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_INTERFACE_REQUEST_H_
      6 #define MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_REQUEST_H_
      7 
      8 #include <string>
      9 #include <utility>
     10 
     11 #include "base/macros.h"
     12 #include "base/optional.h"
     13 #include "base/single_thread_task_runner.h"
     14 #include "base/threading/thread_task_runner_handle.h"
     15 #include "mojo/public/cpp/bindings/disconnect_reason.h"
     16 #include "mojo/public/cpp/bindings/interface_ptr.h"
     17 #include "mojo/public/cpp/bindings/pipe_control_message_proxy.h"
     18 #include "mojo/public/cpp/system/message_pipe.h"
     19 
     20 namespace mojo {
     21 
     22 // Represents a request from a remote client for an implementation of Interface
     23 // over a specified message pipe. The implementor of the interface should
     24 // remove the message pipe by calling PassMessagePipe() and bind it to the
     25 // implementation. If this is not done, the InterfaceRequest will automatically
     26 // close the pipe on destruction. Can also represent the absence of a request
     27 // if the client did not provide a message pipe.
     28 template <typename Interface>
     29 class InterfaceRequest {
     30  public:
     31   // Constructs an empty InterfaceRequest, representing that the client is not
     32   // requesting an implementation of Interface.
     33   InterfaceRequest() {}
     34   InterfaceRequest(decltype(nullptr)) {}
     35 
     36   // Creates a new message pipe over which Interface is to be served, binding
     37   // the specified InterfacePtr to one end of the message pipe and this
     38   // InterfaceRequest to the other. For example usage, see comments on
     39   // MakeRequest(InterfacePtr*) below.
     40   explicit InterfaceRequest(InterfacePtr<Interface>* ptr,
     41                             scoped_refptr<base::SingleThreadTaskRunner> runner =
     42                                 base::ThreadTaskRunnerHandle::Get()) {
     43     MessagePipe pipe;
     44     ptr->Bind(InterfacePtrInfo<Interface>(std::move(pipe.handle0), 0u),
     45               std::move(runner));
     46     Bind(std::move(pipe.handle1));
     47   }
     48 
     49   // Takes the message pipe from another InterfaceRequest.
     50   InterfaceRequest(InterfaceRequest&& other) {
     51     handle_ = std::move(other.handle_);
     52   }
     53   InterfaceRequest& operator=(InterfaceRequest&& other) {
     54     handle_ = std::move(other.handle_);
     55     return *this;
     56   }
     57 
     58   // Assigning to nullptr resets the InterfaceRequest to an empty state,
     59   // closing the message pipe currently bound to it (if any).
     60   InterfaceRequest& operator=(decltype(nullptr)) {
     61     handle_.reset();
     62     return *this;
     63   }
     64 
     65   // Binds the request to a message pipe over which Interface is to be
     66   // requested.  If the request is already bound to a message pipe, the current
     67   // message pipe will be closed.
     68   void Bind(ScopedMessagePipeHandle handle) { handle_ = std::move(handle); }
     69 
     70   // Indicates whether the request currently contains a valid message pipe.
     71   bool is_pending() const { return handle_.is_valid(); }
     72 
     73   // Removes the message pipe from the request and returns it.
     74   ScopedMessagePipeHandle PassMessagePipe() { return std::move(handle_); }
     75 
     76   bool Equals(const InterfaceRequest& other) const {
     77     if (this == &other)
     78       return true;
     79 
     80     // Now that the two refer to different objects, they are equivalent if
     81     // and only if they are both invalid.
     82     return !is_pending() && !other.is_pending();
     83   }
     84 
     85   void ResetWithReason(uint32_t custom_reason, const std::string& description) {
     86     if (!handle_.is_valid())
     87       return;
     88 
     89     Message message =
     90         PipeControlMessageProxy::ConstructPeerEndpointClosedMessage(
     91             kMasterInterfaceId, DisconnectReason(custom_reason, description));
     92     MojoResult result = WriteMessageNew(
     93         handle_.get(), message.TakeMojoMessage(), MOJO_WRITE_MESSAGE_FLAG_NONE);
     94     DCHECK_EQ(MOJO_RESULT_OK, result);
     95 
     96     handle_.reset();
     97   }
     98 
     99  private:
    100   ScopedMessagePipeHandle handle_;
    101 
    102   DISALLOW_COPY_AND_ASSIGN(InterfaceRequest);
    103 };
    104 
    105 // Makes an InterfaceRequest bound to the specified message pipe. If |handle|
    106 // is empty or invalid, the resulting InterfaceRequest will represent the
    107 // absence of a request.
    108 template <typename Interface>
    109 InterfaceRequest<Interface> MakeRequest(ScopedMessagePipeHandle handle) {
    110   InterfaceRequest<Interface> request;
    111   request.Bind(std::move(handle));
    112   return std::move(request);
    113 }
    114 
    115 // Creates a new message pipe over which Interface is to be served. Binds the
    116 // specified InterfacePtr to one end of the message pipe, and returns an
    117 // InterfaceRequest bound to the other. The InterfacePtr should be passed to
    118 // the client, and the InterfaceRequest should be passed to whatever will
    119 // provide the implementation. The implementation should typically be bound to
    120 // the InterfaceRequest using the Binding or StrongBinding classes. The client
    121 // may begin to issue calls even before an implementation has been bound, since
    122 // messages sent over the pipe will just queue up until they are consumed by
    123 // the implementation.
    124 //
    125 // Example #1: Requesting a remote implementation of an interface.
    126 // ===============================================================
    127 //
    128 // Given the following interface:
    129 //
    130 //   interface Database {
    131 //     OpenTable(Table& table);
    132 //   }
    133 //
    134 // The client would have code similar to the following:
    135 //
    136 //   DatabasePtr database = ...;  // Connect to database.
    137 //   TablePtr table;
    138 //   database->OpenTable(MakeRequest(&table));
    139 //
    140 // Upon return from MakeRequest, |table| is ready to have methods called on it.
    141 //
    142 // Example #2: Registering a local implementation with a remote service.
    143 // =====================================================================
    144 //
    145 // Given the following interface
    146 //   interface Collector {
    147 //     RegisterSource(Source source);
    148 //   }
    149 //
    150 // The client would have code similar to the following:
    151 //
    152 //   CollectorPtr collector = ...;  // Connect to Collector.
    153 //   SourcePtr source;
    154 //   InterfaceRequest<Source> source_request(&source);
    155 //   collector->RegisterSource(std::move(source));
    156 //   CreateSource(std::move(source_request));  // Create implementation locally.
    157 //
    158 template <typename Interface>
    159 InterfaceRequest<Interface> MakeRequest(
    160     InterfacePtr<Interface>* ptr,
    161     scoped_refptr<base::SingleThreadTaskRunner> runner =
    162         base::ThreadTaskRunnerHandle::Get()) {
    163   return InterfaceRequest<Interface>(ptr, runner);
    164 }
    165 
    166 // Fuses an InterfaceRequest<T> endpoint with an InterfacePtrInfo<T> endpoint.
    167 // Returns |true| on success or |false| on failure.
    168 template <typename Interface>
    169 bool FuseInterface(InterfaceRequest<Interface> request,
    170                    InterfacePtrInfo<Interface> proxy_info) {
    171   MojoResult result = FuseMessagePipes(request.PassMessagePipe(),
    172                                        proxy_info.PassHandle());
    173   return result == MOJO_RESULT_OK;
    174 }
    175 
    176 }  // namespace mojo
    177 
    178 #endif  // MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_REQUEST_H_
    179