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"
111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/lazy_instance.h"
120f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
130529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "base/strings/string_number_conversions.h"
146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/time/default_tick_clock.h"
154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/values.h"
164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "content/public/browser/browser_thread.h"
175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "extensions/browser/api/cast_channel/cast_socket.h"
186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "extensions/browser/api/cast_channel/logger.h"
19f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/browser/event_router.h"
201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "extensions/common/api/cast_channel/logging.pb.h"
210529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "net/base/ip_endpoint.h"
224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "net/base/net_errors.h"
230529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "net/base/net_util.h"
244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "url/gurl.h"
254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Default timeout interval for connection setup.
275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Used if not otherwise specified at ConnectInfo::timeout.
285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)const int kDefaultConnectTimeoutMillis = 5000;  // 5 seconds.
295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace extensions {
314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace Close = cast_channel::Close;
334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace OnError = cast_channel::OnError;
344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace OnMessage = cast_channel::OnMessage;
354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace Open = cast_channel::Open;
364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace Send = cast_channel::Send;
374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)using cast_channel::CastSocket;
380529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochusing cast_channel::ChannelAuthType;
394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)using cast_channel::ChannelError;
404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)using cast_channel::ChannelInfo;
410529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochusing cast_channel::ConnectInfo;
426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)using cast_channel::ErrorInfo;
436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)using cast_channel::LastErrors;
446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)using cast_channel::Logger;
454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)using cast_channel::MessageInfo;
464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)using cast_channel::ReadyState;
474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)using content::BrowserThread;
484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace {
508bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
518bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// T is an extension dictionary (MessageInfo or ChannelInfo)
528bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)template <class T>
538bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)std::string ParamToString(const T& info) {
548bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  scoped_ptr<base::DictionaryValue> dict = info.ToValue();
558bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  std::string out;
568bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  base::JSONWriter::Write(dict.get(), &out);
578bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  return out;
588bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
598bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
600529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// Fills |channel_info| from the destination and state of |socket|.
610529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid FillChannelInfo(const CastSocket& socket, ChannelInfo* channel_info) {
620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DCHECK(channel_info);
630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  channel_info->channel_id = socket.id();
640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  channel_info->url = socket.CastUrl();
650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  const net::IPEndPoint& ip_endpoint = socket.ip_endpoint();
660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  channel_info->connect_info.ip_address = ip_endpoint.ToStringWithoutPort();
670529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  channel_info->connect_info.port = ip_endpoint.port();
680529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  channel_info->connect_info.auth = socket.channel_auth();
690529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  channel_info->ready_state = socket.ready_state();
700529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  channel_info->error_state = socket.error_state();
710529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
720529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// Fills |error_info| from |error_state| and |last_errors|.
746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void FillErrorInfo(ChannelError error_state,
756e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                   const LastErrors& last_errors,
766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                   ErrorInfo* error_info) {
776e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  error_info->error_state = error_state;
786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (last_errors.event_type != cast_channel::proto::EVENT_TYPE_UNKNOWN)
796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    error_info->event_type.reset(new int(last_errors.event_type));
806e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (last_errors.challenge_reply_error_type !=
816e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      cast_channel::proto::CHALLENGE_REPLY_ERROR_NONE) {
826e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    error_info->challenge_reply_error_type.reset(
836e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        new int(last_errors.challenge_reply_error_type));
846e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (last_errors.net_return_value <= 0)
866e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    error_info->net_return_value.reset(new int(last_errors.net_return_value));
876e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (last_errors.nss_error_code < 0)
886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    error_info->nss_error_code.reset(new int(last_errors.nss_error_code));
896e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
906e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool IsValidConnectInfoPort(const ConnectInfo& connect_info) {
925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return connect_info.port > 0 && connect_info.port <
935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    std::numeric_limits<uint16_t>::max();
945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool IsValidConnectInfoAuth(const ConnectInfo& connect_info) {
975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return connect_info.auth == cast_channel::CHANNEL_AUTH_TYPE_SSL_VERIFIED ||
985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    connect_info.auth == cast_channel::CHANNEL_AUTH_TYPE_SSL;
995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool IsValidConnectInfoIpAddress(const ConnectInfo& connect_info) {
1025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  net::IPAddressNumber ip_address;
1035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return net::ParseIPLiteralToNumber(connect_info.ip_address, &ip_address);
1045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}  // namespace
1074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
108a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)CastChannelAPI::CastChannelAPI(content::BrowserContext* context)
1096e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    : browser_context_(context),
1106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      logger_(
1116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          new Logger(scoped_ptr<base::TickClock>(new base::DefaultTickClock),
1126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                     base::TimeTicks::UnixEpoch())) {
113a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(browser_context_);
1144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// static
117a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)CastChannelAPI* CastChannelAPI::Get(content::BrowserContext* context) {
118a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return BrowserContextKeyedAPIFactory<CastChannelAPI>::Get(context);
1194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)scoped_refptr<Logger> CastChannelAPI::GetLogger() {
1226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  return logger_;
1236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
1246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
125a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)static base::LazyInstance<BrowserContextKeyedAPIFactory<CastChannelAPI> >
126a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    g_factory = LAZY_INSTANCE_INITIALIZER;
1274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// static
129a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)BrowserContextKeyedAPIFactory<CastChannelAPI>*
130a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)CastChannelAPI::GetFactoryInstance() {
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return g_factory.Pointer();
1324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1340f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)void CastChannelAPI::SetSocketForTest(scoped_ptr<CastSocket> socket_for_test) {
1350f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  socket_for_test_ = socket_for_test.Pass();
1360f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
1370f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
1381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciscoped_ptr<cast_channel::CastSocket> CastChannelAPI::GetSocketForTest() {
1391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return socket_for_test_.Pass();
1401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void CastChannelAPI::OnError(const CastSocket* socket,
1436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                             cast_channel::ChannelError error_state,
1446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                             const cast_channel::LastErrors& last_errors) {
145effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
1464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ChannelInfo channel_info;
1470529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  FillChannelInfo(*socket, &channel_info);
1486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  channel_info.error_state = error_state;
1496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  ErrorInfo error_info;
1506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  FillErrorInfo(error_state, last_errors, &error_info);
1516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  scoped_ptr<base::ListValue> results =
1526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      OnError::Create(channel_info, error_info);
1534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  scoped_ptr<Event> event(new Event(OnError::kEventName, results.Pass()));
1540529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  extensions::EventRouter::Get(browser_context_)
155a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      ->DispatchEventToExtension(socket->owner_extension_id(), event.Pass());
1564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void CastChannelAPI::OnMessage(const CastSocket* socket,
1594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                               const MessageInfo& message_info) {
160effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
1614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ChannelInfo channel_info;
1620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  FillChannelInfo(*socket, &channel_info);
1634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  scoped_ptr<base::ListValue> results =
1644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    OnMessage::Create(channel_info, message_info);
165f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  VLOG(1) << "Sending message " << ParamToString(message_info)
166f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          << " to channel " << ParamToString(channel_info);
1674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  scoped_ptr<Event> event(new Event(OnMessage::kEventName, results.Pass()));
1680529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  extensions::EventRouter::Get(browser_context_)
169a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      ->DispatchEventToExtension(socket->owner_extension_id(), event.Pass());
1704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)CastChannelAPI::~CastChannelAPI() {}
1734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)CastChannelAsyncApiFunction::CastChannelAsyncApiFunction()
1758bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  : manager_(NULL), error_(cast_channel::CHANNEL_ERROR_NONE) { }
1764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)CastChannelAsyncApiFunction::~CastChannelAsyncApiFunction() { }
1784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool CastChannelAsyncApiFunction::PrePrepare() {
180a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  manager_ = ApiResourceManager<CastSocket>::Get(browser_context());
1814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return true;
1824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool CastChannelAsyncApiFunction::Respond() {
18503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return error_ == cast_channel::CHANNEL_ERROR_NONE;
1864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1888bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)CastSocket* CastChannelAsyncApiFunction::GetSocketOrCompleteWithError(
1898bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    int channel_id) {
1908bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  CastSocket* socket = GetSocket(channel_id);
1918bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (!socket) {
1925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    SetResultFromError(channel_id,
1935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                       cast_channel::CHANNEL_ERROR_INVALID_CHANNEL_ID);
1948bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    AsyncWorkCompleted();
1954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
1964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return socket;
1974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1998bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)int CastChannelAsyncApiFunction::AddSocket(CastSocket* socket) {
200effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
2018bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  DCHECK(socket);
2028bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  DCHECK(manager_);
2030f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  const int id = manager_->Add(socket);
2040f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  socket->set_id(id);
2050f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  return id;
2064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
2074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2088bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void CastChannelAsyncApiFunction::RemoveSocket(int channel_id) {
209effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
2108bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  DCHECK(manager_);
2118bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  manager_->Remove(extension_->id(), channel_id);
2124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
2134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void CastChannelAsyncApiFunction::SetResultFromSocket(
2155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const CastSocket& socket) {
2164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ChannelInfo channel_info;
2175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  FillChannelInfo(socket, &channel_info);
2185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  error_ = socket.error_state();
2194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  SetResultFromChannelInfo(channel_info);
2204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
2214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void CastChannelAsyncApiFunction::SetResultFromError(int channel_id,
2235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                                     ChannelError error) {
2244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ChannelInfo channel_info;
2255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  channel_info.channel_id = channel_id;
2268bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  channel_info.url = "";
2274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  channel_info.ready_state = cast_channel::READY_STATE_CLOSED;
2284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  channel_info.error_state = error;
2295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  channel_info.connect_info.ip_address = "";
2305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  channel_info.connect_info.port = 0;
2315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  channel_info.connect_info.auth = cast_channel::CHANNEL_AUTH_TYPE_SSL;
2324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  SetResultFromChannelInfo(channel_info);
2334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  error_ = error;
2344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
2354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2368bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)CastSocket* CastChannelAsyncApiFunction::GetSocket(int channel_id) {
237effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
2388bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  DCHECK(manager_);
2398bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  return manager_->Get(extension_->id(), channel_id);
2408bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
2418bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
2428bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void CastChannelAsyncApiFunction::SetResultFromChannelInfo(
2438bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    const ChannelInfo& channel_info) {
244effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
2458bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  SetResult(channel_info.ToValue().release());
2468bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
2478bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
2488bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)CastChannelOpenFunction::CastChannelOpenFunction()
2498bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  : new_channel_id_(0) { }
2504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)CastChannelOpenFunction::~CastChannelOpenFunction() { }
2524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2530529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// TODO(mfoltz): Remove URL parsing when clients have converted to use
2540529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// ConnectInfo.
2550529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
2560529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// Allowed schemes for Cast device URLs.
2570529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochconst char kCastInsecureScheme[] = "cast";
2580529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochconst char kCastSecureScheme[] = "casts";
2590529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
2600529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochbool CastChannelOpenFunction::ParseChannelUrl(const GURL& url,
2610529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                              ConnectInfo* connect_info) {
2620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DCHECK(connect_info);
2630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  VLOG(2) << "ParseChannelUrl";
2640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  bool auth_required = false;
2650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (url.SchemeIs(kCastSecureScheme)) {
2660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    auth_required = true;
2670529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  } else if (!url.SchemeIs(kCastInsecureScheme)) {
2680529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return false;
2690529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
2700529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // TODO(mfoltz): Test for IPv6 addresses.  Brackets or no brackets?
2710529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // TODO(mfoltz): Maybe enforce restriction to IPv4 private and IPv6
2720529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // link-local networks
2730529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  const std::string& path = url.path();
2740529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // Shortest possible: //A:B
2750529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (path.size() < 5) {
2760529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return false;
2770529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
2780529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (path.find("//") != 0) {
2790529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return false;
2800529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
2810529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  size_t colon = path.find_last_of(':');
2820529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (colon == std::string::npos || colon < 3 || colon > path.size() - 2) {
2830529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return false;
2840529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
2850529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  const std::string& ip_address_str = path.substr(2, colon - 2);
2860529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  const std::string& port_str = path.substr(colon + 1);
2870529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  VLOG(2) << "IP: " << ip_address_str << " Port: " << port_str;
2880529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  int port;
2890529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (!base::StringToInt(port_str, &port))
2900529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return false;
2910529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  connect_info->ip_address = ip_address_str;
2920529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  connect_info->port = port;
2930529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  connect_info->auth = auth_required ?
2940529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    cast_channel::CHANNEL_AUTH_TYPE_SSL_VERIFIED :
2950529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    cast_channel::CHANNEL_AUTH_TYPE_SSL;
2960529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return true;
2975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
2980529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
2990529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochnet::IPEndPoint* CastChannelOpenFunction::ParseConnectInfo(
3000529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const ConnectInfo& connect_info) {
3010529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  net::IPAddressNumber ip_address;
3025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  CHECK(net::ParseIPLiteralToNumber(connect_info.ip_address, &ip_address));
3030529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return new net::IPEndPoint(ip_address, connect_info.port);
3040529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
3050529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
3064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool CastChannelOpenFunction::PrePrepare() {
307a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  api_ = CastChannelAPI::Get(browser_context());
3084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return CastChannelAsyncApiFunction::PrePrepare();
3094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
3104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool CastChannelOpenFunction::Prepare() {
3124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  params_ = Open::Params::Create(*args_);
3134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  EXTENSION_FUNCTION_VALIDATE(params_.get());
3140529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // The connect_info parameter may be a string URL like cast:// or casts:// or
3150529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // a ConnectInfo object.
3160529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::string cast_url;
3170529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  switch (params_->connect_info->GetType()) {
3180529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    case base::Value::TYPE_STRING:
3190529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      CHECK(params_->connect_info->GetAsString(&cast_url));
3200529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      connect_info_.reset(new ConnectInfo);
3210529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      if (!ParseChannelUrl(GURL(cast_url), connect_info_.get())) {
3220529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        connect_info_.reset();
3235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        SetError("Invalid connect_info (invalid Cast URL " + cast_url + ")");
3240529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      }
3250529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      break;
3260529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    case base::Value::TYPE_DICTIONARY:
3270529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      connect_info_ = ConnectInfo::FromValue(*(params_->connect_info));
3285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (!connect_info_.get()) {
3295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        SetError("connect_info.auth is required");
3305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      }
3310529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      break;
3320529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    default:
3335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      SetError("Invalid connect_info (unknown type)");
3340529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      break;
3350529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
3365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!connect_info_.get()) {
3375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return false;
3385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
3395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!IsValidConnectInfoPort(*connect_info_)) {
3405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    SetError("Invalid connect_info (invalid port)");
3415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  } else if (!IsValidConnectInfoAuth(*connect_info_)) {
3425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    SetError("Invalid connect_info (invalid auth)");
3435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  } else if (!IsValidConnectInfoIpAddress(*connect_info_)) {
3445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    SetError("Invalid connect_info (invalid IP address)");
3450529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
3465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!GetError().empty()) {
3475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return false;
3485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
3495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  channel_auth_ = connect_info_->auth;
3505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  ip_endpoint_.reset(ParseConnectInfo(*connect_info_));
3515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return true;
3524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
3534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void CastChannelOpenFunction::AsyncWorkStart() {
3554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK(api_);
3560529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DCHECK(ip_endpoint_.get());
3571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  scoped_ptr<CastSocket> socket = api_->GetSocketForTest();
3581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!socket.get()) {
3591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    socket.reset(new CastSocket(
3601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        extension_->id(),
3611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        *ip_endpoint_,
3621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        channel_auth_,
3631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        api_,
3641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        ExtensionsBrowserClient::Get()->GetNetLog(),
3651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        base::TimeDelta::FromMilliseconds(connect_info_->timeout.get()
3661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                              ? *connect_info_->timeout
3671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                              : kDefaultConnectTimeoutMillis),
3681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        api_->GetLogger()));
3691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
3700f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  new_channel_id_ = AddSocket(socket.release());
3716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  CastSocket* new_socket = GetSocket(new_channel_id_);
3726e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  api_->GetLogger()->LogNewSocketEvent(*new_socket);
3736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  new_socket->Connect(base::Bind(&CastChannelOpenFunction::OnOpen, this));
3744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
3754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void CastChannelOpenFunction::OnOpen(int result) {
377effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
3785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  VLOG(1) << "Connect finished, OnOpen invoked.";
3795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  CastSocket* socket = GetSocket(new_channel_id_);
3805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!socket) {
3815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    SetResultFromError(new_channel_id_,
3825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                       cast_channel::CHANNEL_ERROR_CONNECT_ERROR);
3835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  } else {
3845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    SetResultFromSocket(*socket);
3855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
3864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  AsyncWorkCompleted();
3874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
3884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)CastChannelSendFunction::CastChannelSendFunction() { }
3904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)CastChannelSendFunction::~CastChannelSendFunction() { }
3924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool CastChannelSendFunction::Prepare() {
3944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  params_ = Send::Params::Create(*args_);
3954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  EXTENSION_FUNCTION_VALIDATE(params_.get());
3965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (params_->message.namespace_.empty()) {
3975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    SetError("message_info.namespace_ is required");
3985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return false;
3995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
4005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (params_->message.source_id.empty()) {
4015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    SetError("message_info.source_id is required");
4025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return false;
4035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
4045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (params_->message.destination_id.empty()) {
4055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    SetError("message_info.destination_id is required");
4065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return false;
4075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
4085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  switch (params_->message.data->GetType()) {
4095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    case base::Value::TYPE_STRING:
4105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    case base::Value::TYPE_BINARY:
4115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      break;
4125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    default:
4135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      SetError("Invalid type of message_info.data");
4145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return false;
4155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
4164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return true;
4174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
4184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void CastChannelSendFunction::AsyncWorkStart() {
4201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  CastSocket* socket = GetSocket(params_->channel.channel_id);
4211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!socket) {
4221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    SetResultFromError(params_->channel.channel_id,
4231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                       cast_channel::CHANNEL_ERROR_INVALID_CHANNEL_ID);
4241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    AsyncWorkCompleted();
4251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
4261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
4271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  socket->SendMessage(params_->message,
4281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                      base::Bind(&CastChannelSendFunction::OnSend, this));
4294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
4304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void CastChannelSendFunction::OnSend(int result) {
432effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
4335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int channel_id = params_->channel.channel_id;
4345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  CastSocket* socket = GetSocket(channel_id);
4355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (result < 0 || !socket) {
4365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    SetResultFromError(channel_id,
4375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                       cast_channel::CHANNEL_ERROR_SOCKET_ERROR);
4384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  } else {
4395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    SetResultFromSocket(*socket);
4404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
4414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  AsyncWorkCompleted();
4424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
4434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)CastChannelCloseFunction::CastChannelCloseFunction() { }
4454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)CastChannelCloseFunction::~CastChannelCloseFunction() { }
4474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool CastChannelCloseFunction::Prepare() {
4494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  params_ = Close::Params::Create(*args_);
4504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  EXTENSION_FUNCTION_VALIDATE(params_.get());
4514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return true;
4524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
4534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void CastChannelCloseFunction::AsyncWorkStart() {
4551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  CastSocket* socket = GetSocket(params_->channel.channel_id);
4561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!socket) {
4571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    SetResultFromError(params_->channel.channel_id,
4581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                       cast_channel::CHANNEL_ERROR_INVALID_CHANNEL_ID);
4591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    AsyncWorkCompleted();
4601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  } else {
4618bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    socket->Close(base::Bind(&CastChannelCloseFunction::OnClose, this));
4621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
4634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
4644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void CastChannelCloseFunction::OnClose(int result) {
466effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
467f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  VLOG(1) << "CastChannelCloseFunction::OnClose result = " << result;
4685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int channel_id = params_->channel.channel_id;
4695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  CastSocket* socket = GetSocket(channel_id);
4705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (result < 0 || !socket) {
4715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    SetResultFromError(channel_id,
4725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                       cast_channel::CHANNEL_ERROR_SOCKET_ERROR);
4734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  } else {
4745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    SetResultFromSocket(*socket);
4755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // This will delete |socket|.
4768bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    RemoveSocket(channel_id);
4775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    socket = NULL;
4784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
4794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  AsyncWorkCompleted();
4804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
4814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4826e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)CastChannelGetLogsFunction::CastChannelGetLogsFunction() {
4836e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
4846e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
4856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)CastChannelGetLogsFunction::~CastChannelGetLogsFunction() {
4866e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
4876e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
4886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)bool CastChannelGetLogsFunction::PrePrepare() {
4896e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  api_ = CastChannelAPI::Get(browser_context());
4906e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  return CastChannelAsyncApiFunction::PrePrepare();
4916e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
4926e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
4936e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)bool CastChannelGetLogsFunction::Prepare() {
4946e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  return true;
4956e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
4966e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
4976e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void CastChannelGetLogsFunction::AsyncWorkStart() {
4986e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  DCHECK(api_);
4996e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
5006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  size_t length = 0;
5016e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  scoped_ptr<char[]> out = api_->GetLogger()->GetLogs(&length);
5026e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (out.get()) {
5036e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    SetResult(new base::BinaryValue(out.Pass(), length));
5046e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  } else {
5056e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    SetError("Unable to get logs.");
5066e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
5076e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
5086e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  api_->GetLogger()->Reset();
5096e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
5106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  AsyncWorkCompleted();
5116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
5126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
5134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}  // namespace extensions
514