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 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 82 DnsProbeRunner::DnsProbeRunner() : weak_factory_(this), result_(UNKNOWN) {} 83 84 DnsProbeRunner::~DnsProbeRunner() {} 85 86 void DnsProbeRunner::SetClient(scoped_ptr<net::DnsClient> client) { 87 client_ = client.Pass(); 88 } 89 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 120 bool DnsProbeRunner::IsRunning() const { 121 return !callback_.is_null(); 122 } 123 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 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