summaryrefslogtreecommitdiffstats
path: root/net/dns/dns_transaction_unittest.cc
diff options
context:
space:
mode:
authorszym@chromium.org <szym@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-12-20 20:44:59 +0000
committerszym@chromium.org <szym@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-12-20 20:44:59 +0000
commitbdb65984076da8c0d0a2f5fe04b46885f9a21ccc (patch)
tree8c081dd3390157af83237927a10febabc6b65b05 /net/dns/dns_transaction_unittest.cc
parent6ab42d98f29848fc1210a39fb8d47ced24a42ea7 (diff)
downloadchromium_src-bdb65984076da8c0d0a2f5fe04b46885f9a21ccc.zip
chromium_src-bdb65984076da8c0d0a2f5fe04b46885f9a21ccc.tar.gz
chromium_src-bdb65984076da8c0d0a2f5fe04b46885f9a21ccc.tar.bz2
[net/dns] Handle TC bit on DNS response in DnsTransaction.
Adds DnsTCPAttempt. This implementation does not reuse TCP sockets nor share them across concurrent DNS over TCP transactions. BUG=116785 TEST=net_unittests --gtest_filter=DnsTransactionTest.TCP* Review URL: https://chromiumcodereview.appspot.com/11567031 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@174227 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/dns/dns_transaction_unittest.cc')
-rw-r--r--net/dns/dns_transaction_unittest.cc144
1 files changed, 114 insertions, 30 deletions
diff --git a/net/dns/dns_transaction_unittest.cc b/net/dns/dns_transaction_unittest.cc
index abfcf07..9184023 100644
--- a/net/dns/dns_transaction_unittest.cc
+++ b/net/dns/dns_transaction_unittest.cc
@@ -31,28 +31,57 @@ std::string DomainFromDot(const base::StringPiece& dotted) {
return out;
}
-// A SocketDataProvider builder for MockUDPClientSocket. Each socket used by a
-// DnsTransaction expects only one write and zero or more reads.
+// A SocketDataProvider builder.
class DnsSocketData {
public:
// The ctor takes parameters for the DnsQuery.
- DnsSocketData(uint16 id, const char* dotted_name, uint16 qtype, IoMode mode)
+ DnsSocketData(uint16 id,
+ const char* dotted_name,
+ uint16 qtype,
+ IoMode mode,
+ bool use_tcp)
: query_(new DnsQuery(id, DomainFromDot(dotted_name), qtype)),
- write_(mode, query_->io_buffer()->data(), query_->io_buffer()->size()) {
+ use_tcp_(use_tcp) {
+ if (use_tcp_) {
+ scoped_ptr<uint16> length(new uint16);
+ *length = base::HostToNet16(query_->io_buffer()->size());
+ writes_.push_back(MockWrite(mode,
+ reinterpret_cast<const char*>(length.get()),
+ sizeof(uint16)));
+ lengths_.push_back(length.release());
+ }
+ writes_.push_back(MockWrite(mode,
+ query_->io_buffer()->data(),
+ query_->io_buffer()->size()));
}
~DnsSocketData() {}
// All responses must be added before GetProvider.
- // Add pre-built DnsResponse.
- void AddResponse(scoped_ptr<DnsResponse> response, IoMode mode) {
+ // Adds pre-built DnsResponse. |tcp_length| will be used in TCP mode only.
+ void AddResponseWithLength(scoped_ptr<DnsResponse> response, IoMode mode,
+ uint16 tcp_length) {
CHECK(!provider_.get());
+ if (use_tcp_) {
+ scoped_ptr<uint16> length(new uint16);
+ *length = base::HostToNet16(tcp_length);
+ reads_.push_back(MockRead(mode,
+ reinterpret_cast<const char*>(length.get()),
+ sizeof(uint16)));
+ lengths_.push_back(length.release());
+ }
reads_.push_back(MockRead(mode,
response->io_buffer()->data(),
response->io_buffer()->size()));
responses_.push_back(response.release());
}
+ // Adds pre-built DnsResponse.
+ void AddResponse(scoped_ptr<DnsResponse> response, IoMode mode) {
+ uint16 tcp_length = response->io_buffer()->size();
+ AddResponseWithLength(response.Pass(), mode, tcp_length);
+ }
+
// Adds pre-built response from |data| buffer.
void AddResponseData(const uint8* data, size_t length, IoMode mode) {
CHECK(!provider_.get());
@@ -77,14 +106,13 @@ class DnsSocketData {
SocketDataProvider* GetProvider() {
if (provider_.get())
return provider_.get();
- if (reads_.empty()) {
- // Timeout.
- provider_.reset(new DelayedSocketData(2, NULL, 0, &write_, 1));
- } else {
- // Terminate the reads with ERR_IO_PENDING to prevent overrun.
- reads_.push_back(MockRead(ASYNC, ERR_IO_PENDING));
- provider_.reset(new DelayedSocketData(1, &reads_[0], reads_.size(),
- &write_, 1));
+ // Terminate the reads with ERR_IO_PENDING to prevent overrun and default to
+ // timeout.
+ reads_.push_back(MockRead(ASYNC, ERR_IO_PENDING));
+ provider_.reset(new DelayedSocketData(1, &reads_[0], reads_.size(),
+ &writes_[0], writes_.size()));
+ if (use_tcp_) {
+ provider_->set_connect_data(MockConnect(reads_[0].mode, OK));
}
return provider_.get();
}
@@ -101,8 +129,10 @@ class DnsSocketData {
private:
scoped_ptr<DnsQuery> query_;
+ bool use_tcp_;
+ ScopedVector<uint16> lengths_;
ScopedVector<DnsResponse> responses_;
- MockWrite write_;
+ std::vector<MockWrite> writes_;
std::vector<MockRead> reads_;
scoped_ptr<DelayedSocketData> provider_;
@@ -328,6 +358,7 @@ class DnsTransactionTest : public testing::Test {
}
void AddSocketData(scoped_ptr<DnsSocketData> data) {
+ CHECK(socket_factory_.get());
transaction_ids_.push_back(data->query_id());
socket_factory_->AddSocketDataProvider(data->GetProvider());
socket_data_.push_back(data.release());
@@ -341,10 +372,11 @@ class DnsTransactionTest : public testing::Test {
uint16 qtype,
const uint8* response_data,
size_t response_length,
- IoMode mode) {
+ IoMode mode,
+ bool use_tcp) {
CHECK(socket_factory_.get());
scoped_ptr<DnsSocketData> data(
- new DnsSocketData(id, dotted_name, qtype, mode));
+ new DnsSocketData(id, dotted_name, qtype, mode, use_tcp));
data->AddResponseData(response_data, response_length, mode);
AddSocketData(data.Pass());
}
@@ -354,7 +386,8 @@ class DnsTransactionTest : public testing::Test {
uint16 qtype,
const uint8* data,
size_t data_length) {
- AddQueryAndResponse(id, dotted_name, qtype, data, data_length, ASYNC);
+ AddQueryAndResponse(id, dotted_name, qtype, data, data_length, ASYNC,
+ false);
}
void AddSyncQueryAndResponse(uint16 id,
@@ -362,15 +395,15 @@ class DnsTransactionTest : public testing::Test {
uint16 qtype,
const uint8* data,
size_t data_length) {
- AddQueryAndResponse(id, dotted_name, qtype, data, data_length, SYNCHRONOUS);
+ AddQueryAndResponse(id, dotted_name, qtype, data, data_length, SYNCHRONOUS,
+ false);
}
// Add expected query of |dotted_name| and |qtype| and no response.
void AddQueryAndTimeout(const char* dotted_name, uint16 qtype) {
- CHECK(socket_factory_.get());
uint16 id = base::RandInt(0, kuint16max);
scoped_ptr<DnsSocketData> data(
- new DnsSocketData(id, dotted_name, qtype, ASYNC));
+ new DnsSocketData(id, dotted_name, qtype, ASYNC, false));
AddSocketData(data.Pass());
}
@@ -379,22 +412,22 @@ class DnsTransactionTest : public testing::Test {
void AddQueryAndRcode(const char* dotted_name,
uint16 qtype,
int rcode,
- IoMode mode) {
- CHECK(socket_factory_.get());
+ IoMode mode,
+ bool use_tcp) {
CHECK_NE(dns_protocol::kRcodeNOERROR, rcode);
uint16 id = base::RandInt(0, kuint16max);
scoped_ptr<DnsSocketData> data(
- new DnsSocketData(id, dotted_name, qtype, mode));
+ new DnsSocketData(id, dotted_name, qtype, mode, use_tcp));
data->AddRcode(rcode, mode);
AddSocketData(data.Pass());
}
void AddAsyncQueryAndRcode(const char* dotted_name, uint16 qtype, int rcode) {
- AddQueryAndRcode(dotted_name, qtype, rcode, ASYNC);
+ AddQueryAndRcode(dotted_name, qtype, rcode, ASYNC, false);
}
void AddSyncQueryAndRcode(const char* dotted_name, uint16 qtype, int rcode) {
- AddQueryAndRcode(dotted_name, qtype, rcode, SYNCHRONOUS);
+ AddQueryAndRcode(dotted_name, qtype, rcode, SYNCHRONOUS, false);
}
// Checks if the sockets were connected in the order matching the indices in
@@ -446,7 +479,7 @@ class DnsTransactionTest : public testing::Test {
TEST_F(DnsTransactionTest, Lookup) {
AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
- kT0ResponseDatagram, arraysize(kT0ResponseDatagram));
+ kT0ResponseDatagram, arraysize(kT0ResponseDatagram));
TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
@@ -492,7 +525,7 @@ TEST_F(DnsTransactionTest, CancelLookup) {
TEST_F(DnsTransactionTest, DestroyFactory) {
AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
- kT0ResponseDatagram, arraysize(kT0ResponseDatagram));
+ kT0ResponseDatagram, arraysize(kT0ResponseDatagram));
TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
helper0.StartTransaction(transaction_factory_.get());
@@ -521,7 +554,7 @@ TEST_F(DnsTransactionTest, MismatchedResponseSync) {
// Attempt receives mismatched response followed by valid response.
scoped_ptr<DnsSocketData> data(
- new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, SYNCHRONOUS));
+ new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, SYNCHRONOUS, false));
data->AddResponseData(kT1ResponseDatagram,
arraysize(kT1ResponseDatagram), SYNCHRONOUS);
data->AddResponseData(kT0ResponseDatagram,
@@ -540,7 +573,7 @@ TEST_F(DnsTransactionTest, MismatchedResponseAsync) {
// First attempt receives mismatched response followed by valid response.
// Second attempt times out.
scoped_ptr<DnsSocketData> data(
- new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, ASYNC));
+ new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, ASYNC, false));
data->AddResponseData(kT1ResponseDatagram,
arraysize(kT1ResponseDatagram), ASYNC);
data->AddResponseData(kT0ResponseDatagram,
@@ -831,6 +864,57 @@ TEST_F(DnsTransactionTest, ConnectFailure) {
EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
}
+TEST_F(DnsTransactionTest, TCPLookup) {
+ AddAsyncQueryAndRcode(kT0HostName, kT0Qtype,
+ dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC);
+ AddQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
+ kT0ResponseDatagram, arraysize(kT0ResponseDatagram),
+ ASYNC, true /* use_tcp */);
+
+ TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
+ EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
+}
+
+TEST_F(DnsTransactionTest, TCPFailure) {
+ AddAsyncQueryAndRcode(kT0HostName, kT0Qtype,
+ dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC);
+ AddQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL,
+ ASYNC, true /* use_tcp */);
+
+ TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_SERVER_FAILED);
+ EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
+}
+
+TEST_F(DnsTransactionTest, TCPMalformed) {
+ AddAsyncQueryAndRcode(kT0HostName, kT0Qtype,
+ dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC);
+ scoped_ptr<DnsSocketData> data(
+ new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, ASYNC, true));
+ // Valid response but length too short.
+ data->AddResponseWithLength(
+ make_scoped_ptr(
+ new DnsResponse(reinterpret_cast<const char*>(kT0ResponseDatagram),
+ arraysize(kT0ResponseDatagram), 0)),
+ ASYNC,
+ static_cast<uint16>(kT0QuerySize - 1));
+ AddSocketData(data.Pass());
+
+ TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_MALFORMED_RESPONSE);
+ EXPECT_TRUE(helper0.Run(transaction_factory_.get()));
+}
+
+TEST_F(DnsTransactionTest, TCPTimeout) {
+ config_.timeout = TestTimeouts::tiny_timeout();
+ ConfigureFactory();
+ AddAsyncQueryAndRcode(kT0HostName, kT0Qtype,
+ dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC);
+ AddSocketData(make_scoped_ptr(
+ new DnsSocketData(1 /* id */, kT0HostName, kT0Qtype, ASYNC, true)));
+
+ TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_TIMED_OUT);
+ EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get()));
+}
+
} // namespace
} // namespace net