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