Roll src/third_party/WebKit a26a5b9:5fc303f (svn 199161:199164)
[chromium-blink-merge.git] / extensions / browser / api / cast_channel / cast_channel_api.cc
blob3ec0b63bd665d620c846fc1609484e5c42c0b6d8
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "extensions/browser/api/cast_channel/cast_channel_api.h"
7 #include <limits>
8 #include <string>
10 #include "base/json/json_writer.h"
11 #include "base/lazy_instance.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/time/default_tick_clock.h"
15 #include "base/values.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "extensions/browser/api/cast_channel/cast_auth_ica.h"
18 #include "extensions/browser/api/cast_channel/cast_message_util.h"
19 #include "extensions/browser/api/cast_channel/cast_socket.h"
20 #include "extensions/browser/api/cast_channel/keep_alive_delegate.h"
21 #include "extensions/browser/api/cast_channel/logger.h"
22 #include "extensions/browser/event_router.h"
23 #include "extensions/common/api/cast_channel/cast_channel.pb.h"
24 #include "extensions/common/api/cast_channel/logging.pb.h"
25 #include "net/base/ip_endpoint.h"
26 #include "net/base/net_errors.h"
27 #include "net/base/net_util.h"
29 // Default timeout interval for connection setup.
30 // Used if not otherwise specified at ConnectInfo::timeout.
31 const int kDefaultConnectTimeoutMillis = 5000; // 5 seconds.
33 namespace extensions {
35 namespace Close = cast_channel::Close;
36 namespace OnError = cast_channel::OnError;
37 namespace OnMessage = cast_channel::OnMessage;
38 namespace Open = cast_channel::Open;
39 namespace Send = cast_channel::Send;
40 using cast_channel::CastDeviceCapability;
41 using cast_channel::CastMessage;
42 using cast_channel::CastSocket;
43 using cast_channel::ChannelAuthType;
44 using cast_channel::ChannelError;
45 using cast_channel::ChannelInfo;
46 using cast_channel::ConnectInfo;
47 using cast_channel::ErrorInfo;
48 using cast_channel::LastErrors;
49 using cast_channel::Logger;
50 using cast_channel::MessageInfo;
51 using cast_channel::ReadyState;
52 using content::BrowserThread;
54 namespace {
56 // T is an extension dictionary (MessageInfo or ChannelInfo)
57 template <class T>
58 std::string ParamToString(const T& info) {
59 scoped_ptr<base::DictionaryValue> dict = info.ToValue();
60 std::string out;
61 base::JSONWriter::Write(*dict, &out);
62 return out;
65 // Fills |channel_info| from the destination and state of |socket|.
66 void FillChannelInfo(const CastSocket& socket, ChannelInfo* channel_info) {
67 DCHECK(channel_info);
68 channel_info->channel_id = socket.id();
69 const net::IPEndPoint& ip_endpoint = socket.ip_endpoint();
70 channel_info->connect_info.ip_address = ip_endpoint.ToStringWithoutPort();
71 channel_info->connect_info.port = ip_endpoint.port();
72 channel_info->connect_info.auth = socket.channel_auth();
73 channel_info->ready_state = socket.ready_state();
74 channel_info->error_state = socket.error_state();
75 channel_info->keep_alive = socket.keep_alive();
78 // Fills |error_info| from |error_state| and |last_errors|.
79 void FillErrorInfo(ChannelError error_state,
80 const LastErrors& last_errors,
81 ErrorInfo* error_info) {
82 error_info->error_state = error_state;
83 if (last_errors.event_type != cast_channel::proto::EVENT_TYPE_UNKNOWN)
84 error_info->event_type.reset(new int(last_errors.event_type));
85 if (last_errors.challenge_reply_error_type !=
86 cast_channel::proto::CHALLENGE_REPLY_ERROR_NONE) {
87 error_info->challenge_reply_error_type.reset(
88 new int(last_errors.challenge_reply_error_type));
90 if (last_errors.net_return_value <= 0)
91 error_info->net_return_value.reset(new int(last_errors.net_return_value));
92 if (last_errors.nss_error_code < 0)
93 error_info->nss_error_code.reset(new int(last_errors.nss_error_code));
96 bool IsValidConnectInfoPort(const ConnectInfo& connect_info) {
97 return connect_info.port > 0 && connect_info.port <
98 std::numeric_limits<uint16_t>::max();
101 bool IsValidConnectInfoIpAddress(const ConnectInfo& connect_info) {
102 net::IPAddressNumber ip_address;
103 return net::ParseIPLiteralToNumber(connect_info.ip_address, &ip_address);
106 } // namespace
108 CastChannelAPI::CastChannelAPI(content::BrowserContext* context)
109 : browser_context_(context),
110 logger_(
111 new Logger(scoped_ptr<base::TickClock>(new base::DefaultTickClock),
112 base::TimeTicks::UnixEpoch())) {
113 DCHECK(browser_context_);
116 // static
117 CastChannelAPI* CastChannelAPI::Get(content::BrowserContext* context) {
118 return BrowserContextKeyedAPIFactory<CastChannelAPI>::Get(context);
121 scoped_refptr<Logger> CastChannelAPI::GetLogger() {
122 return logger_;
125 void CastChannelAPI::SendEvent(const std::string& extension_id,
126 scoped_ptr<Event> event) {
127 DCHECK_CURRENTLY_ON(BrowserThread::UI);
128 EventRouter* event_router = EventRouter::Get(GetBrowserContext());
129 if (event_router) {
130 event_router->DispatchEventToExtension(extension_id, event.Pass());
134 static base::LazyInstance<BrowserContextKeyedAPIFactory<CastChannelAPI> >
135 g_factory = LAZY_INSTANCE_INITIALIZER;
137 // static
138 BrowserContextKeyedAPIFactory<CastChannelAPI>*
139 CastChannelAPI::GetFactoryInstance() {
140 return g_factory.Pointer();
143 void CastChannelAPI::SetSocketForTest(scoped_ptr<CastSocket> socket_for_test) {
144 socket_for_test_ = socket_for_test.Pass();
147 scoped_ptr<CastSocket> CastChannelAPI::GetSocketForTest() {
148 return socket_for_test_.Pass();
151 content::BrowserContext* CastChannelAPI::GetBrowserContext() const {
152 return browser_context_;
155 void CastChannelAPI::SetPingTimeoutTimerForTest(scoped_ptr<base::Timer> timer) {
156 injected_timeout_timer_ = timer.Pass();
159 scoped_ptr<base::Timer> CastChannelAPI::GetInjectedTimeoutTimerForTest() {
160 return injected_timeout_timer_.Pass();
163 CastChannelAPI::~CastChannelAPI() {}
165 CastChannelAsyncApiFunction::CastChannelAsyncApiFunction() : manager_(nullptr) {
168 CastChannelAsyncApiFunction::~CastChannelAsyncApiFunction() { }
170 bool CastChannelAsyncApiFunction::PrePrepare() {
171 manager_ = ApiResourceManager<CastSocket>::Get(browser_context());
172 return true;
175 bool CastChannelAsyncApiFunction::Respond() {
176 return GetError().empty();
179 CastSocket* CastChannelAsyncApiFunction::GetSocketOrCompleteWithError(
180 int channel_id) {
181 CastSocket* socket = GetSocket(channel_id);
182 if (!socket) {
183 SetResultFromError(channel_id,
184 cast_channel::CHANNEL_ERROR_INVALID_CHANNEL_ID);
185 AsyncWorkCompleted();
187 return socket;
190 int CastChannelAsyncApiFunction::AddSocket(CastSocket* socket) {
191 DCHECK_CURRENTLY_ON(BrowserThread::IO);
192 DCHECK(socket);
193 DCHECK(manager_);
194 const int id = manager_->Add(socket);
195 socket->set_id(id);
196 return id;
199 void CastChannelAsyncApiFunction::RemoveSocket(int channel_id) {
200 DCHECK_CURRENTLY_ON(BrowserThread::IO);
201 DCHECK(manager_);
202 manager_->Remove(extension_->id(), channel_id);
205 void CastChannelAsyncApiFunction::SetResultFromSocket(
206 const CastSocket& socket) {
207 ChannelInfo channel_info;
208 FillChannelInfo(socket, &channel_info);
209 ChannelError error = socket.error_state();
210 if (error != cast_channel::CHANNEL_ERROR_NONE) {
211 SetError("Channel socket error = " + base::IntToString(error));
213 SetResultFromChannelInfo(channel_info);
216 void CastChannelAsyncApiFunction::SetResultFromError(int channel_id,
217 ChannelError error) {
218 ChannelInfo channel_info;
219 channel_info.channel_id = channel_id;
220 channel_info.ready_state = cast_channel::READY_STATE_CLOSED;
221 channel_info.error_state = error;
222 channel_info.connect_info.ip_address = "";
223 channel_info.connect_info.port = 0;
224 channel_info.connect_info.auth = cast_channel::CHANNEL_AUTH_TYPE_SSL;
225 SetResultFromChannelInfo(channel_info);
226 SetError("Channel error = " + base::IntToString(error));
229 CastSocket* CastChannelAsyncApiFunction::GetSocket(int channel_id) const {
230 DCHECK_CURRENTLY_ON(BrowserThread::IO);
231 DCHECK(manager_);
232 return manager_->Get(extension_->id(), channel_id);
235 void CastChannelAsyncApiFunction::SetResultFromChannelInfo(
236 const ChannelInfo& channel_info) {
237 DCHECK_CURRENTLY_ON(BrowserThread::IO);
238 SetResult(channel_info.ToValue().release());
241 CastChannelOpenFunction::CastChannelOpenFunction()
242 : new_channel_id_(0) {
245 CastChannelOpenFunction::~CastChannelOpenFunction() { }
247 net::IPEndPoint* CastChannelOpenFunction::ParseConnectInfo(
248 const ConnectInfo& connect_info) {
249 net::IPAddressNumber ip_address;
250 CHECK(net::ParseIPLiteralToNumber(connect_info.ip_address, &ip_address));
251 return new net::IPEndPoint(ip_address,
252 static_cast<uint16>(connect_info.port));
255 bool CastChannelOpenFunction::PrePrepare() {
256 api_ = CastChannelAPI::Get(browser_context());
257 return CastChannelAsyncApiFunction::PrePrepare();
260 bool CastChannelOpenFunction::Prepare() {
261 params_ = Open::Params::Create(*args_);
262 EXTENSION_FUNCTION_VALIDATE(params_.get());
263 const ConnectInfo& connect_info = params_->connect_info;
264 if (!IsValidConnectInfoPort(connect_info)) {
265 SetError("Invalid connect_info (invalid port)");
266 } else if (!IsValidConnectInfoIpAddress(connect_info)) {
267 SetError("Invalid connect_info (invalid IP address)");
268 } else {
269 // Parse timeout parameters if they are set.
270 if (connect_info.liveness_timeout.get()) {
271 liveness_timeout_ = base::TimeDelta::FromMilliseconds(
272 *connect_info.liveness_timeout.get());
274 if (connect_info.ping_interval.get()) {
275 ping_interval_ =
276 base::TimeDelta::FromMilliseconds(*connect_info.ping_interval.get());
279 // Validate timeout parameters.
280 if (liveness_timeout_ < base::TimeDelta() ||
281 ping_interval_ < base::TimeDelta()) {
282 SetError("livenessTimeout and pingInterval must be greater than 0.");
283 } else if ((liveness_timeout_ > base::TimeDelta()) !=
284 (ping_interval_ > base::TimeDelta())) {
285 SetError("livenessTimeout and pingInterval must be set together.");
286 } else if (liveness_timeout_ < ping_interval_) {
287 SetError("livenessTimeout must be longer than pingTimeout.");
291 if (!GetError().empty()) {
292 return false;
295 channel_auth_ = connect_info.auth;
296 ip_endpoint_.reset(ParseConnectInfo(connect_info));
297 return true;
300 void CastChannelOpenFunction::AsyncWorkStart() {
301 DCHECK(api_);
302 DCHECK(ip_endpoint_.get());
303 const ConnectInfo& connect_info = params_->connect_info;
304 CastSocket* socket;
305 scoped_ptr<CastSocket> test_socket = api_->GetSocketForTest();
306 if (test_socket.get()) {
307 socket = test_socket.release();
308 } else {
309 socket = new cast_channel::CastSocketImpl(
310 extension_->id(), *ip_endpoint_, channel_auth_,
311 ExtensionsBrowserClient::Get()->GetNetLog(),
312 base::TimeDelta::FromMilliseconds(connect_info.timeout.get()
313 ? *connect_info.timeout.get()
314 : kDefaultConnectTimeoutMillis),
315 liveness_timeout_ > base::TimeDelta(), api_->GetLogger(),
316 connect_info.capabilities.get() ? *connect_info.capabilities.get()
317 : CastDeviceCapability::NONE);
319 new_channel_id_ = AddSocket(socket);
320 api_->GetLogger()->LogNewSocketEvent(*socket);
322 // Construct read delegates.
323 scoped_ptr<core_api::cast_channel::CastTransport::Delegate> delegate(
324 make_scoped_ptr(new CastMessageHandler(
325 base::Bind(&CastChannelAPI::SendEvent, api_->AsWeakPtr()), socket,
326 api_->GetLogger())));
327 if (socket->keep_alive()) {
328 // Wrap read delegate in a KeepAliveDelegate for timeout handling.
329 core_api::cast_channel::KeepAliveDelegate* keep_alive =
330 new core_api::cast_channel::KeepAliveDelegate(
331 socket, api_->GetLogger(), delegate.Pass(), ping_interval_,
332 liveness_timeout_);
333 scoped_ptr<base::Timer> injected_timer =
334 api_->GetInjectedTimeoutTimerForTest();
335 if (injected_timer) {
336 keep_alive->SetTimersForTest(
337 make_scoped_ptr(new base::Timer(false, false)),
338 injected_timer.Pass());
340 delegate.reset(keep_alive);
343 api_->GetLogger()->LogNewSocketEvent(*socket);
344 socket->Connect(delegate.Pass(),
345 base::Bind(&CastChannelOpenFunction::OnOpen, this));
348 void CastChannelOpenFunction::OnOpen(cast_channel::ChannelError result) {
349 DCHECK_CURRENTLY_ON(BrowserThread::IO);
350 VLOG(1) << "Connect finished, OnOpen invoked.";
351 CastSocket* socket = GetSocket(new_channel_id_);
352 if (!socket) {
353 SetResultFromError(new_channel_id_, result);
354 } else {
355 SetResultFromSocket(*socket);
357 AsyncWorkCompleted();
360 CastChannelSendFunction::CastChannelSendFunction() { }
362 CastChannelSendFunction::~CastChannelSendFunction() { }
364 bool CastChannelSendFunction::Prepare() {
365 params_ = Send::Params::Create(*args_);
366 EXTENSION_FUNCTION_VALIDATE(params_.get());
367 if (params_->message.namespace_.empty()) {
368 SetError("message_info.namespace_ is required");
369 return false;
371 if (params_->message.source_id.empty()) {
372 SetError("message_info.source_id is required");
373 return false;
375 if (params_->message.destination_id.empty()) {
376 SetError("message_info.destination_id is required");
377 return false;
379 switch (params_->message.data->GetType()) {
380 case base::Value::TYPE_STRING:
381 case base::Value::TYPE_BINARY:
382 break;
383 default:
384 SetError("Invalid type of message_info.data");
385 return false;
387 return true;
390 void CastChannelSendFunction::AsyncWorkStart() {
391 CastSocket* socket = GetSocket(params_->channel.channel_id);
392 if (!socket) {
393 SetResultFromError(params_->channel.channel_id,
394 cast_channel::CHANNEL_ERROR_INVALID_CHANNEL_ID);
395 AsyncWorkCompleted();
396 return;
398 CastMessage message_to_send;
399 if (!MessageInfoToCastMessage(params_->message, &message_to_send)) {
400 SetResultFromError(params_->channel.channel_id,
401 cast_channel::CHANNEL_ERROR_INVALID_MESSAGE);
402 AsyncWorkCompleted();
403 return;
405 socket->transport()->SendMessage(
406 message_to_send, base::Bind(&CastChannelSendFunction::OnSend, this));
409 void CastChannelSendFunction::OnSend(int result) {
410 DCHECK_CURRENTLY_ON(BrowserThread::IO);
411 int channel_id = params_->channel.channel_id;
412 CastSocket* socket = GetSocket(channel_id);
413 if (result < 0 || !socket) {
414 SetResultFromError(channel_id,
415 cast_channel::CHANNEL_ERROR_SOCKET_ERROR);
416 } else {
417 SetResultFromSocket(*socket);
419 AsyncWorkCompleted();
422 CastChannelCloseFunction::CastChannelCloseFunction() { }
424 CastChannelCloseFunction::~CastChannelCloseFunction() { }
426 bool CastChannelCloseFunction::Prepare() {
427 params_ = Close::Params::Create(*args_);
428 EXTENSION_FUNCTION_VALIDATE(params_.get());
429 return true;
432 void CastChannelCloseFunction::AsyncWorkStart() {
433 CastSocket* socket = GetSocket(params_->channel.channel_id);
434 if (!socket) {
435 SetResultFromError(params_->channel.channel_id,
436 cast_channel::CHANNEL_ERROR_INVALID_CHANNEL_ID);
437 AsyncWorkCompleted();
438 } else {
439 socket->Close(base::Bind(&CastChannelCloseFunction::OnClose, this));
443 void CastChannelCloseFunction::OnClose(int result) {
444 DCHECK_CURRENTLY_ON(BrowserThread::IO);
445 VLOG(1) << "CastChannelCloseFunction::OnClose result = " << result;
446 int channel_id = params_->channel.channel_id;
447 CastSocket* socket = GetSocket(channel_id);
448 if (result < 0 || !socket) {
449 SetResultFromError(channel_id,
450 cast_channel::CHANNEL_ERROR_SOCKET_ERROR);
451 } else {
452 SetResultFromSocket(*socket);
453 // This will delete |socket|.
454 RemoveSocket(channel_id);
456 AsyncWorkCompleted();
459 CastChannelGetLogsFunction::CastChannelGetLogsFunction() {
462 CastChannelGetLogsFunction::~CastChannelGetLogsFunction() {
465 bool CastChannelGetLogsFunction::PrePrepare() {
466 api_ = CastChannelAPI::Get(browser_context());
467 return CastChannelAsyncApiFunction::PrePrepare();
470 bool CastChannelGetLogsFunction::Prepare() {
471 return true;
474 void CastChannelGetLogsFunction::AsyncWorkStart() {
475 DCHECK(api_);
477 size_t length = 0;
478 scoped_ptr<char[]> out = api_->GetLogger()->GetLogs(&length);
479 if (out.get()) {
480 SetResult(new base::BinaryValue(out.Pass(), length));
481 } else {
482 SetError("Unable to get logs.");
485 api_->GetLogger()->Reset();
487 AsyncWorkCompleted();
490 CastChannelOpenFunction::CastMessageHandler::CastMessageHandler(
491 const EventDispatchCallback& ui_dispatch_cb,
492 cast_channel::CastSocket* socket,
493 scoped_refptr<Logger> logger)
494 : ui_dispatch_cb_(ui_dispatch_cb), socket_(socket), logger_(logger) {
495 DCHECK(socket_);
496 DCHECK(logger_);
499 CastChannelOpenFunction::CastMessageHandler::~CastMessageHandler() {
502 void CastChannelOpenFunction::CastMessageHandler::OnError(
503 cast_channel::ChannelError error_state) {
504 DCHECK_CURRENTLY_ON(BrowserThread::IO);
506 ChannelInfo channel_info;
507 FillChannelInfo(*socket_, &channel_info);
508 channel_info.error_state = error_state;
509 ErrorInfo error_info;
510 FillErrorInfo(error_state, logger_->GetLastErrors(socket_->id()),
511 &error_info);
513 scoped_ptr<base::ListValue> results =
514 OnError::Create(channel_info, error_info);
515 scoped_ptr<Event> event(new Event(events::CAST_CHANNEL_ON_ERROR,
516 OnError::kEventName, results.Pass()));
517 BrowserThread::PostTask(
518 BrowserThread::UI, FROM_HERE,
519 base::Bind(ui_dispatch_cb_, socket_->owner_extension_id(),
520 base::Passed(event.Pass())));
523 void CastChannelOpenFunction::CastMessageHandler::OnMessage(
524 const CastMessage& message) {
525 DCHECK_CURRENTLY_ON(BrowserThread::IO);
527 MessageInfo message_info;
528 cast_channel::CastMessageToMessageInfo(message, &message_info);
529 ChannelInfo channel_info;
530 FillChannelInfo(*socket_, &channel_info);
531 VLOG(1) << "Received message " << ParamToString(message_info)
532 << " on channel " << ParamToString(channel_info);
534 scoped_ptr<base::ListValue> results =
535 OnMessage::Create(channel_info, message_info);
536 scoped_ptr<Event> event(new Event(events::CAST_CHANNEL_ON_MESSAGE,
537 OnMessage::kEventName, results.Pass()));
538 BrowserThread::PostTask(
539 BrowserThread::UI, FROM_HERE,
540 base::Bind(ui_dispatch_cb_, socket_->owner_extension_id(),
541 base::Passed(event.Pass())));
544 void CastChannelOpenFunction::CastMessageHandler::Start() {
547 CastChannelSetAuthorityKeysFunction::CastChannelSetAuthorityKeysFunction() {
550 CastChannelSetAuthorityKeysFunction::~CastChannelSetAuthorityKeysFunction() {
553 bool CastChannelSetAuthorityKeysFunction::Prepare() {
554 params_ = cast_channel::SetAuthorityKeys::Params::Create(*args_);
555 EXTENSION_FUNCTION_VALIDATE(params_.get());
556 return true;
559 void CastChannelSetAuthorityKeysFunction::AsyncWorkStart() {
560 std::string& keys = params_->keys;
561 std::string& signature = params_->signature;
562 if (signature.empty() || keys.empty() ||
563 !cast_channel::SetTrustedCertificateAuthorities(keys, signature)) {
564 SetError("Unable to set authority keys.");
567 AsyncWorkCompleted();
570 } // namespace extensions