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.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 bad responses received before connectivity status is
29 const unsigned int kNumBadResponses
= 3;
31 // Default url for connectivity checking.
32 const char kDefaultConnectivityCheckUrl
[] =
33 "https://clients3.google.com/generate_204";
37 ConnectivityChecker::ConnectivityChecker(
38 const scoped_refptr
<base::MessageLoopProxy
>& loop_proxy
)
39 : connectivity_observer_list_(
40 new ObserverListThreadSafe
<ConnectivityObserver
>()),
41 loop_proxy_(loop_proxy
),
44 DCHECK(loop_proxy_
.get());
45 loop_proxy
->PostTask(FROM_HERE
,
46 base::Bind(&ConnectivityChecker::Initialize
, this));
49 void ConnectivityChecker::Initialize() {
50 base::CommandLine
* command_line
= base::CommandLine::ForCurrentProcess();
51 base::CommandLine::StringType check_url_str
=
52 command_line
->GetSwitchValueNative(switches::kConnectivityCheckUrl
);
53 connectivity_check_url_
.reset(new GURL(
54 check_url_str
.empty() ? kDefaultConnectivityCheckUrl
: check_url_str
));
56 net::URLRequestContextBuilder builder
;
57 builder
.set_proxy_config_service(
58 new net::ProxyConfigServiceFixed(net::ProxyConfig::CreateDirect()));
59 builder
.DisableHttpCache();
60 url_request_context_
.reset(builder
.Build());
62 net::NetworkChangeNotifier::AddConnectionTypeObserver(this);
63 loop_proxy_
->PostTask(FROM_HERE
,
64 base::Bind(&ConnectivityChecker::Check
, this));
67 ConnectivityChecker::~ConnectivityChecker() {
68 DCHECK(loop_proxy_
.get());
69 loop_proxy_
->DeleteSoon(FROM_HERE
, url_request_context_
.release());
70 loop_proxy_
->DeleteSoon(FROM_HERE
, url_request_
.release());
73 void ConnectivityChecker::AddConnectivityObserver(
74 ConnectivityObserver
* observer
) {
75 connectivity_observer_list_
->AddObserver(observer
);
78 void ConnectivityChecker::RemoveConnectivityObserver(
79 ConnectivityObserver
* observer
) {
80 connectivity_observer_list_
->RemoveObserver(observer
);
83 bool ConnectivityChecker::Connected() const {
87 void ConnectivityChecker::SetConnectivity(bool connected
) {
88 if (connected_
== connected
)
91 connected_
= connected
;
92 connectivity_observer_list_
->Notify(
93 FROM_HERE
, &ConnectivityObserver::OnConnectivityChanged
, connected
);
94 LOG(INFO
) << "Global connection is: " << (connected
? "Up" : "Down");
97 void ConnectivityChecker::Check() {
98 if (!loop_proxy_
->BelongsToCurrentThread()) {
99 loop_proxy_
->PostTask(FROM_HERE
,
100 base::Bind(&ConnectivityChecker::Check
, this));
103 DCHECK(url_request_context_
.get());
105 // If url_request_ is non-null, there is already a check going on. Don't
107 if (url_request_
.get())
110 VLOG(1) << "Connectivity check: url=" << *connectivity_check_url_
;
111 url_request_
= url_request_context_
->CreateRequest(
112 *connectivity_check_url_
, net::MAXIMUM_PRIORITY
, this, NULL
);
113 url_request_
->set_method("HEAD");
114 url_request_
->Start();
117 void ConnectivityChecker::OnConnectionTypeChanged(
118 net::NetworkChangeNotifier::ConnectionType type
) {
119 if (type
== net::NetworkChangeNotifier::CONNECTION_NONE
)
120 SetConnectivity(false);
126 void ConnectivityChecker::OnResponseStarted(net::URLRequest
* request
) {
127 int http_response_code
=
128 (request
->status().is_success() &&
129 request
->response_info().headers
.get() != NULL
)
130 ? request
->response_info().headers
->response_code()
131 : net::HTTP_BAD_REQUEST
;
134 url_request_
.reset(NULL
); // URLRequest::Cancel() is called in destructor.
136 if (http_response_code
< 400) {
137 VLOG(1) << "Connectivity check succeeded";
139 SetConnectivity(true);
143 VLOG(1) << "Connectivity check failed: " << http_response_code
;
145 if (bad_responses_
> kNumBadResponses
) {
146 bad_responses_
= kNumBadResponses
;
147 SetConnectivity(false);
151 loop_proxy_
->PostDelayedTask(
152 FROM_HERE
, base::Bind(&ConnectivityChecker::Check
, this),
153 base::TimeDelta::FromSeconds(kConnectivityPeriodSeconds
));
156 void ConnectivityChecker::OnReadCompleted(net::URLRequest
* request
,
161 void ConnectivityChecker::Cancel() {
162 if (url_request_
.get()) {
163 VLOG(2) << "Cancel connectivity check in progress";
164 url_request_
.reset(NULL
); // URLRequest::Cancel() is called in destructor.
168 } // namespace chromecast