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