14e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 24e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 34e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// found in the LICENSE file. 44e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 54e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/extensions/api/cast_channel/cast_socket.h" 64e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 74e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include <string.h> 84e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 94e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/bind.h" 108bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "base/callback_helpers.h" 114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/lazy_instance.h" 124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/strings/string_number_conversions.h" 134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/sys_byteorder.h" 141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "chrome/browser/extensions/api/cast_channel/cast_auth_util.h" 154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/extensions/api/cast_channel/cast_channel.pb.h" 164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/extensions/api/cast_channel/cast_message_util.h" 174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "net/base/address_list.h" 188bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "net/base/host_port_pair.h" 194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "net/base/net_errors.h" 204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "net/base/net_util.h" 218bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "net/cert/cert_verifier.h" 228bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "net/cert/x509_certificate.h" 238bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "net/http/transport_security_state.h" 248bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "net/socket/client_socket_factory.h" 258bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "net/socket/client_socket_handle.h" 268bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "net/socket/ssl_client_socket.h" 278bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "net/socket/stream_socket.h" 284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "net/socket/tcp_client_socket.h" 298bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "net/ssl/ssl_config_service.h" 308bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "net/ssl/ssl_info.h" 314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace { 334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Allowed schemes for Cast device URLs. 354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kCastInsecureScheme[] = "cast"; 364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kCastSecureScheme[] = "casts"; 374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Size of the message header, in bytes. Don't use sizeof(MessageHeader) 394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// because of alignment; instead, sum the sizeof() for the fields. 404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const uint32 kMessageHeaderSize = sizeof(uint32); 414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// The default keepalive delay. On Linux, keepalives probes will be sent after 434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// the socket is idle for this length of time, and the socket will be closed 444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// after 9 failed probes. So the total idle time before close is 10 * 454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// kTcpKeepAliveDelaySecs. 464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const int kTcpKeepAliveDelaySecs = 10; 474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} // namespace 494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace extensions { 514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)static base::LazyInstance< 534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) ProfileKeyedAPIFactory<ApiResourceManager<api::cast_channel::CastSocket> > > 544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) g_factory = LAZY_INSTANCE_INITIALIZER; 554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// static 574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)template <> 584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)ProfileKeyedAPIFactory<ApiResourceManager<api::cast_channel::CastSocket> >* 594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)ApiResourceManager<api::cast_channel::CastSocket>::GetFactoryInstance() { 604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return &g_factory.Get(); 614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace api { 644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace cast_channel { 654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const uint32 kMaxMessageSize = 65536; 674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)CastSocket::CastSocket(const std::string& owner_extension_id, 691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) const GURL& url, 701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) CastSocket::Delegate* delegate, 714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) net::NetLog* net_log) : 728bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) ApiResource(owner_extension_id), 738bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) channel_id_(0), 748bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) url_(url), 758bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) delegate_(delegate), 761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) auth_required_(false), 778bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) error_state_(CHANNEL_ERROR_NONE), 788bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) ready_state_(READY_STATE_NONE), 798bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) write_callback_pending_(false), 808bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) read_callback_pending_(false), 818bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) current_message_size_(0), 828bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) net_log_(net_log), 83f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) next_state_(CONN_STATE_NONE), 84f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) in_connect_loop_(false) { 854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DCHECK(net_log_); 864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) net_log_source_.type = net::NetLog::SOURCE_SOCKET; 874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) net_log_source_.id = net_log_->NextID(); 884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // We reuse these buffers for each message. 904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) header_read_buffer_ = new net::GrowableIOBuffer(); 914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) header_read_buffer_->SetCapacity(kMessageHeaderSize); 924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) body_read_buffer_ = new net::GrowableIOBuffer(); 934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) body_read_buffer_->SetCapacity(kMaxMessageSize); 944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) current_read_buffer_ = header_read_buffer_; 954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)CastSocket::~CastSocket() { } 984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const GURL& CastSocket::url() const { 1004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return url_; 1014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 1024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1038bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)scoped_ptr<net::TCPClientSocket> CastSocket::CreateTcpSocket() { 1048bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) net::AddressList addresses(ip_endpoint_); 1058bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) scoped_ptr<net::TCPClientSocket> tcp_socket( 1068bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) new net::TCPClientSocket(addresses, net_log_, net_log_source_)); 107f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Options cannot be set on the TCPClientSocket yet, because the 108f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // underlying platform socket will not be created until we Bind() 109f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // or Connect() it. 1108bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return tcp_socket.Pass(); 1118bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)} 1128bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 1138bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)scoped_ptr<net::SSLClientSocket> CastSocket::CreateSslSocket() { 1148bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) net::SSLConfig ssl_config; 1158bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // If a peer cert was extracted in a previous attempt to connect, then 1168bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // whitelist that cert. 1178bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if (!peer_cert_.empty()) { 1188bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) net::SSLConfig::CertAndStatus cert_and_status; 1198bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) cert_and_status.cert_status = net::CERT_STATUS_AUTHORITY_INVALID; 1208bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) cert_and_status.der_cert = peer_cert_; 1218bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) ssl_config.allowed_bad_certs.push_back(cert_and_status); 1228bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) } 1238bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 1248bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) cert_verifier_.reset(net::CertVerifier::CreateDefault()); 1258bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) transport_security_state_.reset(new net::TransportSecurityState); 1268bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) net::SSLClientSocketContext context; 1278bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // CertVerifier and TransportSecurityState are owned by us, not the 1288bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // context object. 1298bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) context.cert_verifier = cert_verifier_.get(); 1308bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) context.transport_security_state = transport_security_state_.get(); 1318bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 1328bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) scoped_ptr<net::ClientSocketHandle> connection(new net::ClientSocketHandle); 1338bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) connection->SetSocket(tcp_socket_.PassAs<net::StreamSocket>()); 1348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) net::HostPortPair host_and_port = net::HostPortPair::FromIPEndPoint( 1358bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) ip_endpoint_); 1368bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 1378bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return net::ClientSocketFactory::GetDefaultFactory()->CreateSSLClientSocket( 1388bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) connection.Pass(), host_and_port, ssl_config, context); 1398bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)} 1408bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 1411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)bool CastSocket::ExtractPeerCert(std::string* cert) { 1421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) DCHECK(cert); 1431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) DCHECK(peer_cert_.empty()); 1441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) net::SSLInfo ssl_info; 1451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (!socket_->GetSSLInfo(&ssl_info) || !ssl_info.cert.get()) 1461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return false; 1471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) bool result = net::X509Certificate::GetDEREncoded( 1481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) ssl_info.cert->os_cert_handle(), cert); 1491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (result) 150f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) VLOG(1) << "Successfully extracted peer certificate: " << *cert; 1511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return result; 1521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 1531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 1541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)int CastSocket::SendAuthChallenge() { 1551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) CastMessage challenge_message; 1561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) CreateAuthChallengeMessage(&challenge_message); 157f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) VLOG(1) << "Sending challenge: " << CastMessageToString(challenge_message); 158f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) int result = SendMessageInternal( 1591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) challenge_message, 1601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) base::Bind(&CastSocket::OnChallengeEvent, AsWeakPtr())); 161f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return (result < 0) ? result : net::OK; 1621e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 1631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 1641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)int CastSocket::ReadAuthChallengeReply() { 165f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) int result = ReadData(); 166f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return (result < 0) ? result : net::OK; 1671e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 1681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 1698bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void CastSocket::OnConnectComplete(int result) { 1708bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) int rv = DoConnectLoop(result); 1718bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if (rv != net::ERR_IO_PENDING) 1728bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) DoConnectCallback(rv); 1734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 1744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void CastSocket::OnChallengeEvent(int result) { 1761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // result >= 0 means read or write succeeded synchronously. 1771e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) int rv = DoConnectLoop(result >= 0 ? net::OK : result); 1781e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (rv != net::ERR_IO_PENDING) 1791e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) DoConnectCallback(rv); 1801e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 1811e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 1824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void CastSocket::Connect(const net::CompletionCallback& callback) { 1834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DCHECK(CalledOnValidThread()); 1844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) int result = net::ERR_CONNECTION_FAILED; 185f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) VLOG(1) << "Connect readyState = " << ready_state_; 1864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (ready_state_ != READY_STATE_NONE) { 1874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) callback.Run(result); 1884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return; 1894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 1904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!ParseChannelUrl(url_)) { 1914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) CloseWithError(cast_channel::CHANNEL_ERROR_CONNECT_ERROR); 1924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) callback.Run(result); 1934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return; 1944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 1954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) connect_callback_ = callback; 1968bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) next_state_ = CONN_STATE_TCP_CONNECT; 1978bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) int rv = DoConnectLoop(net::OK); 1988bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if (rv != net::ERR_IO_PENDING) 1998bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) DoConnectCallback(rv); 2004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 2014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 2028bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// This method performs the state machine transitions for connection flow. 2038bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// There are two entry points to this method: 2048bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// 1. public Connect method: this starts the flow 2058bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// 2. OnConnectComplete: callback method called when an async operation 2068bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// is done. OnConnectComplete calls this method to continue the state 2078bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// machine transitions. 2088bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)int CastSocket::DoConnectLoop(int result) { 209f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Avoid re-entrancy as a result of synchronous completion. 210f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (in_connect_loop_) 211f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return net::ERR_IO_PENDING; 212f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) in_connect_loop_ = true; 213f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 214f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Network operations can either finish synchronously or asynchronously. 2158bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // This method executes the state machine transitions in a loop so that 2168bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // correct state transitions happen even when network operations finish 2178bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // synchronously. 2188bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) int rv = result; 2198bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) do { 2208bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) ConnectionState state = next_state_; 2218bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // All the Do* methods do not set next_state_ in case of an 2228bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // error. So set next_state_ to NONE to figure out if the Do* 2238bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // method changed state or not. 2248bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) next_state_ = CONN_STATE_NONE; 2258bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) switch (state) { 2268bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) case CONN_STATE_TCP_CONNECT: 2278bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) rv = DoTcpConnect(); 2288bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) break; 2298bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) case CONN_STATE_TCP_CONNECT_COMPLETE: 2308bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) rv = DoTcpConnectComplete(rv); 2318bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) break; 2328bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) case CONN_STATE_SSL_CONNECT: 2338bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) DCHECK_EQ(net::OK, rv); 2348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) rv = DoSslConnect(); 2358bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) break; 2368bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) case CONN_STATE_SSL_CONNECT_COMPLETE: 2378bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) rv = DoSslConnectComplete(rv); 2388bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) break; 2391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) case CONN_STATE_AUTH_CHALLENGE_SEND: 2401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) rv = DoAuthChallengeSend(); 2411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) break; 2421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) case CONN_STATE_AUTH_CHALLENGE_SEND_COMPLETE: 2431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) rv = DoAuthChallengeSendComplete(rv); 2441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) break; 2451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) case CONN_STATE_AUTH_CHALLENGE_REPLY_COMPLETE: 2461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) rv = DoAuthChallengeReplyComplete(rv); 2471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) break; 2481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 2498bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) default: 2508bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) NOTREACHED() << "BUG in CastSocket state machine code"; 2518bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) break; 2528bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) } 2538bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) } while (rv != net::ERR_IO_PENDING && next_state_ != CONN_STATE_NONE); 2548bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // Get out of the loop either when: 2558bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // a. A network operation is pending, OR 2568bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // b. The Do* method called did not change state 2578bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 258f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) in_connect_loop_ = false; 259f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 2608bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return rv; 2618bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)} 2628bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 2638bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)int CastSocket::DoTcpConnect() { 264f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) VLOG(1) << "DoTcpConnect"; 2658bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) next_state_ = CONN_STATE_TCP_CONNECT_COMPLETE; 2668bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) tcp_socket_ = CreateTcpSocket(); 2678bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return tcp_socket_->Connect( 2688bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) base::Bind(&CastSocket::OnConnectComplete, AsWeakPtr())); 2698bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)} 2708bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 2718bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)int CastSocket::DoTcpConnectComplete(int result) { 272f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) VLOG(1) << "DoTcpConnectComplete: " << result; 273f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (result == net::OK) { 274f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Enable TCP protocol-level keep-alive. 275f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) bool result = tcp_socket_->SetKeepAlive(true, kTcpKeepAliveDelaySecs); 276f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) LOG_IF(WARNING, !result) << "Failed to SetKeepAlive."; 2778bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) next_state_ = CONN_STATE_SSL_CONNECT; 278f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 2798bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return result; 2808bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)} 2818bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 2828bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)int CastSocket::DoSslConnect() { 283f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) VLOG(1) << "DoSslConnect"; 2848bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) next_state_ = CONN_STATE_SSL_CONNECT_COMPLETE; 2858bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) socket_ = CreateSslSocket(); 2868bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return socket_->Connect( 2878bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) base::Bind(&CastSocket::OnConnectComplete, AsWeakPtr())); 2888bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)} 2898bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 2908bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)int CastSocket::DoSslConnectComplete(int result) { 291f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) VLOG(1) << "DoSslConnectComplete: " << result; 2928bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if (result == net::ERR_CERT_AUTHORITY_INVALID && 2938bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) peer_cert_.empty() && 2948bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) ExtractPeerCert(&peer_cert_)) { 2958bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) next_state_ = CONN_STATE_TCP_CONNECT; 2961e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } else if (result == net::OK && auth_required_) { 2971e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) next_state_ = CONN_STATE_AUTH_CHALLENGE_SEND; 2988bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) } 2998bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return result; 3008bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)} 3018bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 3021e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)int CastSocket::DoAuthChallengeSend() { 303f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) VLOG(1) << "DoAuthChallengeSend"; 3041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) next_state_ = CONN_STATE_AUTH_CHALLENGE_SEND_COMPLETE; 3051e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return SendAuthChallenge(); 3061e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 3071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 3081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)int CastSocket::DoAuthChallengeSendComplete(int result) { 309f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) VLOG(1) << "DoAuthChallengeSendComplete: " << result; 3101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (result != net::OK) 3111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return result; 3121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) next_state_ = CONN_STATE_AUTH_CHALLENGE_REPLY_COMPLETE; 3131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return ReadAuthChallengeReply(); 3141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 3151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 3161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)int CastSocket::DoAuthChallengeReplyComplete(int result) { 317f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) VLOG(1) << "DoAuthChallengeReplyComplete: " << result; 3181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (result != net::OK) 3191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return result; 3201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (!VerifyChallengeReply()) 3211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return net::ERR_FAILED; 322f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) VLOG(1) << "Auth challenge verification succeeded"; 3231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return net::OK; 3241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 3251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 3261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)bool CastSocket::VerifyChallengeReply() { 3271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return AuthenticateChallengeReply(*challenge_reply_.get(), peer_cert_); 3281e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 3291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 3308bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void CastSocket::DoConnectCallback(int result) { 3318bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) ready_state_ = (result == net::OK) ? READY_STATE_OPEN : READY_STATE_CLOSED; 3328bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) error_state_ = (result == net::OK) ? 3338bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) CHANNEL_ERROR_NONE : CHANNEL_ERROR_CONNECT_ERROR; 3348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) base::ResetAndReturn(&connect_callback_).Run(result); 3351e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // Start the ReadData loop if not already started. 3361e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // If auth_required_ is true we would've started a ReadData loop already. 3371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // TODO(munjal): This is a bit ugly. Refactor read and write code. 3381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (result == net::OK && !auth_required_) 3398bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) ReadData(); 3404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 3414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 3424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void CastSocket::Close(const net::CompletionCallback& callback) { 3434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DCHECK(CalledOnValidThread()); 344f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) VLOG(1) << "Close ReadyState = " << ready_state_; 3458bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) tcp_socket_.reset(NULL); 3464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) socket_.reset(NULL); 3478bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) cert_verifier_.reset(NULL); 3488bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) transport_security_state_.reset(NULL); 3494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) ready_state_ = READY_STATE_CLOSED; 3504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) callback.Run(net::OK); 3514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 3524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 3534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void CastSocket::SendMessage(const MessageInfo& message, 3544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const net::CompletionCallback& callback) { 3554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DCHECK(CalledOnValidThread()); 356f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) VLOG(1) << "Send ReadyState " << ready_state_; 3574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) int result = net::ERR_FAILED; 3584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (ready_state_ != READY_STATE_OPEN) { 3594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) callback.Run(result); 3604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return; 3614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 3624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) CastMessage message_proto; 3631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (!MessageInfoToCastMessage(message, &message_proto)) { 3644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) CloseWithError(cast_channel::CHANNEL_ERROR_INVALID_MESSAGE); 3654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // TODO(mfoltz): Do a better job of signaling cast_channel errors to the 3664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // caller. 3674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) callback.Run(net::OK); 3684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return; 3694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 3701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) SendMessageInternal(message_proto, callback); 3711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 3721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 3731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)int CastSocket::SendMessageInternal(const CastMessage& message_proto, 374f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const net::CompletionCallback& callback) { 3751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) WriteRequest write_request(callback); 3761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (!write_request.SetContent(message_proto)) 3771e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return net::ERR_FAILED; 3784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) write_queue_.push(write_request); 3791e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return WriteData(); 3804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 3814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 3821e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)int CastSocket::WriteData() { 3834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DCHECK(CalledOnValidThread()); 384f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) VLOG(1) << "WriteData q = " << write_queue_.size(); 3854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (write_queue_.empty() || write_callback_pending_) 3861e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return net::ERR_FAILED; 3874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 3884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) WriteRequest& request = write_queue_.front(); 3894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 390f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) VLOG(1) << "WriteData byte_count = " << request.io_buffer->size() 391f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) << " bytes_written " << request.io_buffer->BytesConsumed(); 3924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 3934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) write_callback_pending_ = true; 3944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) int result = socket_->Write( 3954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) request.io_buffer.get(), 3964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) request.io_buffer->BytesRemaining(), 3974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::Bind(&CastSocket::OnWriteData, AsWeakPtr())); 3984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 3994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (result != net::ERR_IO_PENDING) 4004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) OnWriteData(result); 4011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 4021e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return result; 4034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 4044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 4054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void CastSocket::OnWriteData(int result) { 4064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DCHECK(CalledOnValidThread()); 407f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) VLOG(1) << "OnWriteComplete result = " << result; 4084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DCHECK(write_callback_pending_); 4094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DCHECK(!write_queue_.empty()); 4104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) write_callback_pending_ = false; 4114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) WriteRequest& request = write_queue_.front(); 4124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) scoped_refptr<net::DrainableIOBuffer> io_buffer = request.io_buffer; 4134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 4144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (result >= 0) { 4154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) io_buffer->DidConsume(result); 4164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (io_buffer->BytesRemaining() > 0) { 417f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) VLOG(1) << "OnWriteComplete size = " << io_buffer->size() 418f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) << " consumed " << io_buffer->BytesConsumed() 419f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) << " remaining " << io_buffer->BytesRemaining() 420f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) << " # requests " << write_queue_.size(); 4214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) WriteData(); 4224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return; 4234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 4244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DCHECK_EQ(io_buffer->BytesConsumed(), io_buffer->size()); 4254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DCHECK_EQ(io_buffer->BytesRemaining(), 0); 4264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) result = io_buffer->BytesConsumed(); 4274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 4284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 4294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) request.callback.Run(result); 4304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) write_queue_.pop(); 4314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 432f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) VLOG(1) << "OnWriteComplete size = " << io_buffer->size() 433f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) << " consumed " << io_buffer->BytesConsumed() 434f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) << " remaining " << io_buffer->BytesRemaining() 435f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) << " # requests " << write_queue_.size(); 4364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 4374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (result < 0) { 4384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) CloseWithError(CHANNEL_ERROR_SOCKET_ERROR); 4394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return; 4404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 4414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 4424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!write_queue_.empty()) 4434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) WriteData(); 4444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 4454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 4461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)int CastSocket::ReadData() { 4474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DCHECK(CalledOnValidThread()); 4481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (!socket_.get()) 4491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return net::ERR_FAILED; 4504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DCHECK(!read_callback_pending_); 4514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) read_callback_pending_ = true; 4524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // Figure out if we are reading the header or body, and the remaining bytes. 4534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) uint32 num_bytes_to_read = 0; 4544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (header_read_buffer_->RemainingCapacity() > 0) { 4554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) current_read_buffer_ = header_read_buffer_; 4564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) num_bytes_to_read = header_read_buffer_->RemainingCapacity(); 4574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DCHECK_LE(num_bytes_to_read, kMessageHeaderSize); 4584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } else { 4594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DCHECK_GT(current_message_size_, 0U); 4604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) num_bytes_to_read = current_message_size_ - body_read_buffer_->offset(); 4614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) current_read_buffer_ = body_read_buffer_; 4624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DCHECK_LE(num_bytes_to_read, kMaxMessageSize); 4634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 4644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DCHECK_GT(num_bytes_to_read, 0U); 4654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // We read up to num_bytes_to_read into |current_read_buffer_|. 4664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) int result = socket_->Read( 4674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) current_read_buffer_.get(), 4684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) num_bytes_to_read, 4694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::Bind(&CastSocket::OnReadData, AsWeakPtr())); 470f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) VLOG(1) << "ReadData result = " << result; 4714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (result > 0) { 4724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) OnReadData(result); 4734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } else if (result != net::ERR_IO_PENDING) { 4744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) CloseWithError(CHANNEL_ERROR_SOCKET_ERROR); 4754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 4761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return result; 4774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 4784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 4794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void CastSocket::OnReadData(int result) { 4804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DCHECK(CalledOnValidThread()); 481f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) VLOG(1) << "OnReadData result = " << result 482f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) << " header offset = " << header_read_buffer_->offset() 483f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) << " body offset = " << body_read_buffer_->offset(); 4844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) read_callback_pending_ = false; 4854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (result <= 0) { 4864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) CloseWithError(CHANNEL_ERROR_SOCKET_ERROR); 4874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return; 4884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 4894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // We read some data. Move the offset in the current buffer forward. 4904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DCHECK_LE(current_read_buffer_->offset() + result, 4914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) current_read_buffer_->capacity()); 4924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) current_read_buffer_->set_offset(current_read_buffer_->offset() + result); 4934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 4944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) bool should_continue = true; 4954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (current_read_buffer_.get() == header_read_buffer_.get() && 4964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) current_read_buffer_->RemainingCapacity() == 0) { 4974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // If we have read a full header, process the contents. 4984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) should_continue = ProcessHeader(); 4994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } else if (current_read_buffer_.get() == body_read_buffer_.get() && 5004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) static_cast<uint32>(current_read_buffer_->offset()) == 5014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) current_message_size_) { 5024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // If we have read a full body, process the contents. 5034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) should_continue = ProcessBody(); 5044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 5054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (should_continue) 5064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) ReadData(); 5074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 5084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 5094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool CastSocket::ProcessHeader() { 5104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DCHECK_EQ(static_cast<uint32>(header_read_buffer_->offset()), 5114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) kMessageHeaderSize); 5124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) MessageHeader header; 5134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) MessageHeader::ReadFromIOBuffer(header_read_buffer_.get(), &header); 5144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (header.message_size > kMaxMessageSize) { 5154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) CloseWithError(cast_channel::CHANNEL_ERROR_INVALID_MESSAGE); 5164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return false; 5174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 518f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) VLOG(1) << "Parsed header { message_size: " << header.message_size << " }"; 5194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) current_message_size_ = header.message_size; 5204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return true; 5214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 5224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 5234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool CastSocket::ProcessBody() { 5244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DCHECK_EQ(static_cast<uint32>(body_read_buffer_->offset()), 5254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) current_message_size_); 5264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!ParseMessageFromBody()) { 5274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) CloseWithError(cast_channel::CHANNEL_ERROR_INVALID_MESSAGE); 5284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return false; 5294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 5304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) current_message_size_ = 0; 5314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) header_read_buffer_->set_offset(0); 5324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) body_read_buffer_->set_offset(0); 5334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) current_read_buffer_ = header_read_buffer_; 5344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return true; 5354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 5364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 5374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool CastSocket::ParseMessageFromBody() { 5384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DCHECK(CalledOnValidThread()); 5394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DCHECK_EQ(static_cast<uint32>(body_read_buffer_->offset()), 5404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) current_message_size_); 5414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) CastMessage message_proto; 5424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!message_proto.ParseFromArray( 5434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) body_read_buffer_->StartOfBuffer(), 5444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) current_message_size_)) 5454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return false; 546f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) VLOG(1) << "Parsed message " << CastMessageToString(message_proto); 5471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // If the message is an auth message then we handle it internally. 5481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (IsAuthMessage(message_proto)) { 5491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) challenge_reply_.reset(new CastMessage(message_proto)); 5501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) OnChallengeEvent(net::OK); 5511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } else if (delegate_) { 5524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) MessageInfo message; 5534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!CastMessageToMessageInfo(message_proto, &message)) 5544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return false; 5554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) delegate_->OnMessage(this, message); 5564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 5574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return true; 5584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 5594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 5604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// static 5614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool CastSocket::Serialize(const CastMessage& message_proto, 5624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) std::string* message_data) { 5634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DCHECK(message_data); 5644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) message_proto.SerializeToString(message_data); 5654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) size_t message_size = message_data->size(); 5664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (message_size > kMaxMessageSize) { 5674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) message_data->clear(); 5684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return false; 5694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 5704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) CastSocket::MessageHeader header; 5714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) header.SetMessageSize(message_size); 5724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) header.PrependToString(message_data); 5734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return true; 5744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}; 5754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 5764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void CastSocket::CloseWithError(ChannelError error) { 5774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DCHECK(CalledOnValidThread()); 5784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) socket_.reset(NULL); 5794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) ready_state_ = READY_STATE_CLOSED; 5804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) error_state_ = error; 5814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (delegate_) 5824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) delegate_->OnError(this, error); 5834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 5844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 5854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool CastSocket::ParseChannelUrl(const GURL& url) { 586f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) VLOG(1) << "url = " + url.spec(); 5874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (url.SchemeIs(kCastInsecureScheme)) { 5881e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) auth_required_ = false; 5894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } else if (url.SchemeIs(kCastSecureScheme)) { 5901e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) auth_required_ = true; 5914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } else { 5924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return false; 5934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 5944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // TODO(mfoltz): Manual parsing, yech. Register cast[s] as standard schemes? 5954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // TODO(mfoltz): Test for IPv6 addresses. Brackets or no brackets? 5964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // TODO(mfoltz): Maybe enforce restriction to IPv4 private and IPv6 link-local 5974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // networks 5984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const std::string& path = url.path(); 5994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // Shortest possible: //A:B 6004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (path.size() < 5) { 6014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return false; 6024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 6034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (path.find("//") != 0) { 6044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return false; 6054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 6064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) size_t colon = path.find_last_of(':'); 6074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (colon == std::string::npos || colon < 3 || colon > path.size() - 2) { 6084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return false; 6094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 6104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const std::string& ip_address_str = path.substr(2, colon - 2); 6114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const std::string& port_str = path.substr(colon + 1); 612f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) VLOG(1) << "addr " << ip_address_str << " port " << port_str; 6134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) int port; 6144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!base::StringToInt(port_str, &port)) 6154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return false; 6164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) net::IPAddressNumber ip_address; 6174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!net::ParseIPLiteralToNumber(ip_address_str, &ip_address)) 6184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return false; 6194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) ip_endpoint_ = net::IPEndPoint(ip_address, port); 6204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return true; 6214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}; 6224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 6234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void CastSocket::FillChannelInfo(ChannelInfo* channel_info) const { 6244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DCHECK(CalledOnValidThread()); 6254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) channel_info->channel_id = channel_id_; 6264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) channel_info->url = url_.spec(); 6274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) channel_info->ready_state = ready_state_; 6284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) channel_info->error_state = error_state_; 6294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 6304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 6310f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)bool CastSocket::CalledOnValidThread() const { 6320f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) return thread_checker_.CalledOnValidThread(); 6330f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)} 6340f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 6354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)CastSocket::MessageHeader::MessageHeader() : message_size(0) { } 6364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 6374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void CastSocket::MessageHeader::SetMessageSize(size_t size) { 6384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DCHECK(size < static_cast<size_t>(kuint32max)); 6394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DCHECK(size > 0); 6404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) message_size = static_cast<size_t>(size); 6414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 6424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 6434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void CastSocket::MessageHeader::PrependToString(std::string* str) { 6444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) MessageHeader output = *this; 6454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) output.message_size = base::HostToNet32(message_size); 6464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) char char_array[kMessageHeaderSize]; 6474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) memcpy(&char_array, &output, arraysize(char_array)); 6484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) str->insert(0, char_array, arraysize(char_array)); 6494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 6504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 6514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void CastSocket::MessageHeader::ReadFromIOBuffer( 6524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) net::GrowableIOBuffer* buffer, MessageHeader* header) { 6534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) uint32 message_size; 6544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) memcpy(&message_size, buffer->StartOfBuffer(), kMessageHeaderSize); 6554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) header->message_size = base::NetToHost32(message_size); 6564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 6574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 6584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)std::string CastSocket::MessageHeader::ToString() { 6594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return "{message_size: " + base::UintToString(message_size) + "}"; 6604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 6614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 6624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)CastSocket::WriteRequest::WriteRequest(const net::CompletionCallback& callback) 6634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) : callback(callback) { } 6644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 6654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool CastSocket::WriteRequest::SetContent(const CastMessage& message_proto) { 6664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DCHECK(!io_buffer.get()); 6674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) std::string message_data; 6684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!Serialize(message_proto, &message_data)) 6694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return false; 6704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) io_buffer = new net::DrainableIOBuffer(new net::StringIOBuffer(message_data), 6714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) message_data.size()); 6724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return true; 6734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 6744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 6754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)CastSocket::WriteRequest::~WriteRequest() { } 6764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 6774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} // namespace cast_channel 6784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} // namespace api 6794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} // namespace extensions 680