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_LIB_INTERFACE_PTR_STATE_H_ 6 #define MOJO_PUBLIC_CPP_BINDINGS_LIB_INTERFACE_PTR_STATE_H_ 7 8 #include <stdint.h> 9 10 #include <algorithm> // For |std::swap()|. 11 #include <memory> 12 #include <string> 13 #include <utility> 14 15 #include "base/bind.h" 16 #include "base/callback_forward.h" 17 #include "base/logging.h" 18 #include "base/macros.h" 19 #include "base/memory/ptr_util.h" 20 #include "base/memory/ref_counted.h" 21 #include "base/single_thread_task_runner.h" 22 #include "mojo/public/cpp/bindings/associated_group.h" 23 #include "mojo/public/cpp/bindings/connection_error_callback.h" 24 #include "mojo/public/cpp/bindings/filter_chain.h" 25 #include "mojo/public/cpp/bindings/interface_endpoint_client.h" 26 #include "mojo/public/cpp/bindings/interface_id.h" 27 #include "mojo/public/cpp/bindings/interface_ptr_info.h" 28 #include "mojo/public/cpp/bindings/lib/multiplex_router.h" 29 #include "mojo/public/cpp/bindings/message_header_validator.h" 30 #include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h" 31 32 namespace mojo { 33 namespace internal { 34 35 template <typename Interface> 36 class InterfacePtrState { 37 public: InterfacePtrState()38 InterfacePtrState() : version_(0u) {} 39 ~InterfacePtrState()40 ~InterfacePtrState() { 41 endpoint_client_.reset(); 42 proxy_.reset(); 43 if (router_) 44 router_->CloseMessagePipe(); 45 } 46 instance()47 Interface* instance() { 48 ConfigureProxyIfNecessary(); 49 50 // This will be null if the object is not bound. 51 return proxy_.get(); 52 } 53 version()54 uint32_t version() const { return version_; } 55 QueryVersion(const base::Callback<void (uint32_t)> & callback)56 void QueryVersion(const base::Callback<void(uint32_t)>& callback) { 57 ConfigureProxyIfNecessary(); 58 59 // It is safe to capture |this| because the callback won't be run after this 60 // object goes away. 61 endpoint_client_->QueryVersion(base::Bind( 62 &InterfacePtrState::OnQueryVersion, base::Unretained(this), callback)); 63 } 64 RequireVersion(uint32_t version)65 void RequireVersion(uint32_t version) { 66 ConfigureProxyIfNecessary(); 67 68 if (version <= version_) 69 return; 70 71 version_ = version; 72 endpoint_client_->RequireVersion(version); 73 } 74 FlushForTesting()75 void FlushForTesting() { 76 ConfigureProxyIfNecessary(); 77 endpoint_client_->FlushForTesting(); 78 } 79 CloseWithReason(uint32_t custom_reason,const std::string & description)80 void CloseWithReason(uint32_t custom_reason, const std::string& description) { 81 ConfigureProxyIfNecessary(); 82 endpoint_client_->CloseWithReason(custom_reason, description); 83 } 84 Swap(InterfacePtrState * other)85 void Swap(InterfacePtrState* other) { 86 using std::swap; 87 swap(other->router_, router_); 88 swap(other->endpoint_client_, endpoint_client_); 89 swap(other->proxy_, proxy_); 90 handle_.swap(other->handle_); 91 runner_.swap(other->runner_); 92 swap(other->version_, version_); 93 } 94 Bind(InterfacePtrInfo<Interface> info,scoped_refptr<base::SingleThreadTaskRunner> runner)95 void Bind(InterfacePtrInfo<Interface> info, 96 scoped_refptr<base::SingleThreadTaskRunner> runner) { 97 DCHECK(!router_); 98 DCHECK(!endpoint_client_); 99 DCHECK(!proxy_); 100 DCHECK(!handle_.is_valid()); 101 DCHECK_EQ(0u, version_); 102 DCHECK(info.is_valid()); 103 104 handle_ = info.PassHandle(); 105 version_ = info.version(); 106 runner_ = std::move(runner); 107 } 108 HasAssociatedInterfaces()109 bool HasAssociatedInterfaces() const { 110 return router_ ? router_->HasAssociatedEndpoints() : false; 111 } 112 113 // After this method is called, the object is in an invalid state and 114 // shouldn't be reused. PassInterface()115 InterfacePtrInfo<Interface> PassInterface() { 116 endpoint_client_.reset(); 117 proxy_.reset(); 118 return InterfacePtrInfo<Interface>( 119 router_ ? router_->PassMessagePipe() : std::move(handle_), version_); 120 } 121 is_bound()122 bool is_bound() const { return handle_.is_valid() || endpoint_client_; } 123 encountered_error()124 bool encountered_error() const { 125 return endpoint_client_ ? endpoint_client_->encountered_error() : false; 126 } 127 set_connection_error_handler(const base::Closure & error_handler)128 void set_connection_error_handler(const base::Closure& error_handler) { 129 ConfigureProxyIfNecessary(); 130 131 DCHECK(endpoint_client_); 132 endpoint_client_->set_connection_error_handler(error_handler); 133 } 134 set_connection_error_with_reason_handler(const ConnectionErrorWithReasonCallback & error_handler)135 void set_connection_error_with_reason_handler( 136 const ConnectionErrorWithReasonCallback& error_handler) { 137 ConfigureProxyIfNecessary(); 138 139 DCHECK(endpoint_client_); 140 endpoint_client_->set_connection_error_with_reason_handler(error_handler); 141 } 142 143 // Returns true if bound and awaiting a response to a message. has_pending_callbacks()144 bool has_pending_callbacks() const { 145 return endpoint_client_ && endpoint_client_->has_pending_responders(); 146 } 147 associated_group()148 AssociatedGroup* associated_group() { 149 ConfigureProxyIfNecessary(); 150 return endpoint_client_->associated_group(); 151 } 152 EnableTestingMode()153 void EnableTestingMode() { 154 ConfigureProxyIfNecessary(); 155 router_->EnableTestingMode(); 156 } 157 ForwardMessage(Message message)158 void ForwardMessage(Message message) { 159 ConfigureProxyIfNecessary(); 160 endpoint_client_->Accept(&message); 161 } 162 ForwardMessageWithResponder(Message message,std::unique_ptr<MessageReceiver> responder)163 void ForwardMessageWithResponder(Message message, 164 std::unique_ptr<MessageReceiver> responder) { 165 ConfigureProxyIfNecessary(); 166 endpoint_client_->AcceptWithResponder(&message, responder.release()); 167 } 168 169 private: 170 using Proxy = typename Interface::Proxy_; 171 ConfigureProxyIfNecessary()172 void ConfigureProxyIfNecessary() { 173 // The proxy has been configured. 174 if (proxy_) { 175 DCHECK(router_); 176 DCHECK(endpoint_client_); 177 return; 178 } 179 // The object hasn't been bound. 180 if (!handle_.is_valid()) 181 return; 182 183 MultiplexRouter::Config config = 184 Interface::PassesAssociatedKinds_ 185 ? MultiplexRouter::MULTI_INTERFACE 186 : (Interface::HasSyncMethods_ 187 ? MultiplexRouter::SINGLE_INTERFACE_WITH_SYNC_METHODS 188 : MultiplexRouter::SINGLE_INTERFACE); 189 router_ = new MultiplexRouter(std::move(handle_), config, true, runner_); 190 router_->SetMasterInterfaceName(Interface::Name_); 191 endpoint_client_.reset(new InterfaceEndpointClient( 192 router_->CreateLocalEndpointHandle(kMasterInterfaceId), nullptr, 193 base::WrapUnique(new typename Interface::ResponseValidator_()), false, 194 std::move(runner_), 195 // The version is only queried from the client so the value passed here 196 // will not be used. 197 0u)); 198 proxy_.reset(new Proxy(endpoint_client_.get())); 199 } 200 OnQueryVersion(const base::Callback<void (uint32_t)> & callback,uint32_t version)201 void OnQueryVersion(const base::Callback<void(uint32_t)>& callback, 202 uint32_t version) { 203 version_ = version; 204 callback.Run(version); 205 } 206 207 scoped_refptr<MultiplexRouter> router_; 208 209 std::unique_ptr<InterfaceEndpointClient> endpoint_client_; 210 std::unique_ptr<Proxy> proxy_; 211 212 // |router_| (as well as other members above) is not initialized until 213 // read/write with the message pipe handle is needed. |handle_| is valid 214 // between the Bind() call and the initialization of |router_|. 215 ScopedMessagePipeHandle handle_; 216 scoped_refptr<base::SingleThreadTaskRunner> runner_; 217 218 uint32_t version_; 219 220 DISALLOW_COPY_AND_ASSIGN(InterfacePtrState); 221 }; 222 223 } // namespace internal 224 } // namespace mojo 225 226 #endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_INTERFACE_PTR_STATE_H_ 227