• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 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.
4 
5 #include "chrome/browser/net/dns_probe_runner.h"
6 
7 #include "base/bind.h"
8 #include "content/public/browser/browser_thread.h"
9 #include "net/base/address_list.h"
10 #include "net/base/ip_endpoint.h"
11 #include "net/base/net_errors.h"
12 #include "net/base/net_log.h"
13 #include "net/base/net_util.h"
14 #include "net/base/network_change_notifier.h"
15 #include "net/dns/dns_client.h"
16 #include "net/dns/dns_protocol.h"
17 #include "net/dns/dns_response.h"
18 #include "net/dns/dns_transaction.h"
19 
20 using base::TimeDelta;
21 using content::BrowserThread;
22 using net::AddressList;
23 using net::BoundNetLog;
24 using net::DnsClient;
25 using net::DnsResponse;
26 using net::DnsTransaction;
27 using net::DnsTransactionFactory;
28 using net::IPAddressNumber;
29 using net::IPEndPoint;
30 using net::NetLog;
31 using net::NetworkChangeNotifier;
32 using net::ParseIPLiteralToNumber;
33 
34 namespace chrome_browser_net {
35 
36 const char* DnsProbeRunner::kKnownGoodHostname = "google.com";
37 
38 namespace {
39 
EvaluateResponse(int net_error,const DnsResponse * response)40 DnsProbeRunner::Result EvaluateResponse(
41     int net_error,
42     const DnsResponse* response) {
43   switch (net_error) {
44     case net::OK:
45       break;
46 
47     // ERR_NAME_NOT_RESOLVED maps to NXDOMAIN, which means the server is working
48     // but returned a wrong answer.
49     case net::ERR_NAME_NOT_RESOLVED:
50       return DnsProbeRunner::INCORRECT;
51 
52     // These results mean we heard *something* from the DNS server, but it was
53     // unsuccessful (SERVFAIL) or malformed.
54     case net::ERR_DNS_MALFORMED_RESPONSE:
55     case net::ERR_DNS_SERVER_REQUIRES_TCP:  // Shouldn't happen; DnsTransaction
56                                             // will retry with TCP.
57     case net::ERR_DNS_SERVER_FAILED:
58     case net::ERR_DNS_SORT_ERROR:  // Can only happen if the server responds.
59       return DnsProbeRunner::FAILING;
60 
61     // Any other error means we never reached the DNS server in the first place.
62     case net::ERR_DNS_TIMED_OUT:
63     default:
64       // Something else happened, probably at a network level.
65       return DnsProbeRunner::UNREACHABLE;
66   }
67 
68   AddressList addr_list;
69   TimeDelta ttl;
70   DnsResponse::Result result = response->ParseToAddressList(&addr_list, &ttl);
71 
72   if (result != DnsResponse::DNS_PARSE_OK)
73     return DnsProbeRunner::FAILING;
74   else if (addr_list.empty())
75     return DnsProbeRunner::INCORRECT;
76   else
77     return DnsProbeRunner::CORRECT;
78 }
79 
80 }  // namespace
81 
DnsProbeRunner()82 DnsProbeRunner::DnsProbeRunner() : weak_factory_(this), result_(UNKNOWN) {}
83 
~DnsProbeRunner()84 DnsProbeRunner::~DnsProbeRunner() {}
85 
SetClient(scoped_ptr<net::DnsClient> client)86 void DnsProbeRunner::SetClient(scoped_ptr<net::DnsClient> client) {
87   client_ = client.Pass();
88 }
89 
RunProbe(const base::Closure & callback)90 void DnsProbeRunner::RunProbe(const base::Closure& callback) {
91   DCHECK(!callback.is_null());
92   DCHECK(client_.get());
93   DCHECK(callback_.is_null());
94   DCHECK(!transaction_.get());
95 
96   callback_ = callback;
97   DnsTransactionFactory* factory = client_->GetTransactionFactory();
98   if (!factory) {
99     // If the DnsTransactionFactory is NULL, then the DnsConfig is invalid, so
100     // the runner can't run a transaction.  Return UNKNOWN asynchronously.
101     result_ = UNKNOWN;
102     BrowserThread::PostTask(
103         BrowserThread::IO,
104         FROM_HERE,
105         base::Bind(&DnsProbeRunner::CallCallback,
106                    weak_factory_.GetWeakPtr()));
107     return;
108   }
109 
110   transaction_ = factory->CreateTransaction(
111       kKnownGoodHostname,
112       net::dns_protocol::kTypeA,
113       base::Bind(&DnsProbeRunner::OnTransactionComplete,
114                  weak_factory_.GetWeakPtr()),
115       BoundNetLog());
116 
117   transaction_->Start();
118 }
119 
IsRunning() const120 bool DnsProbeRunner::IsRunning() const {
121   return !callback_.is_null();
122 }
123 
OnTransactionComplete(DnsTransaction * transaction,int net_error,const DnsResponse * response)124 void DnsProbeRunner::OnTransactionComplete(
125     DnsTransaction* transaction,
126     int net_error,
127     const DnsResponse* response) {
128   DCHECK(!callback_.is_null());
129   DCHECK(transaction_.get());
130   DCHECK_EQ(transaction_.get(), transaction);
131 
132   result_ = EvaluateResponse(net_error, response);
133   transaction_.reset();
134 
135   BrowserThread::PostTask(
136       BrowserThread::IO,
137       FROM_HERE,
138       base::Bind(&DnsProbeRunner::CallCallback,
139                  weak_factory_.GetWeakPtr()));
140 }
141 
CallCallback()142 void DnsProbeRunner::CallCallback() {
143   DCHECK(!callback_.is_null());
144   DCHECK(!transaction_.get());
145 
146   // Clear callback in case it starts a new probe immediately.
147   const base::Closure callback = callback_;
148   callback_.Reset();
149   callback.Run();
150 }
151 
152 }  // namespace chrome_browser_net
153