summaryrefslogtreecommitdiffstats
path: root/net/base
diff options
context:
space:
mode:
authoragayev@chromium.org <agayev@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-07-18 15:12:46 +0000
committeragayev@chromium.org <agayev@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-07-18 15:12:46 +0000
commitd391116230f8281484ef7c339f18f5e8b9692a8b (patch)
treeaf189ad77b3dc7e7d0c14a1a94ca78d1bf614ce9 /net/base
parentbafa00e4fda7ae133485a8b3112e8c942dd58aa3 (diff)
downloadchromium_src-d391116230f8281484ef7c339f18f5e8b9692a8b.zip
chromium_src-d391116230f8281484ef7c339f18f5e8b9692a8b.tar.gz
chromium_src-d391116230f8281484ef7c339f18f5e8b9692a8b.tar.bz2
DnsTransaction: added a delegate interface.
BUG=60149 TEST=net_unittests --gtest_filter="DnsTransaction*" Review URL: http://codereview.chromium.org/7322016 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@92851 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/base')
-rw-r--r--net/base/address_list.cc4
-rw-r--r--net/base/address_list.h2
-rw-r--r--net/base/address_list_unittest.cc2
-rw-r--r--net/base/dns_response.cc4
-rw-r--r--net/base/dns_response.h2
-rw-r--r--net/base/dns_response_unittest.cc4
-rw-r--r--net/base/dns_test_util.cc49
-rw-r--r--net/base/dns_test_util.h137
-rw-r--r--net/base/dns_transaction.cc71
-rw-r--r--net/base/dns_transaction.h50
-rw-r--r--net/base/dns_transaction_unittest.cc341
-rw-r--r--net/base/net_util.h1
12 files changed, 446 insertions, 221 deletions
diff --git a/net/base/address_list.cc b/net/base/address_list.cc
index 279ed79..f9076bc 100644
--- a/net/base/address_list.cc
+++ b/net/base/address_list.cc
@@ -111,13 +111,13 @@ AddressList& AddressList::operator=(const AddressList& addresslist) {
// static
AddressList AddressList::CreateFromIPAddressList(
- const std::vector<IPAddressNumber>& addresses,
+ const IPAddressList& addresses,
uint16 port) {
DCHECK(!addresses.empty());
struct addrinfo* head = NULL;
struct addrinfo* next = NULL;
- for (std::vector<IPAddressNumber>::const_iterator it = addresses.begin();
+ for (IPAddressList::const_iterator it = addresses.begin();
it != addresses.end(); ++it) {
if (head == NULL) {
head = next = CreateAddrInfo(*it, false);
diff --git a/net/base/address_list.h b/net/base/address_list.h
index 840bc51..37967fe 100644
--- a/net/base/address_list.h
+++ b/net/base/address_list.h
@@ -30,7 +30,7 @@ class NET_API AddressList {
// Creates an address list for a list of IP literals.
static AddressList CreateFromIPAddressList(
- const std::vector<IPAddressNumber>& addresses,
+ const IPAddressList& addresses,
uint16 port);
// Creates an address list for a single IP literal.
diff --git a/net/base/address_list_unittest.cc b/net/base/address_list_unittest.cc
index dce412c..f34ffb5 100644
--- a/net/base/address_list_unittest.cc
+++ b/net/base/address_list_unittest.cc
@@ -308,7 +308,7 @@ TEST(AddressListTest, CreateFromIPAddressList) {
const uint16 kPort = 80;
// Construct a list of ip addresses.
- std::vector<IPAddressNumber> ip_list;
+ IPAddressList ip_list;
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
IPAddressNumber ip_number;
ParseIPLiteralToNumber(tests[i].ip_address, &ip_number);
diff --git a/net/base/dns_response.cc b/net/base/dns_response.cc
index 31dfac3..f7d88e1 100644
--- a/net/base/dns_response.cc
+++ b/net/base/dns_response.cc
@@ -22,7 +22,7 @@ DnsResponse::DnsResponse(DnsQuery* query)
DnsResponse::~DnsResponse() {
}
-int DnsResponse::Parse(int nbytes, std::vector<IPAddressNumber>* ip_addresses) {
+int DnsResponse::Parse(int nbytes, IPAddressList* ip_addresses) {
// Response includes query, it should be at least that size.
if (nbytes < query_->io_buffer()->size() || nbytes > kMaxResponseSize)
return ERR_DNS_MALFORMED_RESPONSE;
@@ -65,7 +65,7 @@ int DnsResponse::Parse(int nbytes, std::vector<IPAddressNumber>* ip_addresses) {
if (answer_count < 1)
return ERR_NAME_NOT_RESOLVED;
- std::vector<IPAddressNumber> rdatas;
+ IPAddressList rdatas;
while (answer_count--) {
uint32 ttl;
uint16 rdlength, qtype, qclass;
diff --git a/net/base/dns_response.h b/net/base/dns_response.h
index eff8ffe..d62f350 100644
--- a/net/base/dns_response.h
+++ b/net/base/dns_response.h
@@ -28,7 +28,7 @@ class NET_TEST DnsResponse {
// Parses response of size nbytes and puts address into |ip_addresses|,
// returns net_error code in case of failure.
- int Parse(int nbytes, std::vector<IPAddressNumber>* ip_addresses);
+ int Parse(int nbytes, IPAddressList* ip_addresses);
private:
// The matching query; |this| is the response for |query_|. We do not
diff --git a/net/base/dns_response_unittest.cc b/net/base/dns_response_unittest.cc
index 8f7f5bb..e7701b0 100644
--- a/net/base/dns_response_unittest.cc
+++ b/net/base/dns_response_unittest.cc
@@ -80,7 +80,7 @@ TEST(DnsResponseTest, ResponseWithCnameA) {
0x4a, 0x7d, 0x5f, 0x79 // 74.125.95.121
};
- std::vector<IPAddressNumber> expected_ips;
+ IPAddressList expected_ips;
expected_ips.push_back(IPAddressNumber(ip, ip + arraysize(ip)));
uint8 response_data[] = {
@@ -133,7 +133,7 @@ TEST(DnsResponseTest, ResponseWithCnameA) {
// Verify resolved IPs.
int response_size = arraysize(response_data);
- std::vector<IPAddressNumber> actual_ips;
+ IPAddressList actual_ips;
EXPECT_EQ(OK, r1.Parse(response_size, &actual_ips));
EXPECT_EQ(expected_ips, actual_ips);
}
diff --git a/net/base/dns_test_util.cc b/net/base/dns_test_util.cc
new file mode 100644
index 0000000..f448b6f
--- /dev/null
+++ b/net/base/dns_test_util.cc
@@ -0,0 +1,49 @@
+// Copyright (c) 2011 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 "net/base/dns_test_util.h"
+
+#include "base/message_loop.h"
+
+namespace net {
+
+TestPrng::TestPrng(const std::deque<int>& numbers) : numbers_(numbers) {
+}
+
+TestPrng::~TestPrng() {
+}
+
+int TestPrng::GetNext(int min, int max) {
+ DCHECK(!numbers_.empty());
+ int rv = numbers_.front();
+ numbers_.pop_front();
+ DCHECK(rv >= min && rv <= max);
+ return rv;
+}
+
+bool ConvertStringsToIPAddressList(
+ const char* const ip_strings[], size_t size, IPAddressList* address_list) {
+ DCHECK(address_list);
+ IPAddressList ip_addresses;
+ for (size_t i = 0; i < size; ++i) {
+ IPAddressNumber ip;
+ if (!ParseIPLiteralToNumber(ip_strings[i], &ip))
+ return false;
+ ip_addresses.push_back(ip);
+ }
+ address_list->swap(ip_addresses);
+ return true;
+}
+
+bool CreateDnsAddress(
+ const char* ip_string, uint16 port, IPEndPoint* endpoint) {
+ DCHECK(endpoint);
+ IPAddressNumber ip_address;
+ if (!ParseIPLiteralToNumber(ip_string, &ip_address))
+ return false;
+ *endpoint = IPEndPoint(ip_address, port);
+ return true;
+}
+
+} // namespace net
diff --git a/net/base/dns_test_util.h b/net/base/dns_test_util.h
new file mode 100644
index 0000000..96ce38a
--- /dev/null
+++ b/net/base/dns_test_util.h
@@ -0,0 +1,137 @@
+// Copyright (c) 2011 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.
+
+#ifndef NET_BASE_DNS_TEST_UTIL_H_
+#define NET_BASE_DNS_TEST_UTIL_H_
+#pragma once
+
+#include <deque>
+#include <vector>
+
+#include "base/logging.h"
+#include "net/base/dns_transaction.h"
+#include "net/base/dns_util.h"
+#include "net/base/ip_endpoint.h"
+#include "net/base/net_util.h"
+
+namespace net {
+
+// DNS related classes make use of PRNG for various tasks. This class is
+// used as a PRNG for unit testing those tasks. It takes a deque of
+// integers |numbers| which should be returned by calls to GetNext.
+class TestPrng {
+ public:
+ explicit TestPrng(const std::deque<int>& numbers);
+ ~TestPrng();
+
+ // Pops and returns the next number from |numbers_| deque.
+ int GetNext(int min, int max);
+
+ private:
+ std::deque<int> numbers_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestPrng);
+};
+
+// A utility function for tests that given an array of IP literals,
+// converts it to an IPAddressList.
+bool ConvertStringsToIPAddressList(
+ const char* const ip_strings[], size_t size, IPAddressList* address_list);
+
+// A utility function for tests that creates an IPEndPoint whose IP is
+// |ip_string| and whose port is |port| and stores it in |endpoint|.
+bool CreateDnsAddress(const char* ip_string, uint16 port, IPEndPoint* endpoint);
+
+static const char kDnsIp[] = "192.168.1.1";
+static const uint16 kDnsPort = 53;
+
+//-----------------------------------------------------------------------------
+// Query/response set for www.google.com, ID is fixed to 1.
+
+static const uint16 kT1Qtype = kDNS_A;
+
+static const char kT1DnsName[] = {
+ 0x03, 'w', 'w', 'w',
+ 0x06, 'g', 'o', 'o', 'g', 'l', 'e',
+ 0x03, 'c', 'o', 'm',
+ 0x00
+};
+
+static const uint8 kT1QueryDatagram[] = {
+ // query for www.google.com, type A.
+ 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77,
+ 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03,
+ 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01
+};
+
+static const uint8 kT1ResponseDatagram[] = {
+ // response contains one CNAME for www.l.google.com and the following
+ // IP addresses: 74.125.226.{179,180,176,177,178}
+ 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x06,
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77,
+ 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03,
+ 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01,
+ 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00, 0x01,
+ 0x4d, 0x13, 0x00, 0x08, 0x03, 0x77, 0x77, 0x77,
+ 0x01, 0x6c, 0xc0, 0x10, 0xc0, 0x2c, 0x00, 0x01,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x04,
+ 0x4a, 0x7d, 0xe2, 0xb3, 0xc0, 0x2c, 0x00, 0x01,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x04,
+ 0x4a, 0x7d, 0xe2, 0xb4, 0xc0, 0x2c, 0x00, 0x01,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x04,
+ 0x4a, 0x7d, 0xe2, 0xb0, 0xc0, 0x2c, 0x00, 0x01,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x04,
+ 0x4a, 0x7d, 0xe2, 0xb1, 0xc0, 0x2c, 0x00, 0x01,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x04,
+ 0x4a, 0x7d, 0xe2, 0xb2
+};
+
+static const char* const kT1IpAddresses[] = {
+ "74.125.226.179", "74.125.226.180", "74.125.226.176",
+ "74.125.226.177", "74.125.226.178"
+};
+
+//-----------------------------------------------------------------------------
+// Query/response set for codereview.chromium.org, ID is fixed to 2.
+static const uint16 kT2Qtype = kDNS_A;
+
+static const char kT2DnsName[] = {
+ 0x12, 'c', 'o', 'd', 'e', 'r', 'e', 'v', 'i', 'e', 'w',
+ 0x10, 'c', 'h', 'r', 'o', 'm', 'i', 'u', 'm',
+ 0x03, 'o', 'r', 'g',
+ 0x00
+};
+
+static const uint8 kT2QueryDatagram[] = {
+ // query for codereview.chromium.org, type A.
+ 0x00, 0x02, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0a, 0x63, 0x6f, 0x64,
+ 0x65, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x08,
+ 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x69, 0x75, 0x6d,
+ 0x03, 0x6f, 0x72, 0x67, 0x00, 0x00, 0x01, 0x00,
+ 0x01
+};
+
+static const uint8 kT2ResponseDatagram[] = {
+ // response contains one CNAME for ghs.l.google.com and the following
+ // IP address: 64.233.169.121
+ 0x00, 0x02, 0x81, 0x80, 0x00, 0x01, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x00, 0x0a, 0x63, 0x6f, 0x64,
+ 0x65, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x08,
+ 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x69, 0x75, 0x6d,
+ 0x03, 0x6f, 0x72, 0x67, 0x00, 0x00, 0x01, 0x00,
+ 0x01, 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00,
+ 0x01, 0x41, 0x75, 0x00, 0x12, 0x03, 0x67, 0x68,
+ 0x73, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, 0x67,
+ 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0xc0,
+ 0x35, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01,
+ 0x0b, 0x00, 0x04, 0x40, 0xe9, 0xa9, 0x79
+};
+
+//-----------------------------------------------------------------------------
+
+} // namespace net
+
+#endif // NET_BASE_DNS_TEST_UTIL_H_
diff --git a/net/base/dns_transaction.cc b/net/base/dns_transaction.cc
index 7710b96..88a6268 100644
--- a/net/base/dns_transaction.cc
+++ b/net/base/dns_transaction.cc
@@ -23,15 +23,43 @@ const int kMaxAttempts = arraysize(kTimeoutsMs);
}
+DnsTransaction::Delegate::Delegate() {
+}
+
+DnsTransaction::Delegate::~Delegate() {
+ while (!registered_transactions_.empty()) {
+ DnsTransaction* transaction = *registered_transactions_.begin();
+ transaction->SetDelegate(NULL);
+ }
+ DCHECK(registered_transactions_.empty());
+}
+
+void DnsTransaction::Delegate::OnTransactionComplete(
+ int result,
+ const DnsTransaction* transaction,
+ const IPAddressList& ip_addresses) {
+}
+
+void DnsTransaction::Delegate::Attach(DnsTransaction* transaction) {
+ DCHECK(registered_transactions_.find(transaction) ==
+ registered_transactions_.end());
+ registered_transactions_.insert(transaction);
+}
+
+void DnsTransaction::Delegate::Detach(DnsTransaction* transaction) {
+ DCHECK(registered_transactions_.find(transaction) !=
+ registered_transactions_.end());
+ registered_transactions_.erase(transaction);
+}
+
DnsTransaction::DnsTransaction(const IPEndPoint& dns_server,
const std::string& dns_name,
uint16 query_type,
- std::vector<IPAddressNumber>* results,
const RandIntCallback& rand_int,
ClientSocketFactory* socket_factory)
: dns_server_(dns_server),
- results_(results),
- user_callback_(NULL),
+ key_(dns_name, query_type),
+ delegate_(NULL),
query_(new DnsQuery(dns_name, query_type, rand_int)),
attempts_(0),
next_state_(STATE_NONE),
@@ -39,23 +67,29 @@ DnsTransaction::DnsTransaction(const IPEndPoint& dns_server,
ClientSocketFactory::GetDefaultFactory()),
ALLOW_THIS_IN_INITIALIZER_LIST(
io_callback_(this, &DnsTransaction::OnIOComplete)) {
- DCHECK(results);
DCHECK(!rand_int.is_null());
for (size_t i = 0; i < arraysize(kTimeoutsMs); ++i)
timeouts_ms_.push_back(base::TimeDelta::FromMilliseconds(kTimeoutsMs[i]));
}
DnsTransaction::~DnsTransaction() {
+ SetDelegate(NULL);
+}
+
+void DnsTransaction::SetDelegate(Delegate* delegate) {
+ if (delegate == delegate_)
+ return;
+ if (delegate_)
+ delegate_->Detach(this);
+ delegate_ = delegate;
+ if (delegate_)
+ delegate_->Attach(this);
}
-int DnsTransaction::Start(CompletionCallback* callback) {
- DCHECK(callback);
+int DnsTransaction::Start() {
DCHECK_EQ(STATE_NONE, next_state_);
next_state_ = STATE_CONNECT;
- int rv = DoLoop(OK);
- if (rv == ERR_IO_PENDING)
- user_callback_ = callback;
- return rv;
+ return DoLoop(OK);
}
int DnsTransaction::DoLoop(int result) {
@@ -94,10 +128,8 @@ int DnsTransaction::DoLoop(int result) {
void DnsTransaction::DoCallback(int result) {
DCHECK_NE(result, ERR_IO_PENDING);
- DCHECK(user_callback_);
- CompletionCallback* callback = user_callback_;
- user_callback_ = NULL;
- callback->Run(result);
+ if (delegate_)
+ delegate_->OnTransactionComplete(result, this, ip_addresses_);
}
void DnsTransaction::OnIOComplete(int result) {
@@ -109,10 +141,7 @@ void DnsTransaction::OnIOComplete(int result) {
int DnsTransaction::DoConnect() {
next_state_ = STATE_CONNECT_COMPLETE;
- DCHECK_LE(attempts_, timeouts_ms_.size());
- if (attempts_ == timeouts_ms_.size())
- return ERR_DNS_TIMED_OUT;
-
+ DCHECK_LT(attempts_, timeouts_ms_.size());
StartTimer(timeouts_ms_[attempts_]);
attempts_++;
@@ -169,7 +198,7 @@ int DnsTransaction::DoReadResponseComplete(int rv) {
DCHECK(rv);
// TODO(agayev): when supporting EDNS0 we may need to do multiple reads
// to read the whole response.
- return response_->Parse(rv, results_);
+ return response_->Parse(rv, &ip_addresses_);
}
void DnsTransaction::StartTimer(base::TimeDelta delay) {
@@ -183,6 +212,10 @@ void DnsTransaction::RevokeTimer() {
void DnsTransaction::OnTimeout() {
DCHECK(next_state_ == STATE_SEND_QUERY_COMPLETE ||
next_state_ == STATE_READ_RESPONSE_COMPLETE);
+ if (attempts_ == timeouts_ms_.size()) {
+ DoCallback(ERR_DNS_TIMED_OUT);
+ return;
+ }
next_state_ = STATE_CONNECT;
query_.reset(query_->CloneWithNewId());
int rv = DoLoop(OK);
diff --git a/net/base/dns_transaction.h b/net/base/dns_transaction.h
index 5107724..8f94924 100644
--- a/net/base/dns_transaction.h
+++ b/net/base/dns_transaction.h
@@ -6,9 +6,12 @@
#define NET_BASE_DNS_TRANSACTION_H_
#pragma once
+#include <set>
#include <string>
+#include <utility>
#include <vector>
+#include "base/basictypes.h"
#include "base/scoped_ptr.h"
#include "base/time.h"
#include "base/timer.h"
@@ -31,23 +34,51 @@ class DatagramClientSocket;
// parsing and returning the IP addresses that it matches.
class NET_TEST DnsTransaction : NON_EXPORTED_BASE(public base::NonThreadSafe) {
public:
+ typedef std::pair<std::string, uint16> Key;
+
+ // Interface that should implemented by DnsTransaction consumer and
+ // passed to |Start| method to be notified when the transaction has
+ // completed.
+ class NET_TEST Delegate {
+ public:
+ Delegate();
+ virtual ~Delegate();
+
+ // A consumer of DnsTransaction should override |OnTransactionComplete|
+ // and call |set_delegate(this)|. The method will be called once the
+ // resolution has completed, results passed in as arguments.
+ virtual void OnTransactionComplete(
+ int result,
+ const DnsTransaction* transaction,
+ const IPAddressList& ip_addresses);
+
+ private:
+ friend class DnsTransaction;
+
+ void Attach(DnsTransaction* transaction);
+ void Detach(DnsTransaction* transaction);
+
+ std::set<DnsTransaction*> registered_transactions_;
+
+ DISALLOW_COPY_AND_ASSIGN(Delegate);
+ };
+
// |dns_server| is the address of the DNS server, |dns_name| is the
// hostname (in DNS format) to be resolved, |query_type| is the type of
- // the query, either kDNS_A or kDNS_AAAA, |results| is where the IPs in
- // the response are stored, |rand_int| is the PRNG used for generating
- // DNS query IDs.
+ // the query, either kDNS_A or kDNS_AAAA, |rand_int| is the PRNG used for
+ // generating DNS query.
DnsTransaction(const IPEndPoint& dns_server,
const std::string& dns_name,
uint16 query_type,
- std::vector<IPAddressNumber>* results,
const RandIntCallback& rand_int,
ClientSocketFactory* socket_factory);
~DnsTransaction();
+ void SetDelegate(Delegate* delegate);
+ const Key& key() const { return key_; }
// Starts the resolution process. Will return ERR_IO_PENDING and will
- // notify the caller via |callback| once the resolution is complete.
- // Should only be called once.
- int Start(CompletionCallback* callback);
+ // notify the caller via |delegate|. Should only be called once.
+ int Start();
private:
FRIEND_TEST_ALL_PREFIXES(DnsTransactionTest, FirstTimeoutTest);
@@ -85,8 +116,9 @@ class NET_TEST DnsTransaction : NON_EXPORTED_BASE(public base::NonThreadSafe) {
void set_timeouts_ms(const std::vector<base::TimeDelta>& timeouts_ms);
const IPEndPoint dns_server_;
- std::vector<IPAddressNumber>* results_;
- CompletionCallback* user_callback_;
+ Key key_;
+ IPAddressList ip_addresses_;
+ Delegate* delegate_;
scoped_ptr<DnsQuery> query_;
scoped_ptr<DnsResponse> response_;
diff --git a/net/base/dns_transaction_unittest.cc b/net/base/dns_transaction_unittest.cc
index f51b1ca..4a49952 100644
--- a/net/base/dns_transaction_unittest.cc
+++ b/net/base/dns_transaction_unittest.cc
@@ -8,134 +8,51 @@
#include "base/rand_util.h"
#include "net/base/dns_transaction.h"
#include "net/base/dns_query.h"
-#include "net/base/dns_util.h"
-#include "net/base/ip_endpoint.h"
-#include "net/base/net_util.h"
-#include "net/base/test_completion_callback.h"
+#include "net/base/dns_test_util.h"
#include "net/socket/socket_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
namespace net {
namespace {
-int TestRng1(int /* min */, int /* max */) { return 1; }
-
-std::vector<IPAddressNumber> CStringsToIPAddressList(
- const char* const ip_strings[], size_t size) {
- std::vector<IPAddressNumber> ip_addresses;
- for (size_t i = 0; i < size; ++i) {
- IPAddressNumber ip;
- EXPECT_TRUE(ParseIPLiteralToNumber(ip_strings[i], &ip));
- ip_addresses.push_back(ip);
- }
- return ip_addresses;
-}
-
-IPEndPoint CreateDnsAddress(const char* ip_string, uint16 port) {
- IPAddressNumber ip_address;
- DCHECK(ParseIPLiteralToNumber(ip_string, &ip_address));
- return IPEndPoint(ip_address, port);
-}
-
-static const char* kDnsIp = "192.168.1.1";
-static const uint16 kDnsPort = 53;
static const base::TimeDelta kTimeoutsMs[] = {
base::TimeDelta::FromMilliseconds(20),
base::TimeDelta::FromMilliseconds(20),
base::TimeDelta::FromMilliseconds(20),
};
-//-----------------------------------------------------------------------------
-// Query/response set for www.google.com, ID is fixed to 1.
-
-static const uint16 kT1Qtype = kDNS_A;
-
-static const char kT1DnsName[] = {
- 0x03, 'w', 'w', 'w',
- 0x06, 'g', 'o', 'o', 'g', 'l', 'e',
- 0x03, 'c', 'o', 'm',
- 0x00
-};
-
-static const uint8 kT1QueryDatagram[] = {
- // query for www.google.com, type A.
- 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77,
- 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03,
- 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01
-};
-
-static const uint8 kT1ResponseDatagram[] = {
- // response contains one CNAME for www.l.google.com and the following
- // IP addresses: 74.125.226.{179,180,176,177,178}
- 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x06,
- 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77,
- 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03,
- 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01,
- 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00, 0x01,
- 0x4d, 0x13, 0x00, 0x08, 0x03, 0x77, 0x77, 0x77,
- 0x01, 0x6c, 0xc0, 0x10, 0xc0, 0x2c, 0x00, 0x01,
- 0x00, 0x01, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x04,
- 0x4a, 0x7d, 0xe2, 0xb3, 0xc0, 0x2c, 0x00, 0x01,
- 0x00, 0x01, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x04,
- 0x4a, 0x7d, 0xe2, 0xb4, 0xc0, 0x2c, 0x00, 0x01,
- 0x00, 0x01, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x04,
- 0x4a, 0x7d, 0xe2, 0xb0, 0xc0, 0x2c, 0x00, 0x01,
- 0x00, 0x01, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x04,
- 0x4a, 0x7d, 0xe2, 0xb1, 0xc0, 0x2c, 0x00, 0x01,
- 0x00, 0x01, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x04,
- 0x4a, 0x7d, 0xe2, 0xb2
-};
-
-static const char* const kT1IpAddresses[] = {
- "74.125.226.179", "74.125.226.180", "74.125.226.176",
- "74.125.226.177", "74.125.226.178"
-};
-
-//-----------------------------------------------------------------------------
-// Query/response set for codereview.chromium.org, ID is fixed to 2.
-static const uint16 kT2Qtype = kDNS_A;
+} // namespace
-static const char kT2DnsName[] = {
- 0x12, 'c', 'o', 'd', 'e', 'r', 'e', 'v', 'i', 'e', 'w',
- 0x10, 'c', 'h', 'r', 'o', 'm', 'i', 'u', 'm',
- 0x03, 'o', 'r', 'g',
- 0x00
-};
+class TestDelegate : public DnsTransaction::Delegate {
+ public:
+ TestDelegate() : result_(ERR_UNEXPECTED), transaction_(NULL) {}
+ virtual ~TestDelegate() {}
+ virtual void OnTransactionComplete(
+ int result,
+ const DnsTransaction* transaction,
+ const IPAddressList& ip_addresses) {
+ result_ = result;
+ transaction_ = transaction;
+ ip_addresses_ = ip_addresses;
+ MessageLoop::current()->Quit();
+ }
+ int result() const { return result_; }
+ const DnsTransaction* transaction() const { return transaction_; }
+ const IPAddressList& ip_addresses() const {
+ return ip_addresses_;
+ }
-static const uint8 kT2QueryDatagram[] = {
- // query for codereview.chromium.org, type A.
- 0x00, 0x02, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x0a, 0x63, 0x6f, 0x64,
- 0x65, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x08,
- 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x69, 0x75, 0x6d,
- 0x03, 0x6f, 0x72, 0x67, 0x00, 0x00, 0x01, 0x00,
- 0x01
-};
+ private:
+ int result_;
+ const DnsTransaction* transaction_;
+ IPAddressList ip_addresses_;
-static const uint8 kT2ResponseDatagram[] = {
- // response contains one CNAME for ghs.l.google.com and the following
- // IP address: 64.233.169.121
- 0x00, 0x02, 0x81, 0x80, 0x00, 0x01, 0x00, 0x02,
- 0x00, 0x00, 0x00, 0x00, 0x0a, 0x63, 0x6f, 0x64,
- 0x65, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x08,
- 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x69, 0x75, 0x6d,
- 0x03, 0x6f, 0x72, 0x67, 0x00, 0x00, 0x01, 0x00,
- 0x01, 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00,
- 0x01, 0x41, 0x75, 0x00, 0x12, 0x03, 0x67, 0x68,
- 0x73, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, 0x67,
- 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0xc0,
- 0x35, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01,
- 0x0b, 0x00, 0x04, 0x40, 0xe9, 0xa9, 0x79
+ DISALLOW_COPY_AND_ASSIGN(TestDelegate);
};
-//-----------------------------------------------------------------------------
-
-} // namespace
-TEST(DnsTransactionTest, NormalQueryResponseTest1) {
+TEST(DnsTransactionTest, NormalQueryResponseTest) {
MockWrite writes1[] = {
MockWrite(true, reinterpret_cast<const char*>(kT1QueryDatagram),
arraysize(kT1QueryDatagram))
@@ -151,24 +68,38 @@ TEST(DnsTransactionTest, NormalQueryResponseTest1) {
MockClientSocketFactory factory;
factory.AddSocketDataProvider(&data);
- std::vector<IPAddressNumber> actual_ip_addresses;
- std::vector<IPAddressNumber> expected_ip_addresses =
- CStringsToIPAddressList(kT1IpAddresses, arraysize(kT1IpAddresses));
-
- DnsTransaction t(CreateDnsAddress(kDnsIp, kDnsPort),
- std::string(kT1DnsName, arraysize(kT1DnsName)),
- kT1Qtype,
- &actual_ip_addresses,
- base::Bind(&TestRng1),
- &factory);
- TestCompletionCallback callback;
- int rv = t.Start(&callback);
+ TestPrng test_prng(std::deque<int>(1, 1));
+ RandIntCallback rand_int_cb =
+ base::Bind(&TestPrng::GetNext, base::Unretained(&test_prng));
+ std::string t1_dns_name(kT1DnsName, arraysize(kT1DnsName));
+
+ IPEndPoint dns_server;
+ bool rv0 = CreateDnsAddress(kDnsIp, kDnsPort, &dns_server);
+ ASSERT_TRUE(rv0);
+
+ DnsTransaction t(dns_server, t1_dns_name, kT1Qtype, rand_int_cb, &factory);
+
+ TestDelegate delegate;
+ t.SetDelegate(&delegate);
+
+ IPAddressList expected_ip_addresses;
+ rv0 = ConvertStringsToIPAddressList(kT1IpAddresses,
+ arraysize(kT1IpAddresses),
+ &expected_ip_addresses);
+ ASSERT_TRUE(rv0);
+
+ int rv = t.Start();
EXPECT_EQ(ERR_IO_PENDING, rv);
- rv = callback.WaitForResult();
+
+ MessageLoop::current()->Run();
+
+ EXPECT_TRUE(DnsTransaction::Key(t1_dns_name, kT1Qtype) == t.key());
+ EXPECT_EQ(OK, delegate.result());
+ EXPECT_EQ(&t, delegate.transaction());
+ EXPECT_TRUE(expected_ip_addresses == delegate.ip_addresses());
+
EXPECT_TRUE(data.at_read_eof());
EXPECT_TRUE(data.at_write_eof());
-
- EXPECT_TRUE(actual_ip_addresses == expected_ip_addresses);
}
TEST(DnsTransactionTest, MismatchedQueryResponseTest) {
@@ -187,21 +118,31 @@ TEST(DnsTransactionTest, MismatchedQueryResponseTest) {
MockClientSocketFactory factory;
factory.AddSocketDataProvider(&data);
- std::vector<IPAddressNumber> ip_addresses;
- DnsTransaction t(CreateDnsAddress(kDnsIp, kDnsPort),
- std::string(kT1DnsName, arraysize(kT1DnsName)),
- kT1Qtype,
- &ip_addresses,
- base::Bind(&TestRng1),
- &factory);
- TestCompletionCallback callback;
- int rv = t.Start(&callback);
+ TestPrng test_prng(std::deque<int>(1, 1));
+ RandIntCallback rand_int_cb =
+ base::Bind(&TestPrng::GetNext, base::Unretained(&test_prng));
+ std::string t1_dns_name(kT1DnsName, arraysize(kT1DnsName));
+
+ IPEndPoint dns_server;
+ bool rv0 = CreateDnsAddress(kDnsIp, kDnsPort, &dns_server);
+ ASSERT_TRUE(rv0);
+
+ DnsTransaction t(dns_server, t1_dns_name, kT1Qtype, rand_int_cb, &factory);
+
+ TestDelegate delegate;
+ t.SetDelegate(&delegate);
+
+ int rv = t.Start();
EXPECT_EQ(ERR_IO_PENDING, rv);
- rv = callback.WaitForResult();
+
+ MessageLoop::current()->Run();
+
+ EXPECT_TRUE(DnsTransaction::Key(t1_dns_name, kT1Qtype) == t.key());
+ EXPECT_EQ(ERR_DNS_MALFORMED_RESPONSE, delegate.result());
+ EXPECT_EQ(0u, delegate.ip_addresses().size());
+ EXPECT_EQ(&t, delegate.transaction());
EXPECT_TRUE(data.at_read_eof());
EXPECT_TRUE(data.at_write_eof());
-
- EXPECT_EQ(ERR_DNS_MALFORMED_RESPONSE, rv);
}
// Test that after the first timeout we do a fresh connection and if we get
@@ -226,32 +167,45 @@ TEST(DnsTransactionTest, FirstTimeoutTest) {
factory.AddSocketDataProvider(socket1_data.get());
factory.AddSocketDataProvider(socket2_data.get());
- std::vector<IPAddressNumber> expected_ip_addresses =
- CStringsToIPAddressList(kT1IpAddresses, arraysize(kT1IpAddresses));
-
- std::vector<IPAddressNumber> actual_ip_addresses;
- DnsTransaction transaction(CreateDnsAddress(kDnsIp, kDnsPort),
- std::string(kT1DnsName, arraysize(kT1DnsName)),
- kT1Qtype,
- &actual_ip_addresses,
- base::Bind(&TestRng1),
- &factory);
- transaction.set_timeouts_ms(
+ TestPrng test_prng(std::deque<int>(2, 1));
+ RandIntCallback rand_int_cb =
+ base::Bind(&TestPrng::GetNext, base::Unretained(&test_prng));
+ std::string t1_dns_name(kT1DnsName, arraysize(kT1DnsName));
+
+ IPEndPoint dns_server;
+ bool rv0 = CreateDnsAddress(kDnsIp, kDnsPort, &dns_server);
+ ASSERT_TRUE(rv0);
+
+ DnsTransaction t(dns_server, t1_dns_name, kT1Qtype, rand_int_cb, &factory);
+
+ TestDelegate delegate;
+ t.SetDelegate(&delegate);
+
+ t.set_timeouts_ms(
std::vector<base::TimeDelta>(kTimeoutsMs,
kTimeoutsMs + arraysize(kTimeoutsMs)));
- TestCompletionCallback callback;
- int rv = transaction.Start(&callback);
+ IPAddressList expected_ip_addresses;
+ rv0 = ConvertStringsToIPAddressList(kT1IpAddresses,
+ arraysize(kT1IpAddresses),
+ &expected_ip_addresses);
+ ASSERT_TRUE(rv0);
+
+ int rv = t.Start();
EXPECT_EQ(ERR_IO_PENDING, rv);
- rv = callback.WaitForResult();
+
+ MessageLoop::current()->Run();
+
+ EXPECT_TRUE(DnsTransaction::Key(t1_dns_name, kT1Qtype) == t.key());
+ EXPECT_EQ(OK, delegate.result());
+ EXPECT_EQ(&t, delegate.transaction());
+ EXPECT_TRUE(expected_ip_addresses == delegate.ip_addresses());
EXPECT_TRUE(socket1_data->at_read_eof());
EXPECT_TRUE(socket1_data->at_write_eof());
EXPECT_TRUE(socket2_data->at_read_eof());
EXPECT_TRUE(socket2_data->at_write_eof());
EXPECT_EQ(2u, factory.udp_client_sockets().size());
-
- EXPECT_TRUE(actual_ip_addresses == expected_ip_addresses);
}
// Test that after the first timeout we do a fresh connection, and after
@@ -280,24 +234,39 @@ TEST(DnsTransactionTest, SecondTimeoutTest) {
factory.AddSocketDataProvider(socket2_data.get());
factory.AddSocketDataProvider(socket3_data.get());
- std::vector<IPAddressNumber> expected_ip_addresses =
- CStringsToIPAddressList(kT1IpAddresses, arraysize(kT1IpAddresses));
-
- std::vector<IPAddressNumber> actual_ip_addresses;
- DnsTransaction transaction(CreateDnsAddress(kDnsIp, kDnsPort),
- std::string(kT1DnsName, arraysize(kT1DnsName)),
- kT1Qtype,
- &actual_ip_addresses,
- base::Bind(&TestRng1),
- &factory);
- transaction.set_timeouts_ms(
+ TestPrng test_prng(std::deque<int>(3, 1));
+ RandIntCallback rand_int_cb =
+ base::Bind(&TestPrng::GetNext, base::Unretained(&test_prng));
+ std::string t1_dns_name(kT1DnsName, arraysize(kT1DnsName));
+
+ IPEndPoint dns_server;
+ bool rv0 = CreateDnsAddress(kDnsIp, kDnsPort, &dns_server);
+ ASSERT_TRUE(rv0);
+
+ DnsTransaction t(dns_server, t1_dns_name, kT1Qtype, rand_int_cb, &factory);
+
+ TestDelegate delegate;
+ t.SetDelegate(&delegate);
+
+ t.set_timeouts_ms(
std::vector<base::TimeDelta>(kTimeoutsMs,
kTimeoutsMs + arraysize(kTimeoutsMs)));
- TestCompletionCallback callback;
- int rv = transaction.Start(&callback);
+ IPAddressList expected_ip_addresses;
+ rv0 = ConvertStringsToIPAddressList(kT1IpAddresses,
+ arraysize(kT1IpAddresses),
+ &expected_ip_addresses);
+ ASSERT_TRUE(rv0);
+
+ int rv = t.Start();
EXPECT_EQ(ERR_IO_PENDING, rv);
- rv = callback.WaitForResult();
+
+ MessageLoop::current()->Run();
+
+ EXPECT_TRUE(DnsTransaction::Key(t1_dns_name, kT1Qtype) == t.key());
+ EXPECT_EQ(OK, delegate.result());
+ EXPECT_EQ(&t, delegate.transaction());
+ EXPECT_TRUE(expected_ip_addresses == delegate.ip_addresses());
EXPECT_TRUE(socket1_data->at_read_eof());
EXPECT_TRUE(socket1_data->at_write_eof());
@@ -306,8 +275,6 @@ TEST(DnsTransactionTest, SecondTimeoutTest) {
EXPECT_TRUE(socket3_data->at_read_eof());
EXPECT_TRUE(socket3_data->at_write_eof());
EXPECT_EQ(3u, factory.udp_client_sockets().size());
-
- EXPECT_TRUE(actual_ip_addresses == expected_ip_addresses);
}
// Test that after the first timeout we do a fresh connection, and after
@@ -330,24 +297,32 @@ TEST(DnsTransactionTest, ThirdTimeoutTest) {
factory.AddSocketDataProvider(socket2_data.get());
factory.AddSocketDataProvider(socket3_data.get());
- std::vector<IPAddressNumber> expected_ip_addresses =
- CStringsToIPAddressList(kT1IpAddresses, arraysize(kT1IpAddresses));
-
- std::vector<IPAddressNumber> actual_ip_addresses;
- DnsTransaction transaction(CreateDnsAddress(kDnsIp, kDnsPort),
- std::string(kT1DnsName, arraysize(kT1DnsName)),
- kT1Qtype,
- &actual_ip_addresses,
- base::Bind(&TestRng1),
- &factory);
- transaction.set_timeouts_ms(
+ TestPrng test_prng(std::deque<int>(3, 1));
+ RandIntCallback rand_int_cb =
+ base::Bind(&TestPrng::GetNext, base::Unretained(&test_prng));
+ std::string t1_dns_name(kT1DnsName, arraysize(kT1DnsName));
+
+ IPEndPoint dns_server;
+ bool rv0 = CreateDnsAddress(kDnsIp, kDnsPort, &dns_server);
+ ASSERT_TRUE(rv0);
+
+ DnsTransaction t(dns_server, t1_dns_name, kT1Qtype, rand_int_cb, &factory);
+
+ TestDelegate delegate;
+ t.SetDelegate(&delegate);
+
+ t.set_timeouts_ms(
std::vector<base::TimeDelta>(kTimeoutsMs,
kTimeoutsMs + arraysize(kTimeoutsMs)));
- TestCompletionCallback callback;
- int rv = transaction.Start(&callback);
+ int rv = t.Start();
EXPECT_EQ(ERR_IO_PENDING, rv);
- rv = callback.WaitForResult();
+
+ MessageLoop::current()->Run();
+
+ EXPECT_TRUE(DnsTransaction::Key(t1_dns_name, kT1Qtype) == t.key());
+ EXPECT_EQ(ERR_DNS_TIMED_OUT, delegate.result());
+ EXPECT_EQ(&t, delegate.transaction());
EXPECT_TRUE(socket1_data->at_read_eof());
EXPECT_TRUE(socket1_data->at_write_eof());
@@ -356,8 +331,6 @@ TEST(DnsTransactionTest, ThirdTimeoutTest) {
EXPECT_TRUE(socket3_data->at_read_eof());
EXPECT_TRUE(socket3_data->at_write_eof());
EXPECT_EQ(3u, factory.udp_client_sockets().size());
-
- EXPECT_EQ(ERR_DNS_TIMED_OUT, rv);
}
} // namespace net
diff --git a/net/base/net_util.h b/net/base/net_util.h
index a0a6ba8..344a990 100644
--- a/net/base/net_util.h
+++ b/net/base/net_util.h
@@ -366,6 +366,7 @@ bool HaveOnlyLoopbackAddresses();
//
// IPv4 addresses will have length 4, whereas IPv6 address will have length 16.
typedef std::vector<unsigned char> IPAddressNumber;
+typedef std::vector<IPAddressNumber> IPAddressList;
static const size_t kIPv4AddressSize = 4;
static const size_t kIPv6AddressSize = 16;