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. 32 InterfaceRequest() {} 33 InterfaceRequest(decltype(nullptr)) {} 34 35 explicit InterfaceRequest(ScopedMessagePipeHandle handle) 36 : handle_(std::move(handle)) {} 37 38 // Takes the message pipe from another InterfaceRequest. 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). 49 InterfaceRequest& operator=(decltype(nullptr)) { 50 handle_.reset(); 51 return *this; 52 } 53 54 // Indicates whether the request currently contains a valid message pipe. 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. 60 ScopedMessagePipeHandle PassMessagePipe() { return std::move(handle_); } 61 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 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> 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> 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