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.
InterfaceRequest()32 InterfaceRequest() {}
InterfaceRequest(decltype (nullptr))33 InterfaceRequest(decltype(nullptr)) {}
34
InterfaceRequest(ScopedMessagePipeHandle handle)35 explicit InterfaceRequest(ScopedMessagePipeHandle handle)
36 : handle_(std::move(handle)) {}
37
38 // Takes the message pipe from another InterfaceRequest.
InterfaceRequest(InterfaceRequest && other)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).
decltype(nullptr)49 InterfaceRequest& operator=(decltype(nullptr)) {
50 handle_.reset();
51 return *this;
52 }
53
54 // Indicates whether the request currently contains a valid message pipe.
is_pending()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.
PassMessagePipe()60 ScopedMessagePipeHandle PassMessagePipe() { return std::move(handle_); }
61
Equals(const InterfaceRequest & other)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
ResetWithReason(uint32_t custom_reason,const std::string & description)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>
MakeRequest(InterfacePtrInfo<Interface> * ptr_info)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>
FuseInterface(InterfaceRequest<Interface> request,InterfacePtrInfo<Interface> proxy_info)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