OLD | NEW |
---|---|
(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 class ResponderThunk : public MessageReceiverWithStatus { | |
sky
2015/11/19 17:16:27
Please add a description as to what classes do, ev
yzshen1
2015/11/19 22:00:40
Done.
| |
20 public: | |
21 explicit ResponderThunk( | |
22 const base::WeakPtr<InterfaceEndpointClient>& endpoint_client) | |
23 : endpoint_client_(endpoint_client), accept_was_invoked_(false) {} | |
24 ~ResponderThunk() override { | |
25 if (!accept_was_invoked_) { | |
26 // The Mojo application handled a message that was expecting a response | |
27 // but did not send a response. | |
28 if (endpoint_client_) { | |
29 // We raise an error to signal the calling application that an error | |
30 // condition occurred. Without this the calling application would have | |
31 // no way of knowing it should stop waiting for a response. | |
32 // | |
33 // We raise the error asynchronously and only if |endpoint_client_| is | |
34 // still alive when the task is run. That way it won't break the case | |
35 // where the user abandons the interface endpoint client soon after | |
36 // he/she abandons the callback. | |
37 base::MessageLoop::current()->PostTask( | |
38 FROM_HERE, | |
39 base::Bind(&InterfaceEndpointClient::RaiseError, endpoint_client_)); | |
40 } | |
41 } | |
42 } | |
43 | |
44 // MessageReceiver implementation: | |
45 bool Accept(Message* message) override { | |
46 accept_was_invoked_ = true; | |
47 DCHECK(message->has_flag(kMessageIsResponse)); | |
48 | |
49 bool result = false; | |
50 | |
51 if (endpoint_client_) | |
52 result = endpoint_client_->Accept(message); | |
53 | |
54 return result; | |
55 } | |
56 | |
57 // MessageReceiverWithStatus implementation: | |
58 bool IsValid() override { | |
59 return endpoint_client_ && !endpoint_client_->encountered_error(); | |
60 } | |
61 | |
62 private: | |
63 base::WeakPtr<InterfaceEndpointClient> endpoint_client_; | |
64 bool accept_was_invoked_; | |
65 }; | |
sky
2015/11/19 17:16:27
DISALLOW...
yzshen1
2015/11/19 22:00:40
Done.
| |
66 | |
67 } // namespace | |
68 | |
69 // ---------------------------------------------------------------------------- | |
70 | |
71 InterfaceEndpointClient::HandleIncomingMessageThunk::HandleIncomingMessageThunk( | |
72 InterfaceEndpointClient* owner) | |
73 : owner_(owner) {} | |
74 | |
75 InterfaceEndpointClient::HandleIncomingMessageThunk:: | |
76 ~HandleIncomingMessageThunk() {} | |
77 | |
78 bool InterfaceEndpointClient::HandleIncomingMessageThunk::Accept( | |
79 Message* message) { | |
80 return owner_->HandleValidatedMessage(message); | |
81 } | |
82 | |
83 // ---------------------------------------------------------------------------- | |
84 | |
85 InterfaceEndpointClient::InterfaceEndpointClient( | |
86 ScopedInterfaceEndpointHandle handle, | |
87 MessageReceiverWithResponderStatus* receiver, | |
88 scoped_ptr<MessageFilter> payload_validator) | |
89 : handle_(handle.Pass()), | |
90 incoming_receiver_(receiver), | |
91 payload_validator_(payload_validator.Pass()), | |
92 thunk_(this), | |
93 next_request_id_(1), | |
94 encountered_error_(false), | |
95 weak_ptr_factory_(this) { | |
96 DCHECK(handle_.is_valid()); | |
97 DCHECK(handle_.is_local()); | |
98 | |
99 // TODO(yzshen): the way to use validator (or message filter in general) | |
100 // directly is a little awkward. | |
101 payload_validator_->set_sink(&thunk_); | |
102 | |
103 handle_.router()->AttachEndpointClient(handle_, this); | |
104 } | |
105 | |
106 InterfaceEndpointClient::~InterfaceEndpointClient() { | |
107 DCHECK(thread_checker_.CalledOnValidThread()); | |
108 | |
109 STLDeleteValues(&responders_); | |
110 | |
111 handle_.router()->DetachEndpointClient(handle_); | |
112 } | |
113 | |
114 ScopedInterfaceEndpointHandle InterfaceEndpointClient::PassHandle() { | |
115 DCHECK(thread_checker_.CalledOnValidThread()); | |
116 DCHECK(!has_pending_responders()); | |
117 | |
118 if (!handle_.is_valid()) | |
119 return ScopedInterfaceEndpointHandle(); | |
120 | |
121 handle_.router()->DetachEndpointClient(handle_); | |
122 | |
123 return handle_.Pass(); | |
124 } | |
125 | |
126 void InterfaceEndpointClient::RaiseError() { | |
127 DCHECK(thread_checker_.CalledOnValidThread()); | |
128 | |
129 handle_.router()->RaiseError(); | |
130 } | |
131 | |
132 bool InterfaceEndpointClient::Accept(Message* message) { | |
133 DCHECK(thread_checker_.CalledOnValidThread()); | |
134 DCHECK(!message->has_flag(kMessageExpectsResponse)); | |
135 | |
136 if (encountered_error_) | |
137 return false; | |
138 | |
139 return handle_.router()->SendMessage(handle_, message); | |
140 } | |
141 | |
142 bool InterfaceEndpointClient::AcceptWithResponder(Message* message, | |
143 MessageReceiver* responder) { | |
144 DCHECK(thread_checker_.CalledOnValidThread()); | |
145 DCHECK(message->has_flag(kMessageExpectsResponse)); | |
146 | |
147 if (encountered_error_) | |
148 return false; | |
149 | |
150 // Reserve 0 in case we want it to convey special meaning in the future. | |
151 uint64_t request_id = next_request_id_++; | |
152 if (request_id == 0) | |
153 request_id = next_request_id_++; | |
154 | |
155 message->set_request_id(request_id); | |
156 | |
157 if (!handle_.router()->SendMessage(handle_, message)) | |
158 return false; | |
159 | |
160 // We assume ownership of |responder|. | |
161 responders_[request_id] = responder; | |
162 return true; | |
163 } | |
164 | |
165 bool InterfaceEndpointClient::HandleIncomingMessage(Message* message) { | |
166 DCHECK(thread_checker_.CalledOnValidThread()); | |
167 | |
168 return payload_validator_->Accept(message); | |
169 } | |
170 | |
171 void InterfaceEndpointClient::NotifyError() { | |
172 DCHECK(thread_checker_.CalledOnValidThread()); | |
173 | |
174 if (encountered_error_) | |
175 return; | |
176 encountered_error_ = true; | |
177 error_handler_.Run(); | |
178 } | |
179 | |
180 bool InterfaceEndpointClient::HandleValidatedMessage(Message* message) { | |
181 DCHECK_EQ(handle_.id(), message->interface_id()); | |
182 | |
183 if (message->has_flag(kMessageExpectsResponse)) { | |
184 if (!incoming_receiver_) | |
185 return false; | |
186 | |
187 MessageReceiverWithStatus* responder = | |
188 new ResponderThunk(weak_ptr_factory_.GetWeakPtr()); | |
189 bool ok = incoming_receiver_->AcceptWithResponder(message, responder); | |
sky
2015/11/19 17:16:27
It would be nice if AcceptWithResponder took a sco
yzshen1
2015/11/19 22:00:40
Right. I agree.
That would require quite some cha
| |
190 if (!ok) | |
191 delete responder; | |
192 return ok; | |
193 } else if (message->has_flag(kMessageIsResponse)) { | |
194 uint64_t request_id = message->request_id(); | |
195 ResponderMap::iterator it = responders_.find(request_id); | |
196 if (it == responders_.end()) | |
197 return false; | |
198 MessageReceiver* responder = it->second; | |
199 responders_.erase(it); | |
200 bool ok = responder->Accept(message); | |
201 delete responder; | |
202 return ok; | |
203 } else { | |
204 if (!incoming_receiver_) | |
205 return false; | |
206 | |
207 return incoming_receiver_->Accept(message); | |
208 } | |
209 } | |
210 | |
211 } // namespace internal | |
212 } // namespace mojo | |
OLD | NEW |