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