Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(120)

Side by Side Diff: mojo/public/cpp/bindings/lib/interface_endpoint_client.cc

Issue 1455063004: Mojo C++ bindings: introduce MultiplexRouter and related classes. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 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/interface_endpoint_client.h"
6
7 #include "base/bind.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/stl_util.h"
10 #include "mojo/public/cpp/bindings/lib/multiplex_router.h"
11
12 namespace mojo {
13 namespace internal {
14
15 // ----------------------------------------------------------------------------
16
17 namespace {
18
19 // When receiving an incoming message which expects a repsonse,
20 // InterfaceEndpointClient creates a ResponderThunk object and passes it to the
21 // incoming message receiver. When the receiver finishes processing the message,
22 // it can provide a response using this object.
23 class ResponderThunk : public MessageReceiverWithStatus {
24 public:
25 explicit ResponderThunk(
26 const base::WeakPtr<InterfaceEndpointClient>& endpoint_client)
27 : endpoint_client_(endpoint_client), accept_was_invoked_(false) {}
28 ~ResponderThunk() override {
29 if (!accept_was_invoked_) {
30 // The Mojo application handled a message that was expecting a response
31 // but did not send a response.
32 if (endpoint_client_) {
33 // We raise an error to signal the calling application that an error
34 // condition occurred. Without this the calling application would have
35 // no way of knowing it should stop waiting for a response.
36 //
37 // We raise the error asynchronously and only if |endpoint_client_| is
38 // still alive when the task is run. That way it won't break the case
39 // where the user abandons the interface endpoint client soon after
40 // he/she abandons the callback.
41 base::MessageLoop::current()->PostTask(
42 FROM_HERE,
43 base::Bind(&InterfaceEndpointClient::RaiseError, endpoint_client_));
44 }
45 }
46 }
47
48 // MessageReceiver implementation:
49 bool Accept(Message* message) override {
50 accept_was_invoked_ = true;
51 DCHECK(message->has_flag(kMessageIsResponse));
52
53 bool result = false;
54
55 if (endpoint_client_)
56 result = endpoint_client_->Accept(message);
57
58 return result;
59 }
60
61 // MessageReceiverWithStatus implementation:
62 bool IsValid() override {
63 return endpoint_client_ && !endpoint_client_->encountered_error();
64 }
65
66 private:
67 base::WeakPtr<InterfaceEndpointClient> endpoint_client_;
68 bool accept_was_invoked_;
69
70 DISALLOW_COPY_AND_ASSIGN(ResponderThunk);
71 };
72
73 } // namespace
74
75 // ----------------------------------------------------------------------------
76
77 InterfaceEndpointClient::HandleIncomingMessageThunk::HandleIncomingMessageThunk(
78 InterfaceEndpointClient* owner)
79 : owner_(owner) {}
80
81 InterfaceEndpointClient::HandleIncomingMessageThunk::
82 ~HandleIncomingMessageThunk() {}
83
84 bool InterfaceEndpointClient::HandleIncomingMessageThunk::Accept(
85 Message* message) {
86 return owner_->HandleValidatedMessage(message);
87 }
88
89 // ----------------------------------------------------------------------------
90
91 InterfaceEndpointClient::InterfaceEndpointClient(
92 ScopedInterfaceEndpointHandle handle,
93 MessageReceiverWithResponderStatus* receiver,
94 scoped_ptr<MessageFilter> payload_validator)
95 : handle_(handle.Pass()),
96 incoming_receiver_(receiver),
97 payload_validator_(payload_validator.Pass()),
98 thunk_(this),
99 next_request_id_(1),
100 encountered_error_(false),
101 weak_ptr_factory_(this) {
102 DCHECK(handle_.is_valid());
103 DCHECK(handle_.is_local());
104
105 // TODO(yzshen): the way to use validator (or message filter in general)
106 // directly is a little awkward.
107 payload_validator_->set_sink(&thunk_);
108
109 handle_.router()->AttachEndpointClient(handle_, this);
110 }
111
112 InterfaceEndpointClient::~InterfaceEndpointClient() {
113 DCHECK(thread_checker_.CalledOnValidThread());
114
115 STLDeleteValues(&responders_);
116
117 handle_.router()->DetachEndpointClient(handle_);
118 }
119
120 ScopedInterfaceEndpointHandle InterfaceEndpointClient::PassHandle() {
121 DCHECK(thread_checker_.CalledOnValidThread());
122 DCHECK(!has_pending_responders());
123
124 if (!handle_.is_valid())
125 return ScopedInterfaceEndpointHandle();
126
127 handle_.router()->DetachEndpointClient(handle_);
128
129 return handle_.Pass();
130 }
131
132 void InterfaceEndpointClient::RaiseError() {
133 DCHECK(thread_checker_.CalledOnValidThread());
134
135 handle_.router()->RaiseError();
136 }
137
138 bool InterfaceEndpointClient::Accept(Message* message) {
139 DCHECK(thread_checker_.CalledOnValidThread());
140 DCHECK(!message->has_flag(kMessageExpectsResponse));
141
142 if (encountered_error_)
143 return false;
144
145 return handle_.router()->SendMessage(handle_, message);
146 }
147
148 bool InterfaceEndpointClient::AcceptWithResponder(Message* message,
149 MessageReceiver* responder) {
150 DCHECK(thread_checker_.CalledOnValidThread());
151 DCHECK(message->has_flag(kMessageExpectsResponse));
152
153 if (encountered_error_)
154 return false;
155
156 // Reserve 0 in case we want it to convey special meaning in the future.
157 uint64_t request_id = next_request_id_++;
158 if (request_id == 0)
159 request_id = next_request_id_++;
160
161 message->set_request_id(request_id);
162
163 if (!handle_.router()->SendMessage(handle_, message))
164 return false;
165
166 // We assume ownership of |responder|.
167 responders_[request_id] = responder;
168 return true;
169 }
170
171 bool InterfaceEndpointClient::HandleIncomingMessage(Message* message) {
172 DCHECK(thread_checker_.CalledOnValidThread());
173
174 return payload_validator_->Accept(message);
175 }
176
177 void InterfaceEndpointClient::NotifyError() {
178 DCHECK(thread_checker_.CalledOnValidThread());
179
180 if (encountered_error_)
181 return;
182 encountered_error_ = true;
183 error_handler_.Run();
184 }
185
186 bool InterfaceEndpointClient::HandleValidatedMessage(Message* message) {
187 DCHECK_EQ(handle_.id(), message->interface_id());
188
189 if (message->has_flag(kMessageExpectsResponse)) {
190 if (!incoming_receiver_)
191 return false;
192
193 MessageReceiverWithStatus* responder =
194 new ResponderThunk(weak_ptr_factory_.GetWeakPtr());
195 bool ok = incoming_receiver_->AcceptWithResponder(message, responder);
196 if (!ok)
197 delete responder;
198 return ok;
199 } else if (message->has_flag(kMessageIsResponse)) {
200 uint64_t request_id = message->request_id();
201 ResponderMap::iterator it = responders_.find(request_id);
202 if (it == responders_.end())
203 return false;
204 MessageReceiver* responder = it->second;
205 responders_.erase(it);
206 bool ok = responder->Accept(message);
207 delete responder;
208 return ok;
209 } else {
210 if (!incoming_receiver_)
211 return false;
212
213 return incoming_receiver_->Accept(message);
214 }
215 }
216
217 } // namespace internal
218 } // namespace mojo
OLDNEW
« no previous file with comments | « mojo/public/cpp/bindings/lib/interface_endpoint_client.h ('k') | mojo/public/cpp/bindings/lib/multiplex_router.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698