• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
InterfaceRequest()33   InterfaceRequest() {}
InterfaceRequest(decltype (nullptr))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.
InterfaceRequest(InterfaceRequest && other)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).
decltype(nullptr)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.
Bind(ScopedMessagePipeHandle handle)68   void Bind(ScopedMessagePipeHandle handle) { handle_ = std::move(handle); }
69 
70   // Indicates whether the request currently contains a valid message pipe.
is_pending()71   bool is_pending() const { return handle_.is_valid(); }
72 
73   // Removes the message pipe from the request and returns it.
PassMessagePipe()74   ScopedMessagePipeHandle PassMessagePipe() { return std::move(handle_); }
75 
Equals(const InterfaceRequest & other)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 
ResetWithReason(uint32_t custom_reason,const std::string & description)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>
MakeRequest(ScopedMessagePipeHandle handle)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>
FuseInterface(InterfaceRequest<Interface> request,InterfacePtrInfo<Interface> proxy_info)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