| 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 |