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_IMPL_INTERNAL_H_ 6#define MOJO_PUBLIC_CPP_BINDINGS_LIB_INTERFACE_IMPL_INTERNAL_H_ 7 8#include "mojo/public/cpp/bindings/error_handler.h" 9#include "mojo/public/cpp/bindings/interface_ptr.h" 10#include "mojo/public/cpp/bindings/lib/filter_chain.h" 11#include "mojo/public/cpp/bindings/lib/message_header_validator.h" 12#include "mojo/public/cpp/environment/environment.h" 13#include "mojo/public/cpp/environment/logging.h" 14#include "mojo/public/cpp/system/macros.h" 15 16namespace mojo { 17namespace internal { 18 19template <typename Interface> 20class InterfaceImplBase : public Interface { 21 public: 22 virtual ~InterfaceImplBase() {} 23 virtual void OnConnectionEstablished() = 0; 24 virtual void OnConnectionError() = 0; 25}; 26 27template <typename Interface> 28class InterfaceImplState : public ErrorHandler { 29 public: 30 typedef typename Interface::Client Client; 31 32 explicit InterfaceImplState(InterfaceImplBase<Interface>* instance) 33 : router_(NULL), 34 proxy_(NULL), 35 instance_bound_to_pipe_(false) 36#ifndef NDEBUG 37 , 38 deleting_instance_due_to_error_(false) 39#endif 40 { 41 MOJO_DCHECK(instance); 42 stub_.set_sink(instance); 43 } 44 45 virtual ~InterfaceImplState() { 46#ifndef NDEBUG 47 MOJO_DCHECK(!instance_bound_to_pipe_ || deleting_instance_due_to_error_); 48#endif 49 delete proxy_; 50 if (router_) { 51 router_->set_error_handler(NULL); 52 delete router_; 53 } 54 } 55 56 void BindProxy( 57 InterfacePtr<Interface>* ptr, 58 bool instance_bound_to_pipe, 59 const MojoAsyncWaiter* waiter = Environment::GetDefaultAsyncWaiter()) { 60 MessagePipe pipe; 61 ptr->Bind(pipe.handle0.Pass(), waiter); 62 Bind(pipe.handle1.Pass(), instance_bound_to_pipe, waiter); 63 } 64 65 void Bind(ScopedMessagePipeHandle handle, 66 bool instance_bound_to_pipe, 67 const MojoAsyncWaiter* waiter) { 68 MOJO_CHECK(!router_); 69 70 FilterChain filters; 71 filters.Append<MessageHeaderValidator>(); 72 filters.Append<typename Interface::RequestValidator_>(); 73 filters.Append<typename Interface::Client::ResponseValidator_>(); 74 75 router_ = new Router(handle.Pass(), filters.Pass(), waiter); 76 router_->set_incoming_receiver(&stub_); 77 router_->set_error_handler(this); 78 79 proxy_ = new typename Client::Proxy_(router_); 80 81 instance_bound_to_pipe_ = instance_bound_to_pipe; 82 83 instance()->OnConnectionEstablished(); 84 } 85 86 bool WaitForIncomingMethodCall() { 87 MOJO_DCHECK(router_); 88 return router_->WaitForIncomingMessage(); 89 } 90 91 Router* router() { return router_; } 92 Client* client() { return proxy_; } 93 94 private: 95 InterfaceImplBase<Interface>* instance() { 96 return static_cast<InterfaceImplBase<Interface>*>(stub_.sink()); 97 } 98 99 virtual void OnConnectionError() MOJO_OVERRIDE { 100 // If the the instance is not bound to the pipe, the instance might choose 101 // to delete itself in the OnConnectionError handler, which would in turn 102 // delete this. Save the error behavior before invoking the error handler 103 // so we can correctly decide what to do. 104 bool bound = instance_bound_to_pipe_; 105 instance()->OnConnectionError(); 106 if (!bound) 107 return; 108#ifndef NDEBUG 109 deleting_instance_due_to_error_ = true; 110#endif 111 delete instance(); 112 } 113 114 Router* router_; 115 typename Client::Proxy_* proxy_; 116 typename Interface::Stub_ stub_; 117 bool instance_bound_to_pipe_; 118#ifndef NDEBUG 119 bool deleting_instance_due_to_error_; 120#endif 121 122 MOJO_DISALLOW_COPY_AND_ASSIGN(InterfaceImplState); 123}; 124 125} // namespace internal 126} // namespace mojo 127 128#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_INTERFACE_IMPL_INTERNAL_H_ 129