Home | History | Annotate | Download | only in net
      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