• 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 "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