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 // 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 |
OLD | NEW |