cast_channel_api.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
15f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Copyright 2014 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)
55f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "extensions/browser/api/cast_channel/cast_channel_api.h"
64e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
70529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include <limits>
85f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include <string>
90529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
108bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "base/json/json_writer.h"
110f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
120529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "base/strings/string_number_conversions.h"
134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/values.h"
144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "content/public/browser/browser_thread.h"
155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "extensions/browser/api/cast_channel/cast_socket.h"
16f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/browser/event_router.h"
170529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "net/base/ip_endpoint.h"
184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "net/base/net_errors.h"
190529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "net/base/net_util.h"
204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "url/gurl.h"
214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Default timeout interval for connection setup.
235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Used if not otherwise specified at ConnectInfo::timeout.
245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)const int kDefaultConnectTimeoutMillis = 5000;  // 5 seconds.
255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace extensions {
274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace Close = cast_channel::Close;
294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace OnError = cast_channel::OnError;
304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace OnMessage = cast_channel::OnMessage;
314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace Open = cast_channel::Open;
324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace Send = cast_channel::Send;
334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)using cast_channel::CastSocket;
340529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochusing cast_channel::ChannelAuthType;
354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)using cast_channel::ChannelError;
364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)using cast_channel::ChannelInfo;
370529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochusing cast_channel::ConnectInfo;
384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)using cast_channel::MessageInfo;
394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)using cast_channel::ReadyState;
404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)using content::BrowserThread;
414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace {
438bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
448bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// T is an extension dictionary (MessageInfo or ChannelInfo)
458bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)template <class T>
468bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)std::string ParamToString(const T& info) {
478bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  scoped_ptr<base::DictionaryValue> dict = info.ToValue();
488bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  std::string out;
498bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  base::JSONWriter::Write(dict.get(), &out);
508bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  return out;
518bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
528bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
530529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// Fills |channel_info| from the destination and state of |socket|.
540529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid FillChannelInfo(const CastSocket& socket, ChannelInfo* channel_info) {
550529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DCHECK(channel_info);
560529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  channel_info->channel_id = socket.id();
570529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  channel_info->url = socket.CastUrl();
580529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  const net::IPEndPoint& ip_endpoint = socket.ip_endpoint();
590529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  channel_info->connect_info.ip_address = ip_endpoint.ToStringWithoutPort();
600529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  channel_info->connect_info.port = ip_endpoint.port();
610529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  channel_info->connect_info.auth = socket.channel_auth();
620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  channel_info->ready_state = socket.ready_state();
630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  channel_info->error_state = socket.error_state();
640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool IsValidConnectInfoPort(const ConnectInfo& connect_info) {
675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return connect_info.port > 0 && connect_info.port <
685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    std::numeric_limits<uint16_t>::max();
695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool IsValidConnectInfoAuth(const ConnectInfo& connect_info) {
725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return connect_info.auth == cast_channel::CHANNEL_AUTH_TYPE_SSL_VERIFIED ||
735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    connect_info.auth == cast_channel::CHANNEL_AUTH_TYPE_SSL;
745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool IsValidConnectInfoIpAddress(const ConnectInfo& connect_info) {
775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  net::IPAddressNumber ip_address;
785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return net::ParseIPLiteralToNumber(connect_info.ip_address, &ip_address);
795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}  // namespace
824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
83a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)CastChannelAPI::CastChannelAPI(content::BrowserContext* context)
84a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    : browser_context_(context) {
85a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(browser_context_);
864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// static
89a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)CastChannelAPI* CastChannelAPI::Get(content::BrowserContext* context) {
90a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return BrowserContextKeyedAPIFactory<CastChannelAPI>::Get(context);
914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
93a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)static base::LazyInstance<BrowserContextKeyedAPIFactory<CastChannelAPI> >
94a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    g_factory = LAZY_INSTANCE_INITIALIZER;
954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// static
97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)BrowserContextKeyedAPIFactory<CastChannelAPI>*
98a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)CastChannelAPI::GetFactoryInstance() {
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return g_factory.Pointer();
1004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1020f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)scoped_ptr<CastSocket> CastChannelAPI::CreateCastSocket(
1030529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const std::string& extension_id, const net::IPEndPoint& ip_endpoint,
1045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    ChannelAuthType channel_auth, const base::TimeDelta& timeout) {
1050f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (socket_for_test_.get()) {
1060f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return socket_for_test_.Pass();
1070f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  } else {
1080f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return scoped_ptr<CastSocket>(
1090529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        new CastSocket(extension_id, ip_endpoint, channel_auth, this,
1105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                       ExtensionsBrowserClient::Get()->GetNetLog(),
1115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                       timeout));
1120f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
1130f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
1140f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
1150f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)void CastChannelAPI::SetSocketForTest(scoped_ptr<CastSocket> socket_for_test) {
1160f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  socket_for_test_ = socket_for_test.Pass();
1170f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
1180f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
1194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void CastChannelAPI::OnError(const CastSocket* socket,
1204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                             cast_channel::ChannelError error) {
121effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
1224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ChannelInfo channel_info;
1230529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  FillChannelInfo(*socket, &channel_info);
1244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  channel_info.error_state = error;
1254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  scoped_ptr<base::ListValue> results = OnError::Create(channel_info);
1264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  scoped_ptr<Event> event(new Event(OnError::kEventName, results.Pass()));
1270529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  extensions::EventRouter::Get(browser_context_)
128a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      ->DispatchEventToExtension(socket->owner_extension_id(), event.Pass());
1294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void CastChannelAPI::OnMessage(const CastSocket* socket,
1324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                               const MessageInfo& message_info) {
133effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
1344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ChannelInfo channel_info;
1350529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  FillChannelInfo(*socket, &channel_info);
1364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  scoped_ptr<base::ListValue> results =
1374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    OnMessage::Create(channel_info, message_info);
138f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  VLOG(1) << "Sending message " << ParamToString(message_info)
139f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          << " to channel " << ParamToString(channel_info);
1404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  scoped_ptr<Event> event(new Event(OnMessage::kEventName, results.Pass()));
1410529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  extensions::EventRouter::Get(browser_context_)
142a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      ->DispatchEventToExtension(socket->owner_extension_id(), event.Pass());
1434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)CastChannelAPI::~CastChannelAPI() {}
1464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)CastChannelAsyncApiFunction::CastChannelAsyncApiFunction()
1488bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  : manager_(NULL), error_(cast_channel::CHANNEL_ERROR_NONE) { }
1494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)CastChannelAsyncApiFunction::~CastChannelAsyncApiFunction() { }
1514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool CastChannelAsyncApiFunction::PrePrepare() {
153a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  manager_ = ApiResourceManager<CastSocket>::Get(browser_context());
1544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return true;
1554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool CastChannelAsyncApiFunction::Respond() {
1584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return error_ != cast_channel::CHANNEL_ERROR_NONE;
1594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1618bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)CastSocket* CastChannelAsyncApiFunction::GetSocketOrCompleteWithError(
1628bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    int channel_id) {
1638bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  CastSocket* socket = GetSocket(channel_id);
1648bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (!socket) {
1655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    SetResultFromError(channel_id,
1665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                       cast_channel::CHANNEL_ERROR_INVALID_CHANNEL_ID);
1678bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    AsyncWorkCompleted();
1684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
1694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return socket;
1704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1728bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)int CastChannelAsyncApiFunction::AddSocket(CastSocket* socket) {
173effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
1748bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  DCHECK(socket);
1758bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  DCHECK(manager_);
1760f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  const int id = manager_->Add(socket);
1770f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  socket->set_id(id);
1780f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  return id;
1794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1818bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void CastChannelAsyncApiFunction::RemoveSocket(int channel_id) {
182effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
1838bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  DCHECK(manager_);
1848bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  manager_->Remove(extension_->id(), channel_id);
1854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void CastChannelAsyncApiFunction::SetResultFromSocket(
1885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const CastSocket& socket) {
1894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ChannelInfo channel_info;
1905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  FillChannelInfo(socket, &channel_info);
1915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  error_ = socket.error_state();
1924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  SetResultFromChannelInfo(channel_info);
1934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void CastChannelAsyncApiFunction::SetResultFromError(int channel_id,
1965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                                     ChannelError error) {
1974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ChannelInfo channel_info;
1985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  channel_info.channel_id = channel_id;
1998bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  channel_info.url = "";
2004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  channel_info.ready_state = cast_channel::READY_STATE_CLOSED;
2014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  channel_info.error_state = error;
2025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  channel_info.connect_info.ip_address = "";
2035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  channel_info.connect_info.port = 0;
2045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  channel_info.connect_info.auth = cast_channel::CHANNEL_AUTH_TYPE_SSL;
2054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  SetResultFromChannelInfo(channel_info);
2064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  error_ = error;
2074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
2084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2098bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)CastSocket* CastChannelAsyncApiFunction::GetSocket(int channel_id) {
210effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
2118bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  DCHECK(manager_);
2128bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  return manager_->Get(extension_->id(), channel_id);
2138bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
2148bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
2158bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void CastChannelAsyncApiFunction::SetResultFromChannelInfo(
2168bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    const ChannelInfo& channel_info) {
217effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
2188bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  SetResult(channel_info.ToValue().release());
2198bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
2208bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
2218bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)CastChannelOpenFunction::CastChannelOpenFunction()
2228bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  : new_channel_id_(0) { }
2234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)CastChannelOpenFunction::~CastChannelOpenFunction() { }
2254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2260529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// TODO(mfoltz): Remove URL parsing when clients have converted to use
2270529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// ConnectInfo.
2280529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
2290529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// Allowed schemes for Cast device URLs.
2300529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochconst char kCastInsecureScheme[] = "cast";
2310529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochconst char kCastSecureScheme[] = "casts";
2320529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
2330529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochbool CastChannelOpenFunction::ParseChannelUrl(const GURL& url,
2340529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                              ConnectInfo* connect_info) {
2350529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DCHECK(connect_info);
2360529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  VLOG(2) << "ParseChannelUrl";
2370529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  bool auth_required = false;
2380529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (url.SchemeIs(kCastSecureScheme)) {
2390529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    auth_required = true;
2400529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  } else if (!url.SchemeIs(kCastInsecureScheme)) {
2410529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return false;
2420529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
2430529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // TODO(mfoltz): Test for IPv6 addresses.  Brackets or no brackets?
2440529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // TODO(mfoltz): Maybe enforce restriction to IPv4 private and IPv6
2450529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // link-local networks
2460529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  const std::string& path = url.path();
2470529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // Shortest possible: //A:B
2480529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (path.size() < 5) {
2490529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return false;
2500529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
2510529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (path.find("//") != 0) {
2520529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return false;
2530529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
2540529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  size_t colon = path.find_last_of(':');
2550529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (colon == std::string::npos || colon < 3 || colon > path.size() - 2) {
2560529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return false;
2570529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
2580529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  const std::string& ip_address_str = path.substr(2, colon - 2);
2590529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  const std::string& port_str = path.substr(colon + 1);
2600529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  VLOG(2) << "IP: " << ip_address_str << " Port: " << port_str;
2610529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  int port;
2620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (!base::StringToInt(port_str, &port))
2630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return false;
2640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  connect_info->ip_address = ip_address_str;
2650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  connect_info->port = port;
2660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  connect_info->auth = auth_required ?
2670529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    cast_channel::CHANNEL_AUTH_TYPE_SSL_VERIFIED :
2680529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    cast_channel::CHANNEL_AUTH_TYPE_SSL;
2690529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return true;
2705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
2710529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
2720529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochnet::IPEndPoint* CastChannelOpenFunction::ParseConnectInfo(
2730529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const ConnectInfo& connect_info) {
2740529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  net::IPAddressNumber ip_address;
2755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  CHECK(net::ParseIPLiteralToNumber(connect_info.ip_address, &ip_address));
2760529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return new net::IPEndPoint(ip_address, connect_info.port);
2770529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
2780529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
2794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool CastChannelOpenFunction::PrePrepare() {
280a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  api_ = CastChannelAPI::Get(browser_context());
2814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return CastChannelAsyncApiFunction::PrePrepare();
2824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
2834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool CastChannelOpenFunction::Prepare() {
2854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  params_ = Open::Params::Create(*args_);
2864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  EXTENSION_FUNCTION_VALIDATE(params_.get());
2870529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // The connect_info parameter may be a string URL like cast:// or casts:// or
2880529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // a ConnectInfo object.
2890529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::string cast_url;
2900529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  switch (params_->connect_info->GetType()) {
2910529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    case base::Value::TYPE_STRING:
2920529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      CHECK(params_->connect_info->GetAsString(&cast_url));
2930529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      connect_info_.reset(new ConnectInfo);
2940529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      if (!ParseChannelUrl(GURL(cast_url), connect_info_.get())) {
2950529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        connect_info_.reset();
2965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        SetError("Invalid connect_info (invalid Cast URL " + cast_url + ")");
2970529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      }
2980529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      break;
2990529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    case base::Value::TYPE_DICTIONARY:
3000529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      connect_info_ = ConnectInfo::FromValue(*(params_->connect_info));
3015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (!connect_info_.get()) {
3025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        SetError("connect_info.auth is required");
3035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      }
3040529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      break;
3050529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    default:
3065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      SetError("Invalid connect_info (unknown type)");
3070529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      break;
3080529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
3095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!connect_info_.get()) {
3105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return false;
3115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
3125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!IsValidConnectInfoPort(*connect_info_)) {
3135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    SetError("Invalid connect_info (invalid port)");
3145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  } else if (!IsValidConnectInfoAuth(*connect_info_)) {
3155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    SetError("Invalid connect_info (invalid auth)");
3165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  } else if (!IsValidConnectInfoIpAddress(*connect_info_)) {
3175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    SetError("Invalid connect_info (invalid IP address)");
3180529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
3195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!GetError().empty()) {
3205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return false;
3215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
3225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  channel_auth_ = connect_info_->auth;
3235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  ip_endpoint_.reset(ParseConnectInfo(*connect_info_));
3245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return true;
3254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
3264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void CastChannelOpenFunction::AsyncWorkStart() {
3284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK(api_);
3290529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DCHECK(ip_endpoint_.get());
3300529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  scoped_ptr<CastSocket> socket = api_->CreateCastSocket(
3315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      extension_->id(),
3325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      *ip_endpoint_,
3335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      channel_auth_,
3345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      base::TimeDelta::FromMilliseconds(connect_info_->timeout.get()
3355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                            ? *connect_info_->timeout
3365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                            : kDefaultConnectTimeoutMillis));
3370f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  new_channel_id_ = AddSocket(socket.release());
3380f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  GetSocket(new_channel_id_)->Connect(
3390f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      base::Bind(&CastChannelOpenFunction::OnOpen, this));
3404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
3414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void CastChannelOpenFunction::OnOpen(int result) {
343effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
3445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  VLOG(1) << "Connect finished, OnOpen invoked.";
3455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  CastSocket* socket = GetSocket(new_channel_id_);
3465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!socket) {
3475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    SetResultFromError(new_channel_id_,
3485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                       cast_channel::CHANNEL_ERROR_CONNECT_ERROR);
3495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  } else {
3505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    SetResultFromSocket(*socket);
3515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
3524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  AsyncWorkCompleted();
3534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
3544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)CastChannelSendFunction::CastChannelSendFunction() { }
3564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)CastChannelSendFunction::~CastChannelSendFunction() { }
3584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool CastChannelSendFunction::Prepare() {
3604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  params_ = Send::Params::Create(*args_);
3614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  EXTENSION_FUNCTION_VALIDATE(params_.get());
3625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (params_->message.namespace_.empty()) {
3635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    SetError("message_info.namespace_ is required");
3645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return false;
3655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
3665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (params_->message.source_id.empty()) {
3675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    SetError("message_info.source_id is required");
3685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return false;
3695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
3705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (params_->message.destination_id.empty()) {
3715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    SetError("message_info.destination_id is required");
3725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return false;
3735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
3745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  switch (params_->message.data->GetType()) {
3755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    case base::Value::TYPE_STRING:
3765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    case base::Value::TYPE_BINARY:
3775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      break;
3785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    default:
3795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      SetError("Invalid type of message_info.data");
3805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return false;
3815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
3824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return true;
3834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
3844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void CastChannelSendFunction::AsyncWorkStart() {
3868bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  CastSocket* socket = GetSocketOrCompleteWithError(
3878bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      params_->channel.channel_id);
3888bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (socket)
3898bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    socket->SendMessage(params_->message,
3908bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                        base::Bind(&CastChannelSendFunction::OnSend, this));
3914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
3924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void CastChannelSendFunction::OnSend(int result) {
394effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
3955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int channel_id = params_->channel.channel_id;
3965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  CastSocket* socket = GetSocket(channel_id);
3975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (result < 0 || !socket) {
3985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    SetResultFromError(channel_id,
3995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                       cast_channel::CHANNEL_ERROR_SOCKET_ERROR);
4004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  } else {
4015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    SetResultFromSocket(*socket);
4024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
4034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  AsyncWorkCompleted();
4044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
4054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)CastChannelCloseFunction::CastChannelCloseFunction() { }
4074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)CastChannelCloseFunction::~CastChannelCloseFunction() { }
4094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool CastChannelCloseFunction::Prepare() {
4114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  params_ = Close::Params::Create(*args_);
4124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  EXTENSION_FUNCTION_VALIDATE(params_.get());
4134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return true;
4144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
4154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void CastChannelCloseFunction::AsyncWorkStart() {
4178bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  CastSocket* socket = GetSocketOrCompleteWithError(
4188bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      params_->channel.channel_id);
4198bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (socket)
4208bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    socket->Close(base::Bind(&CastChannelCloseFunction::OnClose, this));
4214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
4224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void CastChannelCloseFunction::OnClose(int result) {
424effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
425f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  VLOG(1) << "CastChannelCloseFunction::OnClose result = " << result;
4265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int channel_id = params_->channel.channel_id;
4275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  CastSocket* socket = GetSocket(channel_id);
4285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (result < 0 || !socket) {
4295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    SetResultFromError(channel_id,
4305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                       cast_channel::CHANNEL_ERROR_SOCKET_ERROR);
4314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  } else {
4325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    SetResultFromSocket(*socket);
4335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // This will delete |socket|.
4348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    RemoveSocket(channel_id);
4355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    socket = NULL;
4364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
4374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  AsyncWorkCompleted();
4384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
4394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}  // namespace extensions
441