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 |