1645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// Copyright 2014 The Chromium Authors. All rights reserved.
2645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// Use of this source code is governed by a BSD-style license that can be
3645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// found in the LICENSE file.
4645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
5645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "mojo/public/cpp/bindings/lib/router.h"
6645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
7645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include <stdint.h>
8645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
9645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include <utility>
10645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
11645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "base/bind.h"
12645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "base/location.h"
13645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "base/logging.h"
14645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "base/memory/ptr_util.h"
15645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "base/stl_util.h"
16645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "mojo/public/cpp/bindings/sync_call_restrictions.h"
17645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
18645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chaveznamespace mojo {
19645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chaveznamespace internal {
20645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
21645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// ----------------------------------------------------------------------------
22645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
23645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chaveznamespace {
24645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
25645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezvoid DCheckIfInvalid(const base::WeakPtr<Router>& router,
26645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                   const std::string& message) {
27645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  bool is_valid = router && !router->encountered_error() && router->is_valid();
28645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK(!is_valid) << message;
29645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
30645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
31645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezclass ResponderThunk : public MessageReceiverWithStatus {
32645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez public:
33645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  explicit ResponderThunk(const base::WeakPtr<Router>& router,
34645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                          scoped_refptr<base::SingleThreadTaskRunner> runner)
35645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      : router_(router),
36645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        accept_was_invoked_(false),
37645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        task_runner_(std::move(runner)) {}
38645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  ~ResponderThunk() override {
39645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (!accept_was_invoked_) {
40645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      // The Mojo application handled a message that was expecting a response
41645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      // but did not send a response.
42645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      // We raise an error to signal the calling application that an error
43645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      // condition occurred. Without this the calling application would have no
44645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      // way of knowing it should stop waiting for a response.
45645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      if (task_runner_->RunsTasksOnCurrentThread()) {
46645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        // Please note that even if this code is run from a different task
47645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        // runner on the same thread as |task_runner_|, it is okay to directly
48645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        // call Router::RaiseError(), because it will raise error from the
49645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        // correct task runner asynchronously.
50645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        if (router_)
51645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez          router_->RaiseError();
52645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      } else {
53645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        task_runner_->PostTask(FROM_HERE,
54645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                               base::Bind(&Router::RaiseError, router_));
55645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      }
56645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
57645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
58645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
59645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // MessageReceiver implementation:
60645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  bool Accept(Message* message) override {
61645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    DCHECK(task_runner_->RunsTasksOnCurrentThread());
62645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    accept_was_invoked_ = true;
63645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    DCHECK(message->has_flag(Message::kFlagIsResponse));
64645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
65645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    bool result = false;
66645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
67645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (router_)
68645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      result = router_->Accept(message);
69645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
70645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return result;
71645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
72645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
73645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // MessageReceiverWithStatus implementation:
74645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  bool IsValid() override {
75645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    DCHECK(task_runner_->RunsTasksOnCurrentThread());
76645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return router_ && !router_->encountered_error() && router_->is_valid();
77645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
78645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
79645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  void DCheckInvalid(const std::string& message) override {
80645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (task_runner_->RunsTasksOnCurrentThread()) {
81645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      DCheckIfInvalid(router_, message);
82645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    } else {
83645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      task_runner_->PostTask(FROM_HERE,
84645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                             base::Bind(&DCheckIfInvalid, router_, message));
85645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
86645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
87645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
88645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez private:
89645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  base::WeakPtr<Router> router_;
90645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  bool accept_was_invoked_;
91645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
92645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez};
93645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
94645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}  // namespace
95645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
96645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// ----------------------------------------------------------------------------
97645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
98645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector ChavezRouter::SyncResponseInfo::SyncResponseInfo(bool* in_response_received)
99645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    : response_received(in_response_received) {}
100645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
101645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector ChavezRouter::SyncResponseInfo::~SyncResponseInfo() {}
102645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
103645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// ----------------------------------------------------------------------------
104645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
105645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector ChavezRouter::HandleIncomingMessageThunk::HandleIncomingMessageThunk(Router* router)
106645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    : router_(router) {
107645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
108645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
109645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector ChavezRouter::HandleIncomingMessageThunk::~HandleIncomingMessageThunk() {
110645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
111645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
112645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezbool Router::HandleIncomingMessageThunk::Accept(Message* message) {
113645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  return router_->HandleIncomingMessage(message);
114645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
115645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
116645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// ----------------------------------------------------------------------------
117645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
118645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector ChavezRouter::Router(ScopedMessagePipeHandle message_pipe,
119645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez               FilterChain filters,
120645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez               bool expects_sync_requests,
121645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez               scoped_refptr<base::SingleThreadTaskRunner> runner)
122645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    : thunk_(this),
123645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      filters_(std::move(filters)),
124645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      connector_(std::move(message_pipe),
125645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                 Connector::SINGLE_THREADED_SEND,
126645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                 std::move(runner)),
127645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      incoming_receiver_(nullptr),
128645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      next_request_id_(0),
129645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      testing_mode_(false),
130645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      pending_task_for_messages_(false),
131645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      encountered_error_(false),
132645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      weak_factory_(this) {
133645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  filters_.SetSink(&thunk_);
134645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (expects_sync_requests)
135645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    connector_.AllowWokenUpBySyncWatchOnSameThread();
136645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  connector_.set_incoming_receiver(filters_.GetHead());
137645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  connector_.set_connection_error_handler(
138645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      base::Bind(&Router::OnConnectionError, base::Unretained(this)));
139645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
140645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
141645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector ChavezRouter::~Router() {}
142645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
143645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezbool Router::Accept(Message* message) {
144645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK(thread_checker_.CalledOnValidThread());
145645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK(!message->has_flag(Message::kFlagExpectsResponse));
146645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  return connector_.Accept(message);
147645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
148645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
149645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezbool Router::AcceptWithResponder(Message* message, MessageReceiver* responder) {
150645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK(thread_checker_.CalledOnValidThread());
151645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK(message->has_flag(Message::kFlagExpectsResponse));
152645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
153645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // Reserve 0 in case we want it to convey special meaning in the future.
154645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  uint64_t request_id = next_request_id_++;
155645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (request_id == 0)
156645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    request_id = next_request_id_++;
157645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
158645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  bool is_sync = message->has_flag(Message::kFlagIsSync);
159645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  message->set_request_id(request_id);
160645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (!connector_.Accept(message))
161645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return false;
162645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
163645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (!is_sync) {
164645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // We assume ownership of |responder|.
165645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    async_responders_[request_id] = base::WrapUnique(responder);
166645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return true;
167645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
168645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
169645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  SyncCallRestrictions::AssertSyncCallAllowed();
170645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
171645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  bool response_received = false;
172645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  std::unique_ptr<MessageReceiver> sync_responder(responder);
173645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  sync_responses_.insert(std::make_pair(
174645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      request_id, base::WrapUnique(new SyncResponseInfo(&response_received))));
175645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
176645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  base::WeakPtr<Router> weak_self = weak_factory_.GetWeakPtr();
177645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  connector_.SyncWatch(&response_received);
178645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // Make sure that this instance hasn't been destroyed.
179645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (weak_self) {
180645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    DCHECK(ContainsKey(sync_responses_, request_id));
181645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    auto iter = sync_responses_.find(request_id);
182645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    DCHECK_EQ(&response_received, iter->second->response_received);
183645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (response_received) {
184645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      std::unique_ptr<Message> response = std::move(iter->second->response);
185645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      ignore_result(sync_responder->Accept(response.get()));
186645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
187645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    sync_responses_.erase(iter);
188645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
189645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
190645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // Return true means that we take ownership of |responder|.
191645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  return true;
192645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
193645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
194645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezvoid Router::EnableTestingMode() {
195645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK(thread_checker_.CalledOnValidThread());
196645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  testing_mode_ = true;
197645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  connector_.set_enforce_errors_from_incoming_receiver(false);
198645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
199645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
200645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezbool Router::HandleIncomingMessage(Message* message) {
201645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK(thread_checker_.CalledOnValidThread());
202645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
203645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  const bool during_sync_call =
204645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      connector_.during_sync_handle_watcher_callback();
205645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (!message->has_flag(Message::kFlagIsSync) &&
206645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      (during_sync_call || !pending_messages_.empty())) {
207645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    std::unique_ptr<Message> pending_message(new Message);
208645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    message->MoveTo(pending_message.get());
209645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    pending_messages_.push(std::move(pending_message));
210645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
211645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (!pending_task_for_messages_) {
212645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      pending_task_for_messages_ = true;
213645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      connector_.task_runner()->PostTask(
214645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez          FROM_HERE, base::Bind(&Router::HandleQueuedMessages,
215645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                                weak_factory_.GetWeakPtr()));
216645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
217645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
218645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return true;
219645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
220645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
221645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  return HandleMessageInternal(message);
222645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
223645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
224645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezvoid Router::HandleQueuedMessages() {
225645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK(thread_checker_.CalledOnValidThread());
226645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK(pending_task_for_messages_);
227645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
228645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  base::WeakPtr<Router> weak_self = weak_factory_.GetWeakPtr();
229645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  while (!pending_messages_.empty()) {
230645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    std::unique_ptr<Message> message(std::move(pending_messages_.front()));
231645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    pending_messages_.pop();
232645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
233645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    bool result = HandleMessageInternal(message.get());
234645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (!weak_self)
235645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      return;
236645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
237645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (!result && !testing_mode_) {
238645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      connector_.RaiseError();
239645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      break;
240645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
241645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
242645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
243645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  pending_task_for_messages_ = false;
244645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
245645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // We may have already seen a connection error from the connector, but
246645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // haven't notified the user because we want to process all the queued
247645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // messages first. We should do it now.
248645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (connector_.encountered_error() && !encountered_error_)
249645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    OnConnectionError();
250645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
251645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
252645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezbool Router::HandleMessageInternal(Message* message) {
253645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (message->has_flag(Message::kFlagExpectsResponse)) {
254645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (!incoming_receiver_)
255645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      return false;
256645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
257645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    MessageReceiverWithStatus* responder = new ResponderThunk(
258645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        weak_factory_.GetWeakPtr(), connector_.task_runner());
259645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    bool ok = incoming_receiver_->AcceptWithResponder(message, responder);
260645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (!ok)
261645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      delete responder;
262645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return ok;
263645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
264645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  } else if (message->has_flag(Message::kFlagIsResponse)) {
265645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    uint64_t request_id = message->request_id();
266645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
267645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (message->has_flag(Message::kFlagIsSync)) {
268645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      auto it = sync_responses_.find(request_id);
269645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      if (it == sync_responses_.end()) {
270645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        DCHECK(testing_mode_);
271645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return false;
272645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      }
273645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      it->second->response.reset(new Message());
274645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      message->MoveTo(it->second->response.get());
275645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      *it->second->response_received = true;
276645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      return true;
277645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
278645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
279645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    auto it = async_responders_.find(request_id);
280645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (it == async_responders_.end()) {
281645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      DCHECK(testing_mode_);
282645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      return false;
283645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
284645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    std::unique_ptr<MessageReceiver> responder = std::move(it->second);
285645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    async_responders_.erase(it);
286645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return responder->Accept(message);
287645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  } else {
288645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (!incoming_receiver_)
289645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      return false;
290645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
291645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return incoming_receiver_->Accept(message);
292645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
293645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
294645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
295645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezvoid Router::OnConnectionError() {
296645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (encountered_error_)
297645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return;
298645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
299645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (!pending_messages_.empty()) {
300645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // After all the pending messages are processed, we will check whether an
301645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // error has been encountered and run the user's connection error handler
302645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // if necessary.
303645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    DCHECK(pending_task_for_messages_);
304645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return;
305645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
306645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
307645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (connector_.during_sync_handle_watcher_callback()) {
308645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // We don't want the error handler to reenter an ongoing sync call.
309645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    connector_.task_runner()->PostTask(
310645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        FROM_HERE,
311645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        base::Bind(&Router::OnConnectionError, weak_factory_.GetWeakPtr()));
312645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return;
313645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
314645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
315645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  encountered_error_ = true;
316645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (!error_handler_.is_null())
317645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    error_handler_.Run();
318645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
319645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
320645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// ----------------------------------------------------------------------------
321645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
322645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}  // namespace internal
323645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}  // namespace mojo
324