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#include "mojo/public/cpp/bindings/lib/router.h"
6
7#include "mojo/public/cpp/environment/logging.h"
8
9namespace mojo {
10namespace internal {
11
12// ----------------------------------------------------------------------------
13
14class ResponderThunk : public MessageReceiver {
15 public:
16  explicit ResponderThunk(const SharedData<Router*>& router)
17      : router_(router) {
18  }
19  virtual ~ResponderThunk() {
20  }
21
22  // MessageReceiver implementation:
23  virtual bool Accept(Message* message) MOJO_OVERRIDE {
24    MOJO_DCHECK(message->has_flag(kMessageIsResponse));
25
26    bool result = false;
27
28    Router* router = router_.value();
29    if (router)
30      result = router->Accept(message);
31
32    return result;
33  }
34
35 private:
36  SharedData<Router*> router_;
37};
38
39// ----------------------------------------------------------------------------
40
41Router::HandleIncomingMessageThunk::HandleIncomingMessageThunk(Router* router)
42    : router_(router) {
43}
44
45Router::HandleIncomingMessageThunk::~HandleIncomingMessageThunk() {
46}
47
48bool Router::HandleIncomingMessageThunk::Accept(Message* message) {
49  return router_->HandleIncomingMessage(message);
50}
51
52// ----------------------------------------------------------------------------
53
54Router::Router(ScopedMessagePipeHandle message_pipe,
55               FilterChain filters,
56               const MojoAsyncWaiter* waiter)
57    : thunk_(this),
58      filters_(filters.Pass()),
59      connector_(message_pipe.Pass(), waiter),
60      weak_self_(this),
61      incoming_receiver_(NULL),
62      next_request_id_(0),
63      testing_mode_(false) {
64  filters_.SetSink(&thunk_);
65  connector_.set_incoming_receiver(filters_.GetHead());
66}
67
68Router::~Router() {
69  weak_self_.set_value(NULL);
70
71  for (ResponderMap::const_iterator i = responders_.begin();
72       i != responders_.end(); ++i) {
73    delete i->second;
74  }
75}
76
77bool Router::Accept(Message* message) {
78  MOJO_DCHECK(!message->has_flag(kMessageExpectsResponse));
79  return connector_.Accept(message);
80}
81
82bool Router::AcceptWithResponder(Message* message,
83                                 MessageReceiver* responder) {
84  MOJO_DCHECK(message->has_flag(kMessageExpectsResponse));
85
86  // Reserve 0 in case we want it to convey special meaning in the future.
87  uint64_t request_id = next_request_id_++;
88  if (request_id == 0)
89    request_id = next_request_id_++;
90
91  message->set_request_id(request_id);
92  if (!connector_.Accept(message))
93    return false;
94
95  // We assume ownership of |responder|.
96  responders_[request_id] = responder;
97  return true;
98}
99
100void Router::EnableTestingMode() {
101  testing_mode_ = true;
102  connector_.set_enforce_errors_from_incoming_receiver(false);
103}
104
105bool Router::HandleIncomingMessage(Message* message) {
106  if (message->has_flag(kMessageExpectsResponse)) {
107    if (incoming_receiver_) {
108      MessageReceiver* responder = new ResponderThunk(weak_self_);
109      bool ok = incoming_receiver_->AcceptWithResponder(message, responder);
110      if (!ok)
111        delete responder;
112      return ok;
113    }
114
115    // If we receive a request expecting a response when the client is not
116    // listening, then we have no choice but to tear down the pipe.
117    connector_.CloseMessagePipe();
118  } else if (message->has_flag(kMessageIsResponse)) {
119    uint64_t request_id = message->request_id();
120    ResponderMap::iterator it = responders_.find(request_id);
121    if (it == responders_.end()) {
122      MOJO_DCHECK(testing_mode_);
123      return false;
124    }
125    MessageReceiver* responder = it->second;
126    responders_.erase(it);
127    bool ok = responder->Accept(message);
128    delete responder;
129    return ok;
130  } else {
131    if (incoming_receiver_)
132      return incoming_receiver_->Accept(message);
133    // OK to drop message on the floor.
134  }
135
136  return false;
137}
138
139// ----------------------------------------------------------------------------
140
141}  // namespace internal
142}  // namespace mojo
143