diff options
author | agayev@chromium.org <agayev@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-07-18 15:12:46 +0000 |
---|---|---|
committer | agayev@chromium.org <agayev@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-07-18 15:12:46 +0000 |
commit | d391116230f8281484ef7c339f18f5e8b9692a8b (patch) | |
tree | af189ad77b3dc7e7d0c14a1a94ca78d1bf614ce9 /net | |
parent | bafa00e4fda7ae133485a8b3112e8c942dd58aa3 (diff) | |
download | chromium_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')
-rw-r--r-- | net/base/address_list.cc | 4 | ||||
-rw-r--r-- | net/base/address_list.h | 2 | ||||
-rw-r--r-- | net/base/address_list_unittest.cc | 2 | ||||
-rw-r--r-- | net/base/dns_response.cc | 4 | ||||
-rw-r--r-- | net/base/dns_response.h | 2 | ||||
-rw-r--r-- | net/base/dns_response_unittest.cc | 4 | ||||
-rw-r--r-- | net/base/dns_test_util.cc | 49 | ||||
-rw-r--r-- | net/base/dns_test_util.h | 137 | ||||
-rw-r--r-- | net/base/dns_transaction.cc | 71 | ||||
-rw-r--r-- | net/base/dns_transaction.h | 50 | ||||
-rw-r--r-- | net/base/dns_transaction_unittest.cc | 341 | ||||
-rw-r--r-- | net/base/net_util.h | 1 | ||||
-rw-r--r-- | net/net.gyp | 6 |
13 files changed, 450 insertions, 223 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; diff --git a/net/net.gyp b/net/net.gyp index 31afc17..f9e62fa 100644 --- a/net/net.gyp +++ b/net/net.gyp @@ -72,9 +72,9 @@ 'base/dns_query.cc', 'base/dns_query.h', 'base/dns_response.cc', - 'base/dns_transaction.h', - 'base/dns_transaction.cc', 'base/dns_response.h', + 'base/dns_transaction.cc', + 'base/dns_transaction.h', 'base/dns_reload_timer.cc', 'base/dns_reload_timer.h', 'base/dnssec_chain_verifier.cc', @@ -1185,6 +1185,8 @@ 'base/cert_test_util.h', 'base/cookie_monster_store_test.cc', 'base/cookie_monster_store_test.h', + 'base/dns_test_util.cc', + 'base/dns_test_util.h', 'base/net_test_suite.cc', 'base/net_test_suite.h', 'base/test_completion_callback.cc', |