// 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_LIB_INTERFACE_PTR_INTERNAL_H_ #define MOJO_PUBLIC_CPP_BINDINGS_LIB_INTERFACE_PTR_INTERNAL_H_ #include // For |std::swap()|. #include "mojo/public/cpp/bindings/callback.h" #include "mojo/public/cpp/bindings/interface_ptr_info.h" #include "mojo/public/cpp/bindings/lib/control_message_proxy.h" #include "mojo/public/cpp/bindings/lib/filter_chain.h" #include "mojo/public/cpp/bindings/lib/message_header_validator.h" #include "mojo/public/cpp/bindings/lib/router.h" #include "mojo/public/cpp/environment/logging.h" struct MojoAsyncWaiter; namespace mojo { namespace internal { template class InterfacePtrState { public: InterfacePtrState() : proxy_(nullptr), router_(nullptr), waiter_(nullptr), version_(0u) {} ~InterfacePtrState() { // Destruction order matters here. We delete |proxy_| first, even though // |router_| may have a reference to it, so that destructors for any request // callbacks still pending can interact with the InterfacePtr. delete proxy_; delete router_; } Interface* instance() { ConfigureProxyIfNecessary(); // This will be null if the object is not bound. return proxy_; } uint32_t version() const { return version_; } void QueryVersion(const Callback& callback) { ConfigureProxyIfNecessary(); // It is safe to capture |this| because the callback won't be run after this // object goes away. auto callback_wrapper = [this, callback](uint32_t version) { this->version_ = version; callback.Run(version); }; // Do a static cast in case the interface contains methods with the same // name. static_cast(proxy_)->QueryVersion(callback_wrapper); } void RequireVersion(uint32_t version) { ConfigureProxyIfNecessary(); if (version <= version_) return; version_ = version; // Do a static cast in case the interface contains methods with the same // name. static_cast(proxy_)->RequireVersion(version); } void Swap(InterfacePtrState* other) { using std::swap; swap(other->proxy_, proxy_); swap(other->router_, router_); handle_.swap(other->handle_); swap(other->waiter_, waiter_); swap(other->version_, version_); } void Bind(InterfacePtrInfo info, const MojoAsyncWaiter* waiter) { MOJO_DCHECK(!proxy_); MOJO_DCHECK(!router_); MOJO_DCHECK(!handle_.is_valid()); MOJO_DCHECK(!waiter_); MOJO_DCHECK(version_ == 0u); MOJO_DCHECK(info.is_valid()); handle_ = info.PassHandle(); waiter_ = waiter; version_ = info.version(); } bool WaitForIncomingResponse() { ConfigureProxyIfNecessary(); MOJO_DCHECK(router_); return router_->WaitForIncomingMessage(MOJO_DEADLINE_INDEFINITE); } // After this method is called, the object is in an invalid state and // shouldn't be reused. InterfacePtrInfo PassInterface() { return InterfacePtrInfo( router_ ? router_->PassMessagePipe() : handle_.Pass(), version_); } bool is_bound() const { return handle_.is_valid() || router_; } bool encountered_error() const { return router_ ? router_->encountered_error() : false; } void set_connection_error_handler(const Closure& error_handler) { ConfigureProxyIfNecessary(); MOJO_DCHECK(router_); router_->set_connection_error_handler(error_handler); } Router* router_for_testing() { ConfigureProxyIfNecessary(); return router_; } private: using Proxy = typename Interface::Proxy_; void ConfigureProxyIfNecessary() { // The proxy has been configured. if (proxy_) { MOJO_DCHECK(router_); return; } // The object hasn't been bound. if (!waiter_) { MOJO_DCHECK(!handle_.is_valid()); return; } FilterChain filters; filters.Append(); filters.Append(); router_ = new Router(handle_.Pass(), filters.Pass(), waiter_); waiter_ = nullptr; proxy_ = new Proxy(router_); } Proxy* proxy_; Router* router_; // |proxy_| and |router_| are not initialized until read/write with the // message pipe handle is needed. |handle_| and |waiter_| are valid between // the Bind() call and the initialization of |proxy_| and |router_|. ScopedMessagePipeHandle handle_; const MojoAsyncWaiter* waiter_; uint32_t version_; MOJO_DISALLOW_COPY_AND_ASSIGN(InterfacePtrState); }; } // namespace internal } // namespace mojo #endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_INTERFACE_PTR_INTERNAL_H_