| 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/system/channel.h" | 5 #include "mojo/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" |
| (...skipping 399 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 410 if (!RunMessagePipeEndpoint(message_view.destination_id(), | 410 if (!RunMessagePipeEndpoint(message_view.destination_id(), |
| 411 message_view.source_id())) { | 411 message_view.source_id())) { |
| 412 HandleRemoteError( | 412 HandleRemoteError( |
| 413 "Received invalid channel message to run message pipe"); | 413 "Received invalid channel message to run message pipe"); |
| 414 } | 414 } |
| 415 break; | 415 break; |
| 416 case MessageInTransit::kSubtypeChannelRemoveMessagePipeEndpoint: | 416 case MessageInTransit::kSubtypeChannelRemoveMessagePipeEndpoint: |
| 417 DVLOG(2) << "Handling channel message to remove message pipe (local ID " | 417 DVLOG(2) << "Handling channel message to remove message pipe (local ID " |
| 418 << message_view.destination_id() << ", remote ID " | 418 << message_view.destination_id() << ", remote ID " |
| 419 << message_view.source_id() << ")"; | 419 << message_view.source_id() << ")"; |
| 420 if (!RemoveMessagePipeEndpoint(message_view.destination_id(), | 420 if (!OnRemoveMessagePipeEndpoint(message_view.destination_id(), |
| 421 message_view.source_id())) { | 421 message_view.source_id())) { |
| 422 HandleRemoteError( | 422 HandleRemoteError( |
| 423 "Received invalid channel message to remove message pipe"); | 423 "Received invalid channel message to remove message pipe"); |
| 424 } | 424 } |
| 425 break; | 425 break; |
| 426 case MessageInTransit::kSubtypeChannelRemoveMessagePipeEndpointAck: | 426 case MessageInTransit::kSubtypeChannelRemoveMessagePipeEndpointAck: |
| 427 DVLOG(2) << "Handling channel message to ack remove message pipe (local " | 427 DVLOG(2) << "Handling channel message to ack remove message pipe (local " |
| 428 "ID " << message_view.destination_id() << ", remote ID " | 428 "ID " << message_view.destination_id() << ", remote ID " |
| 429 << message_view.source_id() << ")"; | 429 << message_view.source_id() << ")"; |
| 430 if (!RemoveMessagePipeEndpoint(message_view.destination_id(), | 430 if (!OnRemoveMessagePipeEndpointAck(message_view.destination_id())) { |
| 431 message_view.source_id())) { | |
| 432 HandleRemoteError( | 431 HandleRemoteError( |
| 433 "Received invalid channel message to ack remove message pipe"); | 432 "Received invalid channel message to ack remove message pipe"); |
| 434 } | 433 } |
| 435 break; | 434 break; |
| 436 default: | 435 default: |
| 437 HandleRemoteError("Received invalid channel message"); | 436 HandleRemoteError("Received invalid channel message"); |
| 438 NOTREACHED(); | 437 NOTREACHED(); |
| 439 break; | 438 break; |
| 440 } | 439 } |
| 441 } | 440 } |
| 442 | 441 |
| 443 bool Channel::RemoveMessagePipeEndpoint( | 442 bool Channel::OnRemoveMessagePipeEndpoint( |
| 444 MessageInTransit::EndpointId local_id, | 443 MessageInTransit::EndpointId local_id, |
| 445 MessageInTransit::EndpointId remote_id) { | 444 MessageInTransit::EndpointId remote_id) { |
| 446 DCHECK(creation_thread_checker_.CalledOnValidThread()); | 445 DCHECK(creation_thread_checker_.CalledOnValidThread()); |
| 447 | 446 |
| 448 // If this is non-null after the locked block, the endpoint should be detached | |
| 449 // (and no remove ack message sent). | |
| 450 scoped_refptr<ChannelEndpoint> endpoint_to_detach; | |
| 451 scoped_refptr<MessagePipe> message_pipe; | 447 scoped_refptr<MessagePipe> message_pipe; |
| 452 unsigned port = ~0u; | 448 unsigned port = ~0u; |
| 453 { | 449 { |
| 454 base::AutoLock locker(lock_); | 450 base::AutoLock locker(lock_); |
| 455 | 451 |
| 456 IdToEndpointMap::iterator it = local_id_to_endpoint_map_.find(local_id); | 452 IdToEndpointMap::iterator it = local_id_to_endpoint_map_.find(local_id); |
| 457 if (it == local_id_to_endpoint_map_.end()) { | 453 if (it == local_id_to_endpoint_map_.end()) { |
| 458 DVLOG(2) << "Remove message pipe error: not found"; | 454 DVLOG(2) << "Remove message pipe endpoint error: not found"; |
| 459 return false; | 455 return false; |
| 460 } | 456 } |
| 461 | 457 |
| 462 switch (it->second->state_) { | 458 switch (it->second->state_) { |
| 463 case ChannelEndpoint::STATE_NORMAL: | 459 case ChannelEndpoint::STATE_NORMAL: |
| 464 it->second->state_ = ChannelEndpoint::STATE_WAIT_LOCAL_DETACH; | 460 // This is the normal case; we'll proceed on to "wait local detach". |
| 465 message_pipe = it->second->message_pipe_; | |
| 466 port = it->second->port_; | |
| 467 it->second->message_pipe_ = nullptr; | |
| 468 // We have to send a remove ack message (outside the lock). | |
| 469 break; | 461 break; |
| 462 |
| 470 case ChannelEndpoint::STATE_WAIT_LOCAL_DETACH: | 463 case ChannelEndpoint::STATE_WAIT_LOCAL_DETACH: |
| 471 DVLOG(2) << "Remove message pipe error: wrong state"; | 464 // We can only be in this state because we got a "remove" already, so |
| 465 // getting another such message is invalid. |
| 466 DVLOG(2) << "Remove message pipe endpoint error: wrong state"; |
| 472 return false; | 467 return false; |
| 468 |
| 473 case ChannelEndpoint::STATE_WAIT_REMOTE_REMOVE_ACK: | 469 case ChannelEndpoint::STATE_WAIT_REMOTE_REMOVE_ACK: |
| 474 endpoint_to_detach = it->second; | 470 // Remove messages "crossed"; we have to wait for the ack. |
| 475 local_id_to_endpoint_map_.erase(it); | 471 return true; |
| 476 // We have to detach (outside the lock). | |
| 477 break; | |
| 478 } | 472 } |
| 479 } | 473 |
| 480 if (endpoint_to_detach.get()) { | 474 it->second->state_ = ChannelEndpoint::STATE_WAIT_LOCAL_DETACH; |
| 481 endpoint_to_detach->DetachFromChannel(); | 475 message_pipe = it->second->message_pipe_; |
| 482 return true; | 476 port = it->second->port_; |
| 477 it->second->message_pipe_ = nullptr; |
| 478 // Send the remove ack message outside the lock. |
| 483 } | 479 } |
| 484 | 480 |
| 485 if (!SendControlMessage( | 481 if (!SendControlMessage( |
| 486 MessageInTransit::kSubtypeChannelRemoveMessagePipeEndpointAck, | 482 MessageInTransit::kSubtypeChannelRemoveMessagePipeEndpointAck, |
| 487 local_id, | 483 local_id, |
| 488 remote_id)) { | 484 remote_id)) { |
| 489 HandleLocalError(base::StringPrintf( | 485 HandleLocalError(base::StringPrintf( |
| 490 "Failed to send message to remove remote message pipe endpoint ack " | 486 "Failed to send message to remove remote message pipe endpoint ack " |
| 491 "(local ID %u, remote ID %u)", | 487 "(local ID %u, remote ID %u)", |
| 492 static_cast<unsigned>(local_id), | 488 static_cast<unsigned>(local_id), |
| 493 static_cast<unsigned>(remote_id))); | 489 static_cast<unsigned>(remote_id))); |
| 494 } | 490 } |
| 495 | 491 |
| 496 message_pipe->Close(port); | 492 message_pipe->Close(port); |
| 497 | |
| 498 return true; | 493 return true; |
| 499 } | 494 } |
| 500 | 495 |
| 496 bool Channel::OnRemoveMessagePipeEndpointAck( |
| 497 MessageInTransit::EndpointId local_id) { |
| 498 DCHECK(creation_thread_checker_.CalledOnValidThread()); |
| 499 |
| 500 scoped_refptr<ChannelEndpoint> endpoint_to_detach; |
| 501 { |
| 502 base::AutoLock locker(lock_); |
| 503 |
| 504 IdToEndpointMap::iterator it = local_id_to_endpoint_map_.find(local_id); |
| 505 if (it == local_id_to_endpoint_map_.end()) { |
| 506 DVLOG(2) << "Remove message pipe endpoint ack error: not found"; |
| 507 return false; |
| 508 } |
| 509 |
| 510 if (it->second->state_ != ChannelEndpoint::STATE_WAIT_REMOTE_REMOVE_ACK) { |
| 511 DVLOG(2) << "Remove message pipe endpoint ack error: wrong state"; |
| 512 return false; |
| 513 } |
| 514 |
| 515 endpoint_to_detach = it->second; |
| 516 local_id_to_endpoint_map_.erase(it); |
| 517 // Detach the endpoint outside the lock. |
| 518 } |
| 519 |
| 520 endpoint_to_detach->DetachFromChannel(); |
| 521 return true; |
| 522 } |
| 523 |
| 501 bool Channel::SendControlMessage(MessageInTransit::Subtype subtype, | 524 bool Channel::SendControlMessage(MessageInTransit::Subtype subtype, |
| 502 MessageInTransit::EndpointId local_id, | 525 MessageInTransit::EndpointId local_id, |
| 503 MessageInTransit::EndpointId remote_id) { | 526 MessageInTransit::EndpointId remote_id) { |
| 504 DVLOG(2) << "Sending channel control message: subtype " << subtype | 527 DVLOG(2) << "Sending channel control message: subtype " << subtype |
| 505 << ", local ID " << local_id << ", remote ID " << remote_id; | 528 << ", local ID " << local_id << ", remote ID " << remote_id; |
| 506 scoped_ptr<MessageInTransit> message(new MessageInTransit( | 529 scoped_ptr<MessageInTransit> message(new MessageInTransit( |
| 507 MessageInTransit::kTypeChannel, subtype, 0, nullptr)); | 530 MessageInTransit::kTypeChannel, subtype, 0, nullptr)); |
| 508 message->set_source_id(local_id); | 531 message->set_source_id(local_id); |
| 509 message->set_destination_id(remote_id); | 532 message->set_destination_id(remote_id); |
| 510 return WriteMessage(message.Pass()); | 533 return WriteMessage(message.Pass()); |
| 511 } | 534 } |
| 512 | 535 |
| 513 void Channel::HandleRemoteError(const base::StringPiece& error_message) { | 536 void Channel::HandleRemoteError(const base::StringPiece& error_message) { |
| 514 // TODO(vtl): Is this how we really want to handle this? Probably we want to | 537 // TODO(vtl): Is this how we really want to handle this? Probably we want to |
| 515 // terminate the connection, since it's spewing invalid stuff. | 538 // terminate the connection, since it's spewing invalid stuff. |
| 516 LOG(WARNING) << error_message; | 539 LOG(WARNING) << error_message; |
| 517 } | 540 } |
| 518 | 541 |
| 519 void Channel::HandleLocalError(const base::StringPiece& error_message) { | 542 void Channel::HandleLocalError(const base::StringPiece& error_message) { |
| 520 // TODO(vtl): Is this how we really want to handle this? | 543 // TODO(vtl): Is this how we really want to handle this? |
| 521 // Sometimes we'll want to propagate the error back to the message pipe | 544 // Sometimes we'll want to propagate the error back to the message pipe |
| 522 // (endpoint), and notify it that the remote is (effectively) closed. | 545 // (endpoint), and notify it that the remote is (effectively) closed. |
| 523 // Sometimes we'll want to kill the channel (and notify all the endpoints that | 546 // Sometimes we'll want to kill the channel (and notify all the endpoints that |
| 524 // their remotes are dead. | 547 // their remotes are dead. |
| 525 LOG(WARNING) << error_message; | 548 LOG(WARNING) << error_message; |
| 526 } | 549 } |
| 527 | 550 |
| 528 } // namespace system | 551 } // namespace system |
| 529 } // namespace mojo | 552 } // namespace mojo |
| OLD | NEW |