OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "mojo/edk/system/channel.h" | 5 #include "mojo/edk/system/channel.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/compiler_specific.h" | 10 #include "base/compiler_specific.h" |
11 #include "base/logging.h" | 11 #include "base/logging.h" |
12 #include "base/macros.h" | 12 #include "base/macros.h" |
13 #include "base/strings/stringprintf.h" | 13 #include "base/strings/stringprintf.h" |
14 #include "mojo/edk/embedder/platform_handle_vector.h" | 14 #include "mojo/edk/embedder/platform_handle_vector.h" |
15 #include "mojo/edk/system/message_pipe_endpoint.h" | |
16 #include "mojo/edk/system/transport_data.h" | 15 #include "mojo/edk/system/transport_data.h" |
17 | 16 |
18 namespace mojo { | 17 namespace mojo { |
19 namespace system { | 18 namespace system { |
20 | 19 |
21 Channel::Channel(embedder::PlatformSupport* platform_support) | 20 Channel::Channel(embedder::PlatformSupport* platform_support) |
22 : platform_support_(platform_support), | 21 : platform_support_(platform_support), |
23 is_running_(false), | 22 is_running_(false), |
24 is_shutting_down_(false) { | 23 is_shutting_down_(false) { |
25 } | 24 } |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
118 | 117 |
119 DLOG_IF(WARNING, is_shutting_down_) | 118 DLOG_IF(WARNING, is_shutting_down_) |
120 << "RunMessagePipeEndpoint() while shutting down"; | 119 << "RunMessagePipeEndpoint() while shutting down"; |
121 } | 120 } |
122 | 121 |
123 // TODO(vtl): FIXME -- We need to handle the case that message pipe is already | 122 // TODO(vtl): FIXME -- We need to handle the case that message pipe is already |
124 // running when we're here due to |kSubtypeChannelRunMessagePipeEndpoint|). | 123 // running when we're here due to |kSubtypeChannelRunMessagePipeEndpoint|). |
125 endpoint->Run(remote_id); | 124 endpoint->Run(remote_id); |
126 } | 125 } |
127 | 126 |
128 void Channel::AttachAndRunEndpoint(scoped_refptr<ChannelEndpoint> endpoint, | 127 ChannelEndpointId Channel::AttachAndRunEndpoint( |
129 bool is_bootstrap) { | 128 scoped_refptr<ChannelEndpoint> endpoint, |
| 129 bool is_bootstrap) { |
130 DCHECK(endpoint.get()); | 130 DCHECK(endpoint.get()); |
131 | 131 |
132 ChannelEndpointId local_id; | 132 ChannelEndpointId local_id; |
133 ChannelEndpointId remote_id; | 133 ChannelEndpointId remote_id; |
134 { | 134 { |
135 base::AutoLock locker(lock_); | 135 base::AutoLock locker(lock_); |
136 | 136 |
137 DLOG_IF(WARNING, is_shutting_down_) | 137 DLOG_IF(WARNING, is_shutting_down_) |
138 << "AttachEndpoint() while shutting down"; | 138 << "AttachEndpoint() while shutting down"; |
139 | 139 |
140 if (is_bootstrap) { | 140 if (is_bootstrap) { |
141 local_id = ChannelEndpointId::GetBootstrap(); | 141 local_id = ChannelEndpointId::GetBootstrap(); |
142 DCHECK(local_id_to_endpoint_map_.find(local_id) == | 142 DCHECK(local_id_to_endpoint_map_.find(local_id) == |
143 local_id_to_endpoint_map_.end()); | 143 local_id_to_endpoint_map_.end()); |
144 | 144 |
145 remote_id = ChannelEndpointId::GetBootstrap(); | 145 remote_id = ChannelEndpointId::GetBootstrap(); |
146 } else { | 146 } else { |
147 // TODO(vtl): More work needs to be done to enable the non-bootstrap case. | |
148 NOTREACHED() << "Non-bootstrap case not yet fully implemented"; | |
149 do { | 147 do { |
150 local_id = local_id_generator_.GetNext(); | 148 local_id = local_id_generator_.GetNext(); |
151 } while (local_id_to_endpoint_map_.find(local_id) != | 149 } while (local_id_to_endpoint_map_.find(local_id) != |
152 local_id_to_endpoint_map_.end()); | 150 local_id_to_endpoint_map_.end()); |
153 | 151 |
154 // TODO(vtl): We also need to check for collisions of remote IDs here. | 152 // TODO(vtl): We also need to check for collisions of remote IDs here. |
155 remote_id = remote_id_generator_.GetNext(); | 153 remote_id = remote_id_generator_.GetNext(); |
156 } | 154 } |
157 | 155 |
158 local_id_to_endpoint_map_[local_id] = endpoint; | 156 local_id_to_endpoint_map_[local_id] = endpoint; |
159 } | 157 } |
160 | 158 |
| 159 if (!is_bootstrap) { |
| 160 if (!SendControlMessage( |
| 161 MessageInTransit::kSubtypeChannelAttachAndRunEndpoint, |
| 162 local_id, |
| 163 remote_id)) { |
| 164 HandleLocalError(base::StringPrintf( |
| 165 "Failed to send message to run remote message pipe endpoint (local " |
| 166 "ID %u, remote ID %u)", |
| 167 static_cast<unsigned>(local_id.value()), |
| 168 static_cast<unsigned>(remote_id.value()))); |
| 169 // TODO(vtl): Should we continue on to |AttachAndRun()|? |
| 170 } |
| 171 } |
| 172 |
161 endpoint->AttachAndRun(this, local_id, remote_id); | 173 endpoint->AttachAndRun(this, local_id, remote_id); |
162 } | 174 return remote_id; |
163 | |
164 void Channel::RunRemoteMessagePipeEndpoint(ChannelEndpointId local_id, | |
165 ChannelEndpointId remote_id) { | |
166 #if DCHECK_IS_ON | |
167 { | |
168 base::AutoLock locker(lock_); | |
169 DCHECK(local_id_to_endpoint_map_.find(local_id) != | |
170 local_id_to_endpoint_map_.end()); | |
171 } | |
172 #endif | |
173 | |
174 if (!SendControlMessage( | |
175 MessageInTransit::kSubtypeChannelRunMessagePipeEndpoint, | |
176 local_id, | |
177 remote_id)) { | |
178 HandleLocalError(base::StringPrintf( | |
179 "Failed to send message to run remote message pipe endpoint (local ID " | |
180 "%u, remote ID %u)", | |
181 static_cast<unsigned>(local_id.value()), | |
182 static_cast<unsigned>(remote_id.value()))); | |
183 } | |
184 } | 175 } |
185 | 176 |
186 bool Channel::WriteMessage(scoped_ptr<MessageInTransit> message) { | 177 bool Channel::WriteMessage(scoped_ptr<MessageInTransit> message) { |
187 base::AutoLock locker(lock_); | 178 base::AutoLock locker(lock_); |
188 if (!is_running_) { | 179 if (!is_running_) { |
189 // TODO(vtl): I think this is probably not an error condition, but I should | 180 // TODO(vtl): I think this is probably not an error condition, but I should |
190 // think about it (and the shutdown sequence) more carefully. | 181 // think about it (and the shutdown sequence) more carefully. |
191 LOG(WARNING) << "WriteMessage() after shutdown"; | 182 LOG(WARNING) << "WriteMessage() after shutdown"; |
192 return false; | 183 return false; |
193 } | 184 } |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
236 local_id, | 227 local_id, |
237 remote_id)) { | 228 remote_id)) { |
238 HandleLocalError(base::StringPrintf( | 229 HandleLocalError(base::StringPrintf( |
239 "Failed to send message to remove remote message pipe endpoint (local " | 230 "Failed to send message to remove remote message pipe endpoint (local " |
240 "ID %u, remote ID %u)", | 231 "ID %u, remote ID %u)", |
241 static_cast<unsigned>(local_id.value()), | 232 static_cast<unsigned>(local_id.value()), |
242 static_cast<unsigned>(remote_id.value()))); | 233 static_cast<unsigned>(remote_id.value()))); |
243 } | 234 } |
244 } | 235 } |
245 | 236 |
| 237 scoped_refptr<MessagePipe> Channel::PassIncomingMessagePipe( |
| 238 ChannelEndpointId local_id) { |
| 239 // No need to check the validity of |local_id| -- if it's not valid, it simply |
| 240 // won't be in |incoming_message_pipes_|. |
| 241 DVLOG_IF(2, !local_id.is_valid() || !local_id.is_remote()) |
| 242 << "Attempt to get invalid incoming message pipe for ID " << local_id; |
| 243 |
| 244 base::AutoLock locker(lock_); |
| 245 |
| 246 auto it = incoming_message_pipes_.find(local_id); |
| 247 if (it == incoming_message_pipes_.end()) |
| 248 return scoped_refptr<MessagePipe>(); |
| 249 |
| 250 scoped_refptr<MessagePipe> rv; |
| 251 rv.swap(it->second); |
| 252 incoming_message_pipes_.erase(it); |
| 253 return rv; |
| 254 } |
| 255 |
246 size_t Channel::GetSerializedPlatformHandleSize() const { | 256 size_t Channel::GetSerializedPlatformHandleSize() const { |
247 return raw_channel_->GetSerializedPlatformHandleSize(); | 257 return raw_channel_->GetSerializedPlatformHandleSize(); |
248 } | 258 } |
249 | 259 |
250 Channel::~Channel() { | 260 Channel::~Channel() { |
251 // The channel should have been shut down first. | 261 // The channel should have been shut down first. |
252 DCHECK(!is_running_); | 262 DCHECK(!is_running_); |
253 } | 263 } |
254 | 264 |
255 void Channel::OnReadMessage( | 265 void Channel::OnReadMessage( |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
368 | 378 |
369 // Currently, no channel messages take platform handles. | 379 // Currently, no channel messages take platform handles. |
370 if (platform_handles) { | 380 if (platform_handles) { |
371 HandleRemoteError( | 381 HandleRemoteError( |
372 "Received invalid channel message (has platform handles)"); | 382 "Received invalid channel message (has platform handles)"); |
373 NOTREACHED(); | 383 NOTREACHED(); |
374 return; | 384 return; |
375 } | 385 } |
376 | 386 |
377 switch (message_view.subtype()) { | 387 switch (message_view.subtype()) { |
378 case MessageInTransit::kSubtypeChannelRunMessagePipeEndpoint: | 388 case MessageInTransit::kSubtypeChannelAttachAndRunEndpoint: |
379 DVLOG(2) << "Handling channel message to run message pipe (local ID " | 389 DVLOG(2) << "Handling channel message to attach and run message pipe " |
380 << message_view.destination_id() << ", remote ID " | 390 "(local ID " << message_view.destination_id() |
381 << message_view.source_id() << ")"; | 391 << ", remote ID " << message_view.source_id() << ")"; |
382 if (!OnRunMessagePipeEndpoint(message_view.destination_id(), | 392 if (!OnAttachAndRunEndpoint(message_view.destination_id(), |
383 message_view.source_id())) { | 393 message_view.source_id())) { |
384 HandleRemoteError( | 394 HandleRemoteError( |
385 "Received invalid channel message to run message pipe"); | 395 "Received invalid channel message to attach and run message pipe"); |
386 } | 396 } |
387 break; | 397 break; |
388 case MessageInTransit::kSubtypeChannelRemoveMessagePipeEndpoint: | 398 case MessageInTransit::kSubtypeChannelRemoveMessagePipeEndpoint: |
389 DVLOG(2) << "Handling channel message to remove message pipe (local ID " | 399 DVLOG(2) << "Handling channel message to remove message pipe (local ID " |
390 << message_view.destination_id() << ", remote ID " | 400 << message_view.destination_id() << ", remote ID " |
391 << message_view.source_id() << ")"; | 401 << message_view.source_id() << ")"; |
392 if (!OnRemoveMessagePipeEndpoint(message_view.destination_id(), | 402 if (!OnRemoveMessagePipeEndpoint(message_view.destination_id(), |
393 message_view.source_id())) { | 403 message_view.source_id())) { |
394 HandleRemoteError( | 404 HandleRemoteError( |
395 "Received invalid channel message to remove message pipe"); | 405 "Received invalid channel message to remove message pipe"); |
396 } | 406 } |
397 break; | 407 break; |
398 case MessageInTransit::kSubtypeChannelRemoveMessagePipeEndpointAck: | 408 case MessageInTransit::kSubtypeChannelRemoveMessagePipeEndpointAck: |
399 DVLOG(2) << "Handling channel message to ack remove message pipe (local " | 409 DVLOG(2) << "Handling channel message to ack remove message pipe (local " |
400 "ID " << message_view.destination_id() << ", remote ID " | 410 "ID " << message_view.destination_id() << ", remote ID " |
401 << message_view.source_id() << ")"; | 411 << message_view.source_id() << ")"; |
402 if (!OnRemoveMessagePipeEndpointAck(message_view.destination_id())) { | 412 if (!OnRemoveMessagePipeEndpointAck(message_view.destination_id())) { |
403 HandleRemoteError( | 413 HandleRemoteError( |
404 "Received invalid channel message to ack remove message pipe"); | 414 "Received invalid channel message to ack remove message pipe"); |
405 } | 415 } |
406 break; | 416 break; |
407 default: | 417 default: |
408 HandleRemoteError("Received invalid channel message"); | 418 HandleRemoteError("Received invalid channel message"); |
409 NOTREACHED(); | 419 NOTREACHED(); |
410 break; | 420 break; |
411 } | 421 } |
412 } | 422 } |
413 | 423 |
414 bool Channel::OnRunMessagePipeEndpoint(ChannelEndpointId local_id, | 424 bool Channel::OnAttachAndRunEndpoint(ChannelEndpointId local_id, |
415 ChannelEndpointId remote_id) { | 425 ChannelEndpointId remote_id) { |
| 426 // We should only get this for remotely-created local endpoints, so our local |
| 427 // ID should be "remote". |
| 428 if (!local_id.is_valid() || !local_id.is_remote()) { |
| 429 DVLOG(2) << "Received attach and run endpoint with invalid local ID"; |
| 430 return false; |
| 431 } |
| 432 |
| 433 // Conversely, the remote end should be "local". |
| 434 if (!remote_id.is_valid() || remote_id.is_remote()) { |
| 435 DVLOG(2) << "Received attach and run endpoint with invalid remote ID"; |
| 436 return false; |
| 437 } |
| 438 |
| 439 // Create a message pipe and thus an endpoint (outside the lock). |
416 scoped_refptr<ChannelEndpoint> endpoint; | 440 scoped_refptr<ChannelEndpoint> endpoint; |
| 441 scoped_refptr<MessagePipe> message_pipe( |
| 442 MessagePipe::CreateLocalProxy(&endpoint)); |
| 443 |
| 444 bool success = true; |
417 { | 445 { |
418 base::AutoLock locker(lock_); | 446 base::AutoLock locker(lock_); |
419 | 447 |
420 IdToEndpointMap::iterator it = local_id_to_endpoint_map_.find(local_id); | 448 if (local_id_to_endpoint_map_.find(local_id) == |
421 if (it == local_id_to_endpoint_map_.end()) | 449 local_id_to_endpoint_map_.end()) { |
422 return false; | 450 DCHECK(incoming_message_pipes_.find(local_id) == |
| 451 incoming_message_pipes_.end()); |
423 | 452 |
424 endpoint = it->second; | 453 // TODO(vtl): Use emplace when we move to C++11 unordered_maps. (It'll |
| 454 // avoid some refcount churn.) |
| 455 local_id_to_endpoint_map_[local_id] = endpoint; |
| 456 incoming_message_pipes_[local_id] = message_pipe; |
| 457 } else { |
| 458 // We need to call |Close()| on the message pipe outside the lock. |
| 459 success = false; |
| 460 } |
| 461 } |
| 462 if (!success) { |
| 463 DVLOG(2) << "Received attach and run endpoint for existing local ID"; |
| 464 message_pipe->Close(0); |
| 465 return false; |
425 } | 466 } |
426 | 467 |
427 RunEndpoint(endpoint, remote_id); | 468 endpoint->AttachAndRun(this, local_id, remote_id); |
428 return true; | 469 return true; |
429 } | 470 } |
430 | 471 |
431 bool Channel::OnRemoveMessagePipeEndpoint(ChannelEndpointId local_id, | 472 bool Channel::OnRemoveMessagePipeEndpoint(ChannelEndpointId local_id, |
432 ChannelEndpointId remote_id) { | 473 ChannelEndpointId remote_id) { |
433 DCHECK(creation_thread_checker_.CalledOnValidThread()); | 474 DCHECK(creation_thread_checker_.CalledOnValidThread()); |
434 | 475 |
435 scoped_refptr<ChannelEndpoint> endpoint; | 476 scoped_refptr<ChannelEndpoint> endpoint; |
436 { | 477 { |
437 base::AutoLock locker(lock_); | 478 base::AutoLock locker(lock_); |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
511 // TODO(vtl): Is this how we really want to handle this? | 552 // TODO(vtl): Is this how we really want to handle this? |
512 // Sometimes we'll want to propagate the error back to the message pipe | 553 // Sometimes we'll want to propagate the error back to the message pipe |
513 // (endpoint), and notify it that the remote is (effectively) closed. | 554 // (endpoint), and notify it that the remote is (effectively) closed. |
514 // Sometimes we'll want to kill the channel (and notify all the endpoints that | 555 // Sometimes we'll want to kill the channel (and notify all the endpoints that |
515 // their remotes are dead. | 556 // their remotes are dead. |
516 LOG(WARNING) << error_message; | 557 LOG(WARNING) << error_message; |
517 } | 558 } |
518 | 559 |
519 } // namespace system | 560 } // namespace system |
520 } // namespace mojo | 561 } // namespace mojo |
OLD | NEW |