263 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			263 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
| // Copyright 2015 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_ASSOCIATED_INTERFACE_PTR_H_
 | |
| #define MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_INTERFACE_PTR_H_
 | |
| 
 | |
| #include <stdint.h>
 | |
| 
 | |
| #include <string>
 | |
| #include <utility>
 | |
| 
 | |
| #include "base/callback.h"
 | |
| #include "base/logging.h"
 | |
| #include "base/macros.h"
 | |
| #include "base/memory/ref_counted.h"
 | |
| #include "base/sequenced_task_runner.h"
 | |
| #include "mojo/public/cpp/bindings/associated_interface_ptr_info.h"
 | |
| #include "mojo/public/cpp/bindings/associated_interface_request.h"
 | |
| #include "mojo/public/cpp/bindings/bindings_export.h"
 | |
| #include "mojo/public/cpp/bindings/connection_error_callback.h"
 | |
| #include "mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h"
 | |
| #include "mojo/public/cpp/bindings/lib/multiplex_router.h"
 | |
| #include "mojo/public/cpp/system/message_pipe.h"
 | |
| 
 | |
| namespace mojo {
 | |
| 
 | |
| // Represents the client side of an associated interface. It is similar to
 | |
| // InterfacePtr, except that it doesn't own a message pipe handle.
 | |
| template <typename Interface>
 | |
| class AssociatedInterfacePtr {
 | |
|  public:
 | |
|   using InterfaceType = Interface;
 | |
|   using PtrInfoType = AssociatedInterfacePtrInfo<Interface>;
 | |
|   using Proxy = typename Interface::Proxy_;
 | |
| 
 | |
|   // Constructs an unbound AssociatedInterfacePtr.
 | |
|   AssociatedInterfacePtr() {}
 | |
|   AssociatedInterfacePtr(decltype(nullptr)) {}
 | |
| 
 | |
|   AssociatedInterfacePtr(AssociatedInterfacePtr&& other) {
 | |
|     internal_state_.Swap(&other.internal_state_);
 | |
|   }
 | |
| 
 | |
|   explicit AssociatedInterfacePtr(PtrInfoType&& info) { Bind(std::move(info)); }
 | |
| 
 | |
|   AssociatedInterfacePtr& operator=(AssociatedInterfacePtr&& other) {
 | |
|     reset();
 | |
|     internal_state_.Swap(&other.internal_state_);
 | |
|     return *this;
 | |
|   }
 | |
| 
 | |
|   // Assigning nullptr to this class causes it to closes the associated
 | |
|   // interface (if any) and returns the pointer to the unbound state.
 | |
|   AssociatedInterfacePtr& operator=(decltype(nullptr)) {
 | |
|     reset();
 | |
|     return *this;
 | |
|   }
 | |
| 
 | |
|   ~AssociatedInterfacePtr() {}
 | |
| 
 | |
|   // Sets up this object as the client side of an associated interface.
 | |
|   // Calling with an invalid |info| has the same effect as reset(). In this
 | |
|   // case, the AssociatedInterfacePtr is not considered as bound.
 | |
|   //
 | |
|   // Optionally, |runner| is a SequencedTaskRunner bound to the current sequence
 | |
|   // on which all callbacks and connection error notifications will be
 | |
|   // dispatched. It is only useful to specify this to use a different
 | |
|   // SequencedTaskRunner than SequencedTaskRunnerHandle::Get().
 | |
|   //
 | |
|   // NOTE: The corresponding AssociatedInterfaceRequest must be sent over
 | |
|   // another interface before using this object to make calls. Please see the
 | |
|   // comments of MakeRequest(AssociatedInterfacePtr<Interface>*) for more
 | |
|   // details.
 | |
|   void Bind(AssociatedInterfacePtrInfo<Interface> info,
 | |
|             scoped_refptr<base::SequencedTaskRunner> runner = nullptr) {
 | |
|     reset();
 | |
| 
 | |
|     if (info.is_valid())
 | |
|       internal_state_.Bind(std::move(info), std::move(runner));
 | |
|   }
 | |
| 
 | |
|   bool is_bound() const { return internal_state_.is_bound(); }
 | |
| 
 | |
|   Proxy* get() const { return internal_state_.instance(); }
 | |
| 
 | |
|   // Functions like a pointer to Interface. Must already be bound.
 | |
|   Proxy* operator->() const { return get(); }
 | |
|   Proxy& operator*() const { return *get(); }
 | |
| 
 | |
|   // Returns the version number of the interface that the remote side supports.
 | |
|   uint32_t version() const { return internal_state_.version(); }
 | |
| 
 | |
|   // Queries the max version that the remote side supports. On completion, the
 | |
|   // result will be returned as the input of |callback|. The version number of
 | |
|   // this object will also be updated.
 | |
|   void QueryVersion(const base::Callback<void(uint32_t)>& callback) {
 | |
|     internal_state_.QueryVersion(callback);
 | |
|   }
 | |
| 
 | |
|   // If the remote side doesn't support the specified version, it will close the
 | |
|   // associated interface asynchronously. This does nothing if it's already
 | |
|   // known that the remote side supports the specified version, i.e., if
 | |
|   // |version <= this->version()|.
 | |
|   //
 | |
|   // After calling RequireVersion() with a version not supported by the remote
 | |
|   // side, all subsequent calls to interface methods will be ignored.
 | |
|   void RequireVersion(uint32_t version) {
 | |
|     internal_state_.RequireVersion(version);
 | |
|   }
 | |
| 
 | |
|   // Sends a message on the underlying message pipe and runs the current
 | |
|   // message loop until its response is received. This can be used in tests to
 | |
|   // verify that no message was sent on a message pipe in response to some
 | |
|   // stimulus.
 | |
|   void FlushForTesting() { internal_state_.FlushForTesting(); }
 | |
| 
 | |
|   // Closes the associated interface (if any) and returns the pointer to the
 | |
|   // unbound state.
 | |
|   void reset() {
 | |
|     State doomed;
 | |
|     internal_state_.Swap(&doomed);
 | |
|   }
 | |
| 
 | |
|   // Similar to the method above, but also specifies a disconnect reason.
 | |
|   void ResetWithReason(uint32_t custom_reason, const std::string& description) {
 | |
|     if (internal_state_.is_bound())
 | |
|       internal_state_.CloseWithReason(custom_reason, description);
 | |
|     reset();
 | |
|   }
 | |
| 
 | |
|   // Indicates whether an error has been encountered. If true, method calls made
 | |
|   // on this interface will be dropped (and may already have been dropped).
 | |
|   bool encountered_error() const { return internal_state_.encountered_error(); }
 | |
| 
 | |
|   // Registers a handler to receive error notifications.
 | |
|   //
 | |
|   // This method may only be called after the AssociatedInterfacePtr has been
 | |
|   // bound.
 | |
|   void set_connection_error_handler(base::OnceClosure error_handler) {
 | |
|     internal_state_.set_connection_error_handler(std::move(error_handler));
 | |
|   }
 | |
| 
 | |
|   void set_connection_error_with_reason_handler(
 | |
|       ConnectionErrorWithReasonCallback error_handler) {
 | |
|     internal_state_.set_connection_error_with_reason_handler(
 | |
|         std::move(error_handler));
 | |
|   }
 | |
| 
 | |
|   // Unbinds and returns the associated interface pointer information which
 | |
|   // could be used to setup an AssociatedInterfacePtr again. This method may be
 | |
|   // used to move the proxy to a different sequence.
 | |
|   //
 | |
|   // It is an error to call PassInterface() while there are pending responses.
 | |
|   // TODO: fix this restriction, it's not always obvious when there is a
 | |
|   // pending response.
 | |
|   AssociatedInterfacePtrInfo<Interface> PassInterface() {
 | |
|     DCHECK(!internal_state_.has_pending_callbacks());
 | |
|     State state;
 | |
|     internal_state_.Swap(&state);
 | |
| 
 | |
|     return state.PassInterface();
 | |
|   }
 | |
| 
 | |
|   // DO NOT USE. Exposed only for internal use and for testing.
 | |
|   internal::AssociatedInterfacePtrState<Interface>* internal_state() {
 | |
|     return &internal_state_;
 | |
|   }
 | |
| 
 | |
|   // Allow AssociatedInterfacePtr<> to be used in boolean expressions.
 | |
|   explicit operator bool() const { return internal_state_.is_bound(); }
 | |
| 
 | |
|  private:
 | |
|   typedef internal::AssociatedInterfacePtrState<Interface> State;
 | |
|   mutable State internal_state_;
 | |
| 
 | |
|   DISALLOW_COPY_AND_ASSIGN(AssociatedInterfacePtr);
 | |
| };
 | |
| 
 | |
| // Creates an associated interface. The returned request is supposed to be sent
 | |
| // over another interface (either associated or non-associated).
 | |
| //
 | |
| // NOTE: |ptr| must NOT be used to make calls before the request is sent.
 | |
| // Violating that will lead to crash. On the other hand, as soon as the request
 | |
| // is sent, |ptr| is usable. There is no need to wait until the request is bound
 | |
| // to an implementation at the remote side.
 | |
| template <typename Interface>
 | |
| AssociatedInterfaceRequest<Interface> MakeRequest(
 | |
|     AssociatedInterfacePtr<Interface>* ptr,
 | |
|     scoped_refptr<base::SequencedTaskRunner> runner = nullptr) {
 | |
|   AssociatedInterfacePtrInfo<Interface> ptr_info;
 | |
|   auto request = MakeRequest(&ptr_info);
 | |
|   ptr->Bind(std::move(ptr_info), std::move(runner));
 | |
|   return request;
 | |
| }
 | |
| 
 | |
| // Creates an associated interface. One of the two endpoints is supposed to be
 | |
| // sent over another interface (either associated or non-associated); while the
 | |
| // other is used locally.
 | |
| //
 | |
| // NOTE: If |ptr_info| is used locally and bound to an AssociatedInterfacePtr,
 | |
| // the interface pointer must NOT be used to make calls before the request is
 | |
| // sent. Please see NOTE of the previous function for more details.
 | |
| template <typename Interface>
 | |
| AssociatedInterfaceRequest<Interface> MakeRequest(
 | |
|     AssociatedInterfacePtrInfo<Interface>* ptr_info) {
 | |
|   ScopedInterfaceEndpointHandle handle0;
 | |
|   ScopedInterfaceEndpointHandle handle1;
 | |
|   ScopedInterfaceEndpointHandle::CreatePairPendingAssociation(&handle0,
 | |
|                                                               &handle1);
 | |
| 
 | |
|   ptr_info->set_handle(std::move(handle0));
 | |
|   ptr_info->set_version(0);
 | |
| 
 | |
|   return AssociatedInterfaceRequest<Interface>(std::move(handle1));
 | |
| }
 | |
| 
 | |
| // Like MakeRequest() above, but it creates a dedicated message pipe. The
 | |
| // returned request can be bound directly to an implementation, without being
 | |
| // first passed through a message pipe endpoint.
 | |
| //
 | |
| // This function has two main uses:
 | |
| //
 | |
| //  * In testing, where the returned request is bound to e.g. a mock and there
 | |
| //    are no other interfaces involved.
 | |
| //
 | |
| //  * When discarding messages sent on an interface, which can be done by
 | |
| //    discarding the returned request.
 | |
| template <typename Interface>
 | |
| AssociatedInterfaceRequest<Interface> MakeRequestAssociatedWithDedicatedPipe(
 | |
|     AssociatedInterfacePtr<Interface>* ptr) {
 | |
|   MessagePipe pipe;
 | |
|   scoped_refptr<internal::MultiplexRouter> router0 =
 | |
|       new internal::MultiplexRouter(
 | |
|           std::move(pipe.handle0), internal::MultiplexRouter::MULTI_INTERFACE,
 | |
|           false, base::SequencedTaskRunnerHandle::Get());
 | |
|   scoped_refptr<internal::MultiplexRouter> router1 =
 | |
|       new internal::MultiplexRouter(
 | |
|           std::move(pipe.handle1), internal::MultiplexRouter::MULTI_INTERFACE,
 | |
|           true, base::SequencedTaskRunnerHandle::Get());
 | |
| 
 | |
|   ScopedInterfaceEndpointHandle endpoint0, endpoint1;
 | |
|   ScopedInterfaceEndpointHandle::CreatePairPendingAssociation(&endpoint0,
 | |
|                                                               &endpoint1);
 | |
|   InterfaceId id = router1->AssociateInterface(std::move(endpoint0));
 | |
|   endpoint0 = router0->CreateLocalEndpointHandle(id);
 | |
| 
 | |
|   ptr->Bind(AssociatedInterfacePtrInfo<Interface>(std::move(endpoint0),
 | |
|                                                   Interface::Version_));
 | |
|   return AssociatedInterfaceRequest<Interface>(std::move(endpoint1));
 | |
| }
 | |
| 
 | |
| // |handle| is supposed to be the request of an associated interface. This
 | |
| // method associates the interface with a dedicated, disconnected message pipe.
 | |
| // That way, the corresponding associated interface pointer of |handle| can
 | |
| // safely make calls (although those calls are silently dropped).
 | |
| MOJO_CPP_BINDINGS_EXPORT void AssociateWithDisconnectedPipe(
 | |
|     ScopedInterfaceEndpointHandle handle);
 | |
| 
 | |
| }  // namespace mojo
 | |
| 
 | |
| #endif  // MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_INTERFACE_PTR_H_
 |