1 // Copyright 2015 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 "chromecast/net/connectivity_checker_impl.h"
7 #include "base/command_line.h"
8 #include "base/logging.h"
9 #include "base/message_loop/message_loop.h"
10 #include "chromecast/net/net_switches.h"
11 #include "net/base/request_priority.h"
12 #include "net/http/http_response_headers.h"
13 #include "net/http/http_response_info.h"
14 #include "net/http/http_status_code.h"
15 #include "net/proxy/proxy_config.h"
16 #include "net/proxy/proxy_config_service_fixed.h"
17 #include "net/url_request/url_request_context.h"
18 #include "net/url_request/url_request_context_builder.h"
20 namespace chromecast
{
24 // How often connectivity checks are performed in seconds.
25 const unsigned int kConnectivityPeriodSeconds
= 1;
27 // Number of consecutive connectivity check errors before status is changed
29 const unsigned int kNumErrorsToNotifyOffline
= 3;
31 // Request timeout value in seconds.
32 const unsigned int kRequestTimeoutInSeconds
= 3;
34 // Default url for connectivity checking.
35 const char kDefaultConnectivityCheckUrl
[] =
36 "https://clients3.google.com/generate_204";
40 ConnectivityCheckerImpl::ConnectivityCheckerImpl(
41 const scoped_refptr
<base::SingleThreadTaskRunner
>& task_runner
)
42 : ConnectivityChecker(),
43 task_runner_(task_runner
),
46 DCHECK(task_runner_
.get());
47 task_runner
->PostTask(FROM_HERE
,
48 base::Bind(&ConnectivityCheckerImpl::Initialize
, this));
51 void ConnectivityCheckerImpl::Initialize() {
52 base::CommandLine
* command_line
= base::CommandLine::ForCurrentProcess();
53 base::CommandLine::StringType check_url_str
=
54 command_line
->GetSwitchValueNative(switches::kConnectivityCheckUrl
);
55 connectivity_check_url_
.reset(new GURL(
56 check_url_str
.empty() ? kDefaultConnectivityCheckUrl
: check_url_str
));
58 net::URLRequestContextBuilder builder
;
59 builder
.set_proxy_config_service(
60 new net::ProxyConfigServiceFixed(net::ProxyConfig::CreateDirect()));
61 builder
.DisableHttpCache();
62 url_request_context_
.reset(builder
.Build());
64 net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
65 task_runner_
->PostTask(FROM_HERE
,
66 base::Bind(&ConnectivityCheckerImpl::Check
, this));
69 ConnectivityCheckerImpl::~ConnectivityCheckerImpl() {
70 DCHECK(task_runner_
.get());
71 net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
72 task_runner_
->DeleteSoon(FROM_HERE
, url_request_
.release());
73 task_runner_
->DeleteSoon(FROM_HERE
, url_request_context_
.release());
76 bool ConnectivityCheckerImpl::Connected() const {
80 void ConnectivityCheckerImpl::SetConnected(bool connected
) {
81 if (connected_
== connected
)
84 connected_
= connected
;
86 LOG(INFO
) << "Global connection is: " << (connected
? "Up" : "Down");
89 void ConnectivityCheckerImpl::Check() {
90 if (!task_runner_
->BelongsToCurrentThread()) {
91 task_runner_
->PostTask(FROM_HERE
,
92 base::Bind(&ConnectivityCheckerImpl::Check
, this));
95 DCHECK(url_request_context_
.get());
97 // Don't check connectivity if network is offline, because Internet could be
98 // accessible via netifs ignored.
99 if (net::NetworkChangeNotifier::IsOffline())
102 // If url_request_ is non-null, there is already a check going on. Don't
104 if (url_request_
.get())
107 VLOG(1) << "Connectivity check: url=" << *connectivity_check_url_
;
108 url_request_
= url_request_context_
->CreateRequest(
109 *connectivity_check_url_
, net::MAXIMUM_PRIORITY
, this);
110 url_request_
->set_method("HEAD");
111 url_request_
->Start();
113 timeout_
.Reset(base::Bind(&ConnectivityCheckerImpl::OnUrlRequestTimeout
,
115 base::MessageLoop::current()->PostDelayedTask(
118 base::TimeDelta::FromSeconds(kRequestTimeoutInSeconds
));
121 void ConnectivityCheckerImpl::OnNetworkChanged(
122 net::NetworkChangeNotifier::ConnectionType type
) {
123 VLOG(2) << "OnNetworkChanged " << type
;
126 if (type
== net::NetworkChangeNotifier::CONNECTION_NONE
) {
134 void ConnectivityCheckerImpl::OnResponseStarted(net::URLRequest
* request
) {
136 int http_response_code
=
137 (request
->status().is_success() &&
138 request
->response_info().headers
.get() != NULL
)
139 ? request
->response_info().headers
->response_code()
140 : net::HTTP_BAD_REQUEST
;
143 url_request_
.reset(NULL
); // URLRequest::Cancel() is called in destructor.
145 if (http_response_code
< 400) {
146 VLOG(1) << "Connectivity check succeeded";
151 VLOG(1) << "Connectivity check failed: " << http_response_code
;
155 void ConnectivityCheckerImpl::OnReadCompleted(net::URLRequest
* request
,
160 void ConnectivityCheckerImpl::OnSSLCertificateError(
161 net::URLRequest
* request
,
162 const net::SSLInfo
& ssl_info
,
164 LOG(ERROR
) << "OnSSLCertificateError: cert_status=" << ssl_info
.cert_status
;
169 void ConnectivityCheckerImpl::OnUrlRequestError() {
171 if (check_errors_
> kNumErrorsToNotifyOffline
) {
172 check_errors_
= kNumErrorsToNotifyOffline
;
175 url_request_
.reset(NULL
);
177 task_runner_
->PostDelayedTask(
178 FROM_HERE
, base::Bind(&ConnectivityCheckerImpl::Check
, this),
179 base::TimeDelta::FromSeconds(kConnectivityPeriodSeconds
));
182 void ConnectivityCheckerImpl::OnUrlRequestTimeout() {
183 LOG(ERROR
) << "time out";
187 void ConnectivityCheckerImpl::Cancel() {
188 if (!url_request_
.get())
190 VLOG(2) << "Cancel connectivity check in progress";
192 url_request_
.reset(NULL
); // URLRequest::Cancel() is called in destructor.
195 } // namespace chromecast