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