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/socket/ssl_client_socket.h"
18 #include "net/url_request/url_request_context.h"
19 #include "net/url_request/url_request_context_builder.h"
21 namespace chromecast
{
25 // How often connectivity checks are performed in seconds.
26 const unsigned int kConnectivityPeriodSeconds
= 1;
28 // Number of consecutive connectivity check errors before status is changed
30 const unsigned int kNumErrorsToNotifyOffline
= 3;
32 // Request timeout value in seconds.
33 const unsigned int kRequestTimeoutInSeconds
= 3;
35 // Default url for connectivity checking.
36 const char kDefaultConnectivityCheckUrl
[] =
37 "https://clients3.google.com/generate_204";
41 ConnectivityCheckerImpl::ConnectivityCheckerImpl(
42 const scoped_refptr
<base::SingleThreadTaskRunner
>& task_runner
)
43 : ConnectivityChecker(),
44 task_runner_(task_runner
),
47 DCHECK(task_runner_
.get());
48 task_runner
->PostTask(FROM_HERE
,
49 base::Bind(&ConnectivityCheckerImpl::Initialize
, this));
52 void ConnectivityCheckerImpl::Initialize() {
53 base::CommandLine
* command_line
= base::CommandLine::ForCurrentProcess();
54 base::CommandLine::StringType check_url_str
=
55 command_line
->GetSwitchValueNative(switches::kConnectivityCheckUrl
);
56 connectivity_check_url_
.reset(new GURL(
57 check_url_str
.empty() ? kDefaultConnectivityCheckUrl
: check_url_str
));
59 net::URLRequestContextBuilder builder
;
60 builder
.set_proxy_config_service(make_scoped_ptr(
61 new net::ProxyConfigServiceFixed(net::ProxyConfig::CreateDirect())));
62 builder
.DisableHttpCache();
63 url_request_context_
= builder
.Build().Pass();
65 net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
66 task_runner_
->PostTask(FROM_HERE
,
67 base::Bind(&ConnectivityCheckerImpl::Check
, this));
70 ConnectivityCheckerImpl::~ConnectivityCheckerImpl() {
71 DCHECK(task_runner_
.get());
72 net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
73 task_runner_
->DeleteSoon(FROM_HERE
, url_request_
.release());
74 task_runner_
->DeleteSoon(FROM_HERE
, url_request_context_
.release());
77 bool ConnectivityCheckerImpl::Connected() const {
81 void ConnectivityCheckerImpl::SetConnected(bool connected
) {
82 if (connected_
== connected
)
85 connected_
= connected
;
87 LOG(INFO
) << "Global connection is: " << (connected
? "Up" : "Down");
90 void ConnectivityCheckerImpl::Check() {
91 if (!task_runner_
->BelongsToCurrentThread()) {
92 task_runner_
->PostTask(FROM_HERE
,
93 base::Bind(&ConnectivityCheckerImpl::Check
, this));
96 DCHECK(url_request_context_
.get());
98 // Don't check connectivity if network is offline, because Internet could be
99 // accessible via netifs ignored.
100 if (net::NetworkChangeNotifier::IsOffline())
103 // If url_request_ is non-null, there is already a check going on. Don't
105 if (url_request_
.get())
108 VLOG(1) << "Connectivity check: url=" << *connectivity_check_url_
;
109 url_request_
= url_request_context_
->CreateRequest(
110 *connectivity_check_url_
, net::MAXIMUM_PRIORITY
, this);
111 url_request_
->set_method("HEAD");
112 url_request_
->Start();
114 timeout_
.Reset(base::Bind(&ConnectivityCheckerImpl::OnUrlRequestTimeout
,
116 base::MessageLoop::current()->PostDelayedTask(
119 base::TimeDelta::FromSeconds(kRequestTimeoutInSeconds
));
122 void ConnectivityCheckerImpl::OnNetworkChanged(
123 net::NetworkChangeNotifier::ConnectionType type
) {
124 VLOG(2) << "OnNetworkChanged " << type
;
127 if (type
== net::NetworkChangeNotifier::CONNECTION_NONE
) {
135 void ConnectivityCheckerImpl::OnResponseStarted(net::URLRequest
* request
) {
137 int http_response_code
=
138 (request
->status().is_success() &&
139 request
->response_info().headers
.get() != NULL
)
140 ? request
->response_info().headers
->response_code()
141 : net::HTTP_BAD_REQUEST
;
144 url_request_
.reset(NULL
); // URLRequest::Cancel() is called in destructor.
146 if (http_response_code
< 400) {
147 VLOG(1) << "Connectivity check succeeded";
152 VLOG(1) << "Connectivity check failed: " << http_response_code
;
156 void ConnectivityCheckerImpl::OnReadCompleted(net::URLRequest
* request
,
161 void ConnectivityCheckerImpl::OnSSLCertificateError(
162 net::URLRequest
* request
,
163 const net::SSLInfo
& ssl_info
,
165 LOG(ERROR
) << "OnSSLCertificateError: cert_status=" << ssl_info
.cert_status
;
167 net::SSLClientSocket::ClearSessionCache();
171 void ConnectivityCheckerImpl::OnUrlRequestError() {
173 if (check_errors_
> kNumErrorsToNotifyOffline
) {
174 check_errors_
= kNumErrorsToNotifyOffline
;
177 url_request_
.reset(NULL
);
179 task_runner_
->PostDelayedTask(
180 FROM_HERE
, base::Bind(&ConnectivityCheckerImpl::Check
, this),
181 base::TimeDelta::FromSeconds(kConnectivityPeriodSeconds
));
184 void ConnectivityCheckerImpl::OnUrlRequestTimeout() {
185 LOG(ERROR
) << "time out";
189 void ConnectivityCheckerImpl::Cancel() {
190 if (!url_request_
.get())
192 VLOG(2) << "Cancel connectivity check in progress";
194 url_request_
.reset(NULL
); // URLRequest::Cancel() is called in destructor.
197 } // namespace chromecast