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