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 "chrome/browser/extensions/api/cast_channel/cast_socket.h" | 5 #include "chrome/browser/extensions/api/cast_channel/cast_socket.h" |
6 | 6 |
7 #include <stdlib.h> | 7 #include <stdlib.h> |
8 #include <string.h> | 8 #include <string.h> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
151 return false; | 151 return false; |
152 bool result = net::X509Certificate::GetDEREncoded( | 152 bool result = net::X509Certificate::GetDEREncoded( |
153 ssl_info.cert->os_cert_handle(), cert); | 153 ssl_info.cert->os_cert_handle(), cert); |
154 if (result) | 154 if (result) |
155 VLOG_WITH_CONNECTION(1) << "Successfully extracted peer certificate: " | 155 VLOG_WITH_CONNECTION(1) << "Successfully extracted peer certificate: " |
156 << *cert; | 156 << *cert; |
157 return result; | 157 return result; |
158 } | 158 } |
159 | 159 |
160 bool CastSocket::VerifyChallengeReply() { | 160 bool CastSocket::VerifyChallengeReply() { |
161 return AuthenticateChallengeReply(*challenge_reply_.get(), peer_cert_); | 161 return AuthenticateChallengeReply(*challenge_reply_, peer_cert_); |
162 } | 162 } |
163 | 163 |
164 void CastSocket::Connect(const net::CompletionCallback& callback) { | 164 void CastSocket::Connect(const net::CompletionCallback& callback) { |
165 DCHECK(CalledOnValidThread()); | 165 DCHECK(CalledOnValidThread()); |
166 VLOG_WITH_CONNECTION(1) << "Connect readyState = " << ready_state_; | 166 VLOG_WITH_CONNECTION(1) << "Connect readyState = " << ready_state_; |
167 if (ready_state_ != READY_STATE_NONE) { | 167 if (ready_state_ != READY_STATE_NONE) { |
168 callback.Run(net::ERR_CONNECTION_FAILED); | 168 callback.Run(net::ERR_CONNECTION_FAILED); |
169 return; | 169 return; |
170 } | 170 } |
171 ready_state_ = READY_STATE_CONNECTING; | 171 ready_state_ = READY_STATE_CONNECTING; |
(...skipping 353 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
525 rv = DoRead(); | 525 rv = DoRead(); |
526 break; | 526 break; |
527 case READ_STATE_READ_COMPLETE: | 527 case READ_STATE_READ_COMPLETE: |
528 rv = DoReadComplete(rv); | 528 rv = DoReadComplete(rv); |
529 break; | 529 break; |
530 case READ_STATE_DO_CALLBACK: | 530 case READ_STATE_DO_CALLBACK: |
531 rv = DoReadCallback(); | 531 rv = DoReadCallback(); |
532 break; | 532 break; |
533 case READ_STATE_ERROR: | 533 case READ_STATE_ERROR: |
534 rv = DoReadError(rv); | 534 rv = DoReadError(rv); |
535 DCHECK_EQ(read_state_, READ_STATE_NONE); | |
535 break; | 536 break; |
536 default: | 537 default: |
537 NOTREACHED() << "BUG in read flow. Unknown state: " << state; | 538 NOTREACHED() << "BUG in read flow. Unknown state: " << state; |
538 break; | 539 break; |
539 } | 540 } |
540 } while (rv != net::ERR_IO_PENDING && read_state_ != READ_STATE_NONE); | 541 } while (rv != net::ERR_IO_PENDING && read_state_ != READ_STATE_NONE); |
541 | 542 |
542 // Read loop is done - If the result is ERR_FAILED then close with error. | 543 if (rv == net::ERR_FAILED) { |
543 if (rv == net::ERR_FAILED) | 544 if (ready_state_ == READY_STATE_CONNECTING) { |
544 CloseWithError(error_state_); | 545 // Read errors during the handshake should notify the caller via |
546 // the connect callback, rather than the message event delegate. | |
547 PostTaskToStartConnectLoop(net::ERR_FAILED); | |
548 } else { | |
549 // Connection is already established. | |
550 // Close and send error status via the message event delegate. | |
551 CloseWithError(error_state_); | |
552 } | |
553 } | |
545 } | 554 } |
546 | 555 |
547 int CastSocket::DoRead() { | 556 int CastSocket::DoRead() { |
548 read_state_ = READ_STATE_READ_COMPLETE; | 557 read_state_ = READ_STATE_READ_COMPLETE; |
549 // Figure out whether to read header or body, and the remaining bytes. | 558 // Figure out whether to read header or body, and the remaining bytes. |
550 uint32 num_bytes_to_read = 0; | 559 uint32 num_bytes_to_read = 0; |
551 if (header_read_buffer_->RemainingCapacity() > 0) { | 560 if (header_read_buffer_->RemainingCapacity() > 0) { |
552 current_read_buffer_ = header_read_buffer_; | 561 current_read_buffer_ = header_read_buffer_; |
553 num_bytes_to_read = header_read_buffer_->RemainingCapacity(); | 562 num_bytes_to_read = header_read_buffer_->RemainingCapacity(); |
554 DCHECK_LE(num_bytes_to_read, MessageHeader::header_size()); | 563 CHECK_LE(num_bytes_to_read, MessageHeader::header_size()); |
555 } else { | 564 } else { |
556 DCHECK_GT(current_message_size_, 0U); | 565 DCHECK_GT(current_message_size_, 0U); |
557 num_bytes_to_read = current_message_size_ - body_read_buffer_->offset(); | 566 num_bytes_to_read = current_message_size_ - body_read_buffer_->offset(); |
558 current_read_buffer_ = body_read_buffer_; | 567 current_read_buffer_ = body_read_buffer_; |
559 DCHECK_LE(num_bytes_to_read, MessageHeader::max_message_size()); | 568 CHECK_LE(num_bytes_to_read, MessageHeader::max_message_size()); |
560 } | 569 } |
561 DCHECK_GT(num_bytes_to_read, 0U); | 570 CHECK_NE(num_bytes_to_read, 0U); |
Wez
2014/07/24 23:18:38
CHECK_GT?
Kevin M
2014/07/25 17:02:38
Done.
| |
562 | 571 |
563 // Read up to num_bytes_to_read into |current_read_buffer_|. | 572 // Read up to num_bytes_to_read into |current_read_buffer_|. |
564 return socket_->Read( | 573 return socket_->Read( |
565 current_read_buffer_.get(), | 574 current_read_buffer_.get(), |
566 num_bytes_to_read, | 575 num_bytes_to_read, |
567 base::Bind(&CastSocket::DoReadLoop, AsWeakPtr())); | 576 base::Bind(&CastSocket::DoReadLoop, AsWeakPtr())); |
568 } | 577 } |
569 | 578 |
570 int CastSocket::DoReadComplete(int result) { | 579 int CastSocket::DoReadComplete(int result) { |
571 VLOG_WITH_CONNECTION(2) << "DoReadComplete result = " << result | 580 VLOG_WITH_CONNECTION(2) << "DoReadComplete result = " << result |
572 << " header offset = " | 581 << " header offset = " |
573 << header_read_buffer_->offset() | 582 << header_read_buffer_->offset() |
574 << " body offset = " << body_read_buffer_->offset(); | 583 << " body offset = " << body_read_buffer_->offset(); |
575 if (result <= 0) { // 0 means EOF: the peer closed the socket | 584 if (result <= 0) { // 0 means EOF: the peer closed the socket |
576 VLOG_WITH_CONNECTION(1) << "Read error, peer closed the socket"; | 585 VLOG_WITH_CONNECTION(1) << "Read error, peer closed the socket"; |
577 error_state_ = CHANNEL_ERROR_SOCKET_ERROR; | 586 error_state_ = CHANNEL_ERROR_SOCKET_ERROR; |
578 read_state_ = READ_STATE_ERROR; | 587 read_state_ = READ_STATE_ERROR; |
579 return result == 0 ? net::ERR_FAILED : result; | 588 return result == 0 ? net::ERR_FAILED : result; |
580 } | 589 } |
581 | 590 |
582 // Some data was read. Move the offset in the current buffer forward. | 591 // Some data was read. Move the offset in the current buffer forward. |
583 DCHECK_LE(current_read_buffer_->offset() + result, | 592 CHECK_LE(current_read_buffer_->offset() + result, |
584 current_read_buffer_->capacity()); | 593 current_read_buffer_->capacity()); |
585 current_read_buffer_->set_offset(current_read_buffer_->offset() + result); | 594 current_read_buffer_->set_offset(current_read_buffer_->offset() + result); |
586 read_state_ = READ_STATE_READ; | 595 read_state_ = READ_STATE_READ; |
587 | 596 |
588 if (current_read_buffer_.get() == header_read_buffer_.get() && | 597 if (current_read_buffer_.get() == header_read_buffer_.get() && |
589 current_read_buffer_->RemainingCapacity() == 0) { | 598 current_read_buffer_->RemainingCapacity() == 0) { |
590 // A full header is read, process the contents. | 599 // A full header is read, process the contents. |
591 if (!ProcessHeader()) { | 600 if (!ProcessHeader()) { |
592 error_state_ = cast_channel::CHANNEL_ERROR_INVALID_MESSAGE; | 601 error_state_ = cast_channel::CHANNEL_ERROR_INVALID_MESSAGE; |
593 read_state_ = READ_STATE_ERROR; | 602 read_state_ = READ_STATE_ERROR; |
594 } | 603 } |
595 } else if (current_read_buffer_.get() == body_read_buffer_.get() && | 604 } else if (current_read_buffer_.get() == body_read_buffer_.get() && |
596 static_cast<uint32>(current_read_buffer_->offset()) == | 605 static_cast<uint32>(current_read_buffer_->offset()) == |
597 current_message_size_) { | 606 current_message_size_) { |
598 // Full body is read, process the contents. | 607 // Full body is read, process the contents. |
599 if (ProcessBody()) { | 608 if (ProcessBody()) { |
600 read_state_ = READ_STATE_DO_CALLBACK; | 609 read_state_ = READ_STATE_DO_CALLBACK; |
601 } else { | 610 } else { |
602 error_state_ = cast_channel::CHANNEL_ERROR_INVALID_MESSAGE; | 611 error_state_ = cast_channel::CHANNEL_ERROR_INVALID_MESSAGE; |
603 read_state_ = READ_STATE_ERROR; | 612 read_state_ = READ_STATE_ERROR; |
604 } | 613 } |
605 } | 614 } |
606 | 615 |
607 return net::OK; | 616 return net::OK; |
608 } | 617 } |
609 | 618 |
610 int CastSocket::DoReadCallback() { | 619 int CastSocket::DoReadCallback() { |
611 read_state_ = READ_STATE_READ; | 620 read_state_ = READ_STATE_READ; |
612 const CastMessage& message = *(current_message_.get()); | 621 const CastMessage& message = *current_message_; |
613 if (IsAuthMessage(message)) { | 622 if (ready_state_ == READY_STATE_CONNECTING) { |
614 // An auth message is received, check that connect flow is running. | 623 if (IsAuthMessage(message)) { |
615 if (ready_state_ == READY_STATE_CONNECTING) { | |
616 challenge_reply_.reset(new CastMessage(message)); | 624 challenge_reply_.reset(new CastMessage(message)); |
617 PostTaskToStartConnectLoop(net::OK); | 625 PostTaskToStartConnectLoop(net::OK); |
626 return net::OK; | |
618 } else { | 627 } else { |
628 // Expected an auth message, got something else instead. Handle as error. | |
619 read_state_ = READ_STATE_ERROR; | 629 read_state_ = READ_STATE_ERROR; |
630 return net::ERR_INVALID_RESPONSE; | |
620 } | 631 } |
621 } else if (delegate_) { | |
622 MessageInfo message_info; | |
623 if (CastMessageToMessageInfo(message, &message_info)) | |
624 delegate_->OnMessage(this, message_info); | |
625 else | |
626 read_state_ = READ_STATE_ERROR; | |
627 } | 632 } |
633 | |
634 MessageInfo message_info; | |
635 if (!CastMessageToMessageInfo(message, &message_info)) { | |
636 current_message_->Clear(); | |
637 read_state_ = READ_STATE_ERROR; | |
638 return net::ERR_INVALID_RESPONSE; | |
639 } | |
640 delegate_->OnMessage(this, message_info); | |
628 current_message_->Clear(); | 641 current_message_->Clear(); |
629 return net::OK; | 642 return net::OK; |
630 } | 643 } |
631 | 644 |
632 int CastSocket::DoReadError(int result) { | 645 int CastSocket::DoReadError(int result) { |
633 DCHECK_LE(result, 0); | 646 DCHECK_LE(result, 0); |
634 // If inside connection flow, then get back to connect loop. | |
635 if (ready_state_ == READY_STATE_CONNECTING) { | |
636 PostTaskToStartConnectLoop(result); | |
637 // does not try to report error also. | |
638 return net::OK; | |
639 } | |
640 return net::ERR_FAILED; | 647 return net::ERR_FAILED; |
641 } | 648 } |
642 | 649 |
643 bool CastSocket::ProcessHeader() { | 650 bool CastSocket::ProcessHeader() { |
644 DCHECK_EQ(static_cast<uint32>(header_read_buffer_->offset()), | 651 CHECK_EQ(static_cast<uint32>(header_read_buffer_->offset()), |
645 MessageHeader::header_size()); | 652 MessageHeader::header_size()); |
646 MessageHeader header; | 653 MessageHeader header; |
647 MessageHeader::ReadFromIOBuffer(header_read_buffer_.get(), &header); | 654 MessageHeader::ReadFromIOBuffer(header_read_buffer_.get(), &header); |
648 if (header.message_size > MessageHeader::max_message_size()) | 655 if (header.message_size > MessageHeader::max_message_size()) |
649 return false; | 656 return false; |
650 | 657 |
651 VLOG_WITH_CONNECTION(2) << "Parsed header { message_size: " | 658 VLOG_WITH_CONNECTION(2) << "Parsed header { message_size: " |
652 << header.message_size << " }"; | 659 << header.message_size << " }"; |
653 current_message_size_ = header.message_size; | 660 current_message_size_ = header.message_size; |
654 return true; | 661 return true; |
655 } | 662 } |
656 | 663 |
657 bool CastSocket::ProcessBody() { | 664 bool CastSocket::ProcessBody() { |
658 DCHECK_EQ(static_cast<uint32>(body_read_buffer_->offset()), | 665 CHECK_EQ(static_cast<uint32>(body_read_buffer_->offset()), |
659 current_message_size_); | 666 current_message_size_); |
660 if (!current_message_->ParseFromArray( | 667 if (!current_message_->ParseFromArray( |
661 body_read_buffer_->StartOfBuffer(), current_message_size_)) { | 668 body_read_buffer_->StartOfBuffer(), current_message_size_)) { |
662 return false; | 669 return false; |
663 } | 670 } |
664 current_message_size_ = 0; | 671 current_message_size_ = 0; |
665 header_read_buffer_->set_offset(0); | 672 header_read_buffer_->set_offset(0); |
666 body_read_buffer_->set_offset(0); | 673 body_read_buffer_->set_offset(0); |
667 current_read_buffer_ = header_read_buffer_; | 674 current_read_buffer_ = header_read_buffer_; |
668 return true; | 675 return true; |
669 } | 676 } |
670 | 677 |
671 // static | 678 // static |
672 bool CastSocket::Serialize(const CastMessage& message_proto, | 679 bool CastSocket::Serialize(const CastMessage& message_proto, |
673 std::string* message_data) { | 680 std::string* message_data) { |
674 DCHECK(message_data); | 681 DCHECK(message_data); |
675 message_proto.SerializeToString(message_data); | 682 message_proto.SerializeToString(message_data); |
676 size_t message_size = message_data->size(); | 683 size_t message_size = message_data->size(); |
677 if (message_size > MessageHeader::max_message_size()) { | 684 if (message_size > MessageHeader::max_message_size()) { |
678 message_data->clear(); | 685 message_data->clear(); |
679 return false; | 686 return false; |
680 } | 687 } |
681 CastSocket::MessageHeader header; | 688 CastSocket::MessageHeader header; |
682 header.SetMessageSize(message_size); | 689 header.SetMessageSize(message_size); |
683 header.PrependToString(message_data); | 690 header.PrependToString(message_data); |
684 return true; | 691 return true; |
685 }; | 692 } |
686 | 693 |
687 void CastSocket::CloseWithError(ChannelError error) { | 694 void CastSocket::CloseWithError(ChannelError error) { |
688 DCHECK(CalledOnValidThread()); | 695 DCHECK(CalledOnValidThread()); |
689 socket_.reset(NULL); | 696 socket_.reset(NULL); |
690 ready_state_ = READY_STATE_CLOSED; | 697 ready_state_ = READY_STATE_CLOSED; |
691 error_state_ = error; | 698 error_state_ = error; |
692 if (delegate_) | 699 if (delegate_) |
693 delegate_->OnError(this, error); | 700 delegate_->OnError(this, error); |
694 } | 701 } |
695 | 702 |
696 std::string CastSocket::CastUrl() const { | 703 std::string CastSocket::CastUrl() const { |
697 return ((channel_auth_ == CHANNEL_AUTH_TYPE_SSL_VERIFIED) ? | 704 return ((channel_auth_ == CHANNEL_AUTH_TYPE_SSL_VERIFIED) ? |
698 "casts://" : "cast://") + ip_endpoint_.ToString(); | 705 "casts://" : "cast://") + ip_endpoint_.ToString(); |
699 } | 706 } |
700 | 707 |
701 bool CastSocket::CalledOnValidThread() const { | 708 bool CastSocket::CalledOnValidThread() const { |
702 return thread_checker_.CalledOnValidThread(); | 709 return thread_checker_.CalledOnValidThread(); |
703 } | 710 } |
704 | 711 |
705 CastSocket::MessageHeader::MessageHeader() : message_size(0) { } | 712 CastSocket::MessageHeader::MessageHeader() : message_size(0) { } |
706 | 713 |
707 void CastSocket::MessageHeader::SetMessageSize(size_t size) { | 714 void CastSocket::MessageHeader::SetMessageSize(size_t size) { |
708 DCHECK(size < static_cast<size_t>(kuint32max)); | 715 message_size = size; |
709 DCHECK(size > 0); | |
710 message_size = static_cast<size_t>(size); | |
711 } | 716 } |
712 | 717 |
713 // TODO(mfoltz): Investigate replacing header serialization with base::Pickle, | 718 // TODO(mfoltz): Investigate replacing header serialization with base::Pickle, |
714 // if bit-for-bit compatible. | 719 // if bit-for-bit compatible. |
715 void CastSocket::MessageHeader::PrependToString(std::string* str) { | 720 void CastSocket::MessageHeader::PrependToString(std::string* str) { |
716 MessageHeader output = *this; | 721 MessageHeader output = *this; |
717 output.message_size = base::HostToNet32(message_size); | 722 output.message_size = base::HostToNet32(message_size); |
718 size_t header_size = base::checked_cast<size_t,uint32>( | 723 size_t header_size = base::checked_cast<size_t,uint32>( |
719 MessageHeader::header_size()); | 724 MessageHeader::header_size()); |
720 scoped_ptr<char, base::FreeDeleter> char_array( | 725 scoped_ptr<char, base::FreeDeleter> char_array( |
(...skipping 30 matching lines...) Expand all Loading... | |
751 return true; | 756 return true; |
752 } | 757 } |
753 | 758 |
754 CastSocket::WriteRequest::~WriteRequest() { } | 759 CastSocket::WriteRequest::~WriteRequest() { } |
755 | 760 |
756 } // namespace cast_channel | 761 } // namespace cast_channel |
757 } // namespace api | 762 } // namespace api |
758 } // namespace extensions | 763 } // namespace extensions |
759 | 764 |
760 #undef VLOG_WITH_CONNECTION | 765 #undef VLOG_WITH_CONNECTION |
OLD | NEW |