Chromium Code Reviews| Index: chromecast/net/connectivity_checker.cc |
| diff --git a/chromecast/net/connectivity_checker.cc b/chromecast/net/connectivity_checker.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..633c2ac4013a37ffea8c818eabfff130772b82b8 |
| --- /dev/null |
| +++ b/chromecast/net/connectivity_checker.cc |
| @@ -0,0 +1,175 @@ |
| +// Copyright 2015 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "chromecast/net/connectivity_checker.h" |
| + |
| +#include "base/command_line.h" |
| +#include "base/logging.h" |
| +#include "base/message_loop/message_loop.h" |
| +#include "chromecast/net/net_switches.h" |
| +#include "net/base/request_priority.h" |
| +#include "net/http/http_response_headers.h" |
| +#include "net/http/http_response_info.h" |
| +#include "net/http/http_status_code.h" |
| +#include "net/proxy/proxy_config.h" |
| +#include "net/proxy/proxy_config_service_fixed.h" |
| +#include "net/url_request/url_request_context.h" |
| +#include "net/url_request/url_request_context_builder.h" |
| + |
| +namespace chromecast { |
| + |
| +namespace { |
| + |
| +// How often we perform connectivity checks in seconds |
|
gunsch
2015/02/20 01:56:03
nit: avoid first-person references in comments, he
derekjchow1
2015/02/20 02:24:16
Done.
|
| +const unsigned int kConnectivityPeriodSeconds = 1; |
| + |
| +// Number of consecutive bad responses we receive before we change connectivity |
| +// to offline |
| +const unsigned int kNumBadResponses = 3; |
| + |
| +// Default url for connectivity checking. |
| +const char kDefaultConnectivityCheckUrl[] = |
| + "https://clients3.google.com/generate_204"; |
| + |
| +} // namespace |
| + |
| +ConnectivityChecker::ConnectivityChecker( |
| + const scoped_refptr<base::MessageLoopProxy>& loop_proxy) |
| + : connectivity_observer_list_( |
| + new ObserverListThreadSafe<ConnectivityObserver>()), |
| + loop_proxy_(loop_proxy), |
| + connected_(false), |
| + bad_responses_(0) { |
| + DCHECK(loop_proxy_.get()); |
| + loop_proxy->PostTask(FROM_HERE, |
| + base::Bind(&ConnectivityChecker::Initialize, this)); |
| +} |
| + |
| +void ConnectivityChecker::Initialize() { |
| + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); |
| + base::CommandLine::StringType check_url_str = |
| + command_line->GetSwitchValueNative(switches::kConnectivityCheckUrl); |
| + connectivity_check_url_.reset(new GURL( |
| + check_url_str.empty() ? kDefaultConnectivityCheckUrl : check_url_str)); |
| + |
| + net::URLRequestContextBuilder builder; |
| + builder.set_proxy_config_service( |
| + new net::ProxyConfigServiceFixed(net::ProxyConfig::CreateDirect())); |
| + builder.DisableHttpCache(); |
| + url_request_context_.reset(builder.Build()); |
| + |
| + net::NetworkChangeNotifier::AddConnectionTypeObserver(this); |
| + if (!net::NetworkChangeNotifier::IsOffline()) { |
| + loop_proxy_->PostTask(FROM_HERE, |
| + base::Bind(&ConnectivityChecker::Check, this)); |
| + } |
| +} |
| + |
| +ConnectivityChecker::~ConnectivityChecker() { |
| + DCHECK(loop_proxy_.get()); |
| + loop_proxy_->DeleteSoon(FROM_HERE, url_request_context_.release()); |
| +} |
| + |
| +void ConnectivityChecker::AddConnectivityObserver( |
| + ConnectivityObserver* observer) { |
| + connectivity_observer_list_->AddObserver(observer); |
| +} |
| + |
| +void ConnectivityChecker::RemoveConnectivityObserver( |
| + ConnectivityObserver* observer) { |
| + connectivity_observer_list_->RemoveObserver(observer); |
| +} |
| + |
| +bool ConnectivityChecker::Connected() const { |
| + return connected_; |
| +} |
| + |
| +void ConnectivityChecker::SetConnectivity(bool connected) { |
| + if (connected) |
| + bad_responses_ = 0; |
|
gunsch
2015/02/20 01:57:28
how about moving "bad_responses_ = 0" to "OnRespon
derekjchow1
2015/02/20 02:24:16
Done.
|
| + |
| + if (connected_ == connected) |
| + return; |
| + |
| + connected_ = connected; |
| + connectivity_observer_list_->Notify( |
| + FROM_HERE, &ConnectivityObserver::OnConnectivityChanged, connected); |
| + LOG(INFO) << "Global connection is: " << (connected ? "Up" : "Down"); |
| +} |
| + |
| +void ConnectivityChecker::Check() { |
| + if (!loop_proxy_->BelongsToCurrentThread()) { |
| + loop_proxy_->PostTask(FROM_HERE, |
| + base::Bind(&ConnectivityChecker::Check, this)); |
| + return; |
| + } |
| + DCHECK(url_request_context_.get()); |
| + |
| + // If url_request_ is non-null, there is already a check going on. Don't |
| + // start another. |
| + if (url_request_.get()) |
| + return; |
| + |
| + VLOG(2) << "Connectivity check: url=" << *connectivity_check_url_; |
| + url_request_ = url_request_context_->CreateRequest( |
| + *connectivity_check_url_, net::MAXIMUM_PRIORITY, this, NULL); |
| + url_request_->set_method("HEAD"); |
| + url_request_->Start(); |
| +} |
| + |
| +void ConnectivityChecker::OnConnectionTypeChanged( |
| + net::NetworkChangeNotifier::ConnectionType type) { |
| + Cancel(); |
| + |
| + // If there is no connection, set connectivity to false. Otherwise retest |
| + // connectivity |
| + if (type == net::NetworkChangeNotifier::CONNECTION_NONE) { |
| + SetConnectivity(false); |
| + } else { |
| + Check(); |
| + } |
| +} |
| + |
| +void ConnectivityChecker::OnResponseStarted(net::URLRequest* request) { |
| + int http_response_code = |
| + (request->status().is_success() && |
| + request->response_info().headers.get() != NULL) |
| + ? request->response_info().headers->response_code() |
| + : net::HTTP_BAD_REQUEST; |
| + |
| + // Clears resources. |
| + url_request_.reset(NULL); // URLRequest::Cancel() is called in destructor. |
| + |
| + if (http_response_code < 400) { |
| + SetConnectivity(true); |
| + return; |
| + } |
| + |
| + ++bad_responses_; |
| + if (bad_responses_ > kNumBadResponses) { |
| + bad_responses_ = kNumBadResponses; |
| + SetConnectivity(false); |
| + } |
| + |
| + // Check again |
| + if (!net::NetworkChangeNotifier::IsOffline()) { |
| + loop_proxy_->PostDelayedTask( |
| + FROM_HERE, base::Bind(&ConnectivityChecker::Check, this), |
| + base::TimeDelta::FromSeconds(kConnectivityPeriodSeconds)); |
| + } |
| +} |
| + |
| +void ConnectivityChecker::OnReadCompleted(net::URLRequest* request, |
| + int bytes_read) { |
| + NOTREACHED(); |
| +} |
| + |
| +void ConnectivityChecker::Cancel() { |
| + if (url_request_.get()) { |
| + VLOG(2) << "Cancel connectivity check in progress"; |
| + url_request_.reset(NULL); // URLRequest::Cancel() is called in destructor. |
| + } |
| +} |
| + |
| +} // namespace chromecast |