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. 33 InterfaceRequest() {} 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. 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). 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. 68 void Bind(ScopedMessagePipeHandle handle) { handle_ = std::move(handle); } 69 70 // Indicates whether the request currently contains a valid message pipe. 71 bool is_pending() const { return handle_.is_valid(); } 72 73 // Removes the message pipe from the request and returns it. 74 ScopedMessagePipeHandle PassMessagePipe() { return std::move(handle_); } 75 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 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> 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> 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