// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_REQUEST_H_ #define MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_REQUEST_H_ #include <string> #include <utility> #include "base/macros.h" #include "base/optional.h" #include "base/single_thread_task_runner.h" #include "mojo/public/cpp/bindings/disconnect_reason.h" #include "mojo/public/cpp/bindings/interface_ptr.h" #include "mojo/public/cpp/bindings/pipe_control_message_proxy.h" #include "mojo/public/cpp/system/message_pipe.h" namespace mojo { // Represents a request from a remote client for an implementation of Interface // over a specified message pipe. The implementor of the interface should // remove the message pipe by calling PassMessagePipe() and bind it to the // implementation. If this is not done, the InterfaceRequest will automatically // close the pipe on destruction. Can also represent the absence of a request // if the client did not provide a message pipe. template <typename Interface> class InterfaceRequest { public: // Constructs an empty InterfaceRequest, representing that the client is not // requesting an implementation of Interface. InterfaceRequest() {} InterfaceRequest(decltype(nullptr)) {} explicit InterfaceRequest(ScopedMessagePipeHandle handle) : handle_(std::move(handle)) {} // Takes the message pipe from another InterfaceRequest. InterfaceRequest(InterfaceRequest&& other) { handle_ = std::move(other.handle_); } InterfaceRequest& operator=(InterfaceRequest&& other) { handle_ = std::move(other.handle_); return *this; } // Assigning to nullptr resets the InterfaceRequest to an empty state, // closing the message pipe currently bound to it (if any). InterfaceRequest& operator=(decltype(nullptr)) { handle_.reset(); return *this; } // Indicates whether the request currently contains a valid message pipe. bool is_pending() const { return handle_.is_valid(); } explicit operator bool() const { return handle_.is_valid(); } // Removes the message pipe from the request and returns it. ScopedMessagePipeHandle PassMessagePipe() { return std::move(handle_); } bool Equals(const InterfaceRequest& other) const { if (this == &other) return true; // Now that the two refer to different objects, they are equivalent if // and only if they are both invalid. return !is_pending() && !other.is_pending(); } void ResetWithReason(uint32_t custom_reason, const std::string& description) { if (!handle_.is_valid()) return; Message message = PipeControlMessageProxy::ConstructPeerEndpointClosedMessage( kMasterInterfaceId, DisconnectReason(custom_reason, description)); MojoResult result = WriteMessageNew( handle_.get(), message.TakeMojoMessage(), MOJO_WRITE_MESSAGE_FLAG_NONE); DCHECK_EQ(MOJO_RESULT_OK, result); handle_.reset(); } private: ScopedMessagePipeHandle handle_; DISALLOW_COPY_AND_ASSIGN(InterfaceRequest); }; // Creates a new message pipe over which Interface is to be served. Binds the // specified InterfacePtr to one end of the message pipe, and returns an // InterfaceRequest bound to the other. The InterfacePtr should be passed to // the client, and the InterfaceRequest should be passed to whatever will // provide the implementation. The implementation should typically be bound to // the InterfaceRequest using the Binding or StrongBinding classes. The client // may begin to issue calls even before an implementation has been bound, since // messages sent over the pipe will just queue up until they are consumed by // the implementation. // // Example #1: Requesting a remote implementation of an interface. // =============================================================== // // Given the following interface: // // interface Database { // OpenTable(Table& table); // } // // The client would have code similar to the following: // // DatabasePtr database = ...; // Connect to database. // TablePtr table; // database->OpenTable(MakeRequest(&table)); // // Upon return from MakeRequest, |table| is ready to have methods called on it. // // Example #2: Registering a local implementation with a remote service. // ===================================================================== // // Given the following interface // interface Collector { // RegisterSource(Source source); // } // // The client would have code similar to the following: // // CollectorPtr collector = ...; // Connect to Collector. // SourcePtr source; // InterfaceRequest<Source> source_request(&source); // collector->RegisterSource(std::move(source)); // CreateSource(std::move(source_request)); // Create implementation locally. // template <typename Interface> InterfaceRequest<Interface> MakeRequest( InterfacePtr<Interface>* ptr, scoped_refptr<base::SingleThreadTaskRunner> runner = nullptr) { MessagePipe pipe; ptr->Bind(InterfacePtrInfo<Interface>(std::move(pipe.handle0), 0u), std::move(runner)); return InterfaceRequest<Interface>(std::move(pipe.handle1)); } // Similar to the constructor above, but binds one end of the message pipe to // an InterfacePtrInfo instance. template <typename Interface> InterfaceRequest<Interface> MakeRequest(InterfacePtrInfo<Interface>* ptr_info) { MessagePipe pipe; ptr_info->set_handle(std::move(pipe.handle0)); ptr_info->set_version(0u); return InterfaceRequest<Interface>(std::move(pipe.handle1)); } // Fuses an InterfaceRequest<T> endpoint with an InterfacePtrInfo<T> endpoint. // Returns |true| on success or |false| on failure. template <typename Interface> bool FuseInterface(InterfaceRequest<Interface> request, InterfacePtrInfo<Interface> proxy_info) { MojoResult result = FuseMessagePipes(request.PassMessagePipe(), proxy_info.PassHandle()); return result == MOJO_RESULT_OK; } } // namespace mojo #endif // MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_REQUEST_H_