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.
7 #include "base/memory/ref_counted.h"
8 #include "base/message_loop/message_loop.h"
9 #include "net/base/rand_callback.h"
10 #include "net/base/test_completion_callback.h"
11 #include "net/dns/mdns_client_impl.h"
12 #include "net/dns/mock_mdns_socket_factory.h"
13 #include "net/dns/record_rdata.h"
14 #include "net/udp/udp_client_socket.h"
15 #include "testing/gmock/include/gmock/gmock.h"
16 #include "testing/gtest/include/gtest/gtest.h"
18 using ::testing::Invoke;
19 using ::testing::InvokeWithoutArgs;
20 using ::testing::StrictMock;
21 using ::testing::NiceMock;
22 using ::testing::Exactly;
23 using ::testing::Return;
24 using ::testing::SaveArg;
31 const uint8 kSamplePacket1[] = {
33 0x00, 0x00, // ID is zeroed out
34 0x81, 0x80, // Standard query response, RA, no error
35 0x00, 0x00, // No questions (for simplicity)
36 0x00, 0x02, // 2 RRs (answers)
37 0x00, 0x00, // 0 authority RRs
38 0x00, 0x00, // 0 additional RRs
41 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
42 0x04, '_', 't', 'c', 'p',
43 0x05, 'l', 'o', 'c', 'a', 'l',
45 0x00, 0x0c, // TYPE is PTR.
46 0x00, 0x01, // CLASS is IN.
47 0x00, 0x00, // TTL (4 bytes) is 1 second;
49 0x00, 0x08, // RDLENGTH is 8 bytes.
50 0x05, 'h', 'e', 'l', 'l', 'o',
54 0x08, '_', 'p', 'r', 'i', 'n', 't', 'e', 'r',
55 0xc0, 0x14, // Pointer to "._tcp.local"
56 0x00, 0x0c, // TYPE is PTR.
57 0x00, 0x01, // CLASS is IN.
58 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 49 seconds.
60 0x00, 0x08, // RDLENGTH is 8 bytes.
61 0x05, 'h', 'e', 'l', 'l', 'o',
65 const uint8 kCorruptedPacketBadQuestion[] = {
67 0x00, 0x00, // ID is zeroed out
68 0x81, 0x80, // Standard query response, RA, no error
69 0x00, 0x01, // One question
70 0x00, 0x02, // 2 RRs (answers)
71 0x00, 0x00, // 0 authority RRs
72 0x00, 0x00, // 0 additional RRs
74 // Question is corrupted and cannot be read.
75 0x99, 'h', 'e', 'l', 'l', 'o',
81 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
82 0x04, '_', 't', 'c', 'p',
83 0x05, 'l', 'o', 'c', 'a', 'l',
85 0x00, 0x0c, // TYPE is PTR.
86 0x00, 0x01, // CLASS is IN.
87 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
89 0x00, 0x99, // RDLENGTH is impossible
90 0x05, 'h', 'e', 'l', 'l', 'o',
94 0x08, '_', 'p', 'r', // Useless trailing data.
97 const uint8 kCorruptedPacketUnsalvagable[] = {
99 0x00, 0x00, // ID is zeroed out
100 0x81, 0x80, // Standard query response, RA, no error
101 0x00, 0x00, // No questions (for simplicity)
102 0x00, 0x02, // 2 RRs (answers)
103 0x00, 0x00, // 0 authority RRs
104 0x00, 0x00, // 0 additional RRs
107 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
108 0x04, '_', 't', 'c', 'p',
109 0x05, 'l', 'o', 'c', 'a', 'l',
111 0x00, 0x0c, // TYPE is PTR.
112 0x00, 0x01, // CLASS is IN.
113 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
115 0x00, 0x99, // RDLENGTH is impossible
116 0x05, 'h', 'e', 'l', 'l', 'o',
120 0x08, '_', 'p', 'r', // Useless trailing data.
123 const uint8 kCorruptedPacketDoubleRecord[] = {
125 0x00, 0x00, // ID is zeroed out
126 0x81, 0x80, // Standard query response, RA, no error
127 0x00, 0x00, // No questions (for simplicity)
128 0x00, 0x02, // 2 RRs (answers)
129 0x00, 0x00, // 0 authority RRs
130 0x00, 0x00, // 0 additional RRs
133 0x06, 'p', 'r', 'i', 'v', 'e', 't',
134 0x05, 'l', 'o', 'c', 'a', 'l',
136 0x00, 0x01, // TYPE is A.
137 0x00, 0x01, // CLASS is IN.
138 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
140 0x00, 0x04, // RDLENGTH is 4
144 // Answer 2 -- Same key
145 0x06, 'p', 'r', 'i', 'v', 'e', 't',
146 0x05, 'l', 'o', 'c', 'a', 'l',
148 0x00, 0x01, // TYPE is A.
149 0x00, 0x01, // CLASS is IN.
150 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
152 0x00, 0x04, // RDLENGTH is 4
157 const uint8 kCorruptedPacketSalvagable[] = {
159 0x00, 0x00, // ID is zeroed out
160 0x81, 0x80, // Standard query response, RA, no error
161 0x00, 0x00, // No questions (for simplicity)
162 0x00, 0x02, // 2 RRs (answers)
163 0x00, 0x00, // 0 authority RRs
164 0x00, 0x00, // 0 additional RRs
167 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
168 0x04, '_', 't', 'c', 'p',
169 0x05, 'l', 'o', 'c', 'a', 'l',
171 0x00, 0x0c, // TYPE is PTR.
172 0x00, 0x01, // CLASS is IN.
173 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
175 0x00, 0x08, // RDLENGTH is 8 bytes.
176 0x99, 'h', 'e', 'l', 'l', 'o', // Bad RDATA format.
180 0x08, '_', 'p', 'r', 'i', 'n', 't', 'e', 'r',
181 0xc0, 0x14, // Pointer to "._tcp.local"
182 0x00, 0x0c, // TYPE is PTR.
183 0x00, 0x01, // CLASS is IN.
184 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 49 seconds.
186 0x00, 0x08, // RDLENGTH is 8 bytes.
187 0x05, 'h', 'e', 'l', 'l', 'o',
191 const uint8 kSamplePacket2[] = {
193 0x00, 0x00, // ID is zeroed out
194 0x81, 0x80, // Standard query response, RA, no error
195 0x00, 0x00, // No questions (for simplicity)
196 0x00, 0x02, // 2 RRs (answers)
197 0x00, 0x00, // 0 authority RRs
198 0x00, 0x00, // 0 additional RRs
201 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
202 0x04, '_', 't', 'c', 'p',
203 0x05, 'l', 'o', 'c', 'a', 'l',
205 0x00, 0x0c, // TYPE is PTR.
206 0x00, 0x01, // CLASS is IN.
207 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
209 0x00, 0x08, // RDLENGTH is 8 bytes.
210 0x05, 'z', 'z', 'z', 'z', 'z',
214 0x08, '_', 'p', 'r', 'i', 'n', 't', 'e', 'r',
215 0xc0, 0x14, // Pointer to "._tcp.local"
216 0x00, 0x0c, // TYPE is PTR.
217 0x00, 0x01, // CLASS is IN.
218 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
220 0x00, 0x08, // RDLENGTH is 8 bytes.
221 0x05, 'z', 'z', 'z', 'z', 'z',
225 const uint8 kQueryPacketPrivet[] = {
227 0x00, 0x00, // ID is zeroed out
228 0x00, 0x00, // No flags.
229 0x00, 0x01, // One question.
230 0x00, 0x00, // 0 RRs (answers)
231 0x00, 0x00, // 0 authority RRs
232 0x00, 0x00, // 0 additional RRs
235 // This part is echoed back from the respective query.
236 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
237 0x04, '_', 't', 'c', 'p',
238 0x05, 'l', 'o', 'c', 'a', 'l',
240 0x00, 0x0c, // TYPE is PTR.
241 0x00, 0x01, // CLASS is IN.
244 const uint8 kSamplePacketAdditionalOnly[] = {
246 0x00, 0x00, // ID is zeroed out
247 0x81, 0x80, // Standard query response, RA, no error
248 0x00, 0x00, // No questions (for simplicity)
249 0x00, 0x00, // 2 RRs (answers)
250 0x00, 0x00, // 0 authority RRs
251 0x00, 0x01, // 0 additional RRs
254 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
255 0x04, '_', 't', 'c', 'p',
256 0x05, 'l', 'o', 'c', 'a', 'l',
258 0x00, 0x0c, // TYPE is PTR.
259 0x00, 0x01, // CLASS is IN.
260 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
262 0x00, 0x08, // RDLENGTH is 8 bytes.
263 0x05, 'h', 'e', 'l', 'l', 'o',
267 const uint8 kSamplePacketNsec[] = {
269 0x00, 0x00, // ID is zeroed out
270 0x81, 0x80, // Standard query response, RA, no error
271 0x00, 0x00, // No questions (for simplicity)
272 0x00, 0x01, // 1 RR (answers)
273 0x00, 0x00, // 0 authority RRs
274 0x00, 0x00, // 0 additional RRs
277 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
278 0x04, '_', 't', 'c', 'p',
279 0x05, 'l', 'o', 'c', 'a', 'l',
281 0x00, 0x2f, // TYPE is NSEC.
282 0x00, 0x01, // CLASS is IN.
283 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
285 0x00, 0x06, // RDLENGTH is 6 bytes.
287 0x00, 0x02, 0x00, 0x08 // Only A record present
290 const uint8 kSamplePacketAPrivet[] = {
292 0x00, 0x00, // ID is zeroed out
293 0x81, 0x80, // Standard query response, RA, no error
294 0x00, 0x00, // No questions (for simplicity)
295 0x00, 0x01, // 1 RR (answers)
296 0x00, 0x00, // 0 authority RRs
297 0x00, 0x00, // 0 additional RRs
300 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
301 0x04, '_', 't', 'c', 'p',
302 0x05, 'l', 'o', 'c', 'a', 'l',
304 0x00, 0x01, // TYPE is A.
305 0x00, 0x01, // CLASS is IN.
306 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
308 0x00, 0x04, // RDLENGTH is 4 bytes.
313 const uint8 kSamplePacketGoodbye[] = {
315 0x00, 0x00, // ID is zeroed out
316 0x81, 0x80, // Standard query response, RA, no error
317 0x00, 0x00, // No questions (for simplicity)
318 0x00, 0x01, // 2 RRs (answers)
319 0x00, 0x00, // 0 authority RRs
320 0x00, 0x00, // 0 additional RRs
323 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
324 0x04, '_', 't', 'c', 'p',
325 0x05, 'l', 'o', 'c', 'a', 'l',
327 0x00, 0x0c, // TYPE is PTR.
328 0x00, 0x01, // CLASS is IN.
329 0x00, 0x00, // TTL (4 bytes) is zero;
331 0x00, 0x08, // RDLENGTH is 8 bytes.
332 0x05, 'z', 'z', 'z', 'z', 'z',
336 std::string MakeString(const uint8* data, unsigned size) {
337 return std::string(reinterpret_cast<const char*>(data), size);
340 class PtrRecordCopyContainer {
342 PtrRecordCopyContainer() {}
343 ~PtrRecordCopyContainer() {}
345 bool is_set() const { return set_; }
347 void SaveWithDummyArg(int unused, const RecordParsed* value) {
351 void Save(const RecordParsed* value) {
353 name_ = value->name();
354 ptrdomain_ = value->rdata<PtrRecordRdata>()->ptrdomain();
358 bool IsRecordWith(std::string name, std::string ptrdomain) {
359 return set_ && name_ == name && ptrdomain_ == ptrdomain;
362 const std::string& name() { return name_; }
363 const std::string& ptrdomain() { return ptrdomain_; }
364 int ttl() { return ttl_; }
369 std::string ptrdomain_;
373 class MDnsTest : public ::testing::Test {
377 virtual void SetUp() OVERRIDE;
378 virtual void TearDown() OVERRIDE;
379 void DeleteTransaction();
380 void DeleteBothListeners();
381 void RunFor(base::TimeDelta time_period);
384 MOCK_METHOD2(MockableRecordCallback, void(MDnsTransaction::Result result,
385 const RecordParsed* record));
387 MOCK_METHOD2(MockableRecordCallback2, void(MDnsTransaction::Result result,
388 const RecordParsed* record));
392 void ExpectPacket(const uint8* packet, unsigned size);
393 void SimulatePacketReceive(const uint8* packet, unsigned size);
395 scoped_ptr<MDnsClientImpl> test_client_;
396 IPEndPoint mdns_ipv4_endpoint_;
397 StrictMock<MockMDnsSocketFactory>* socket_factory_;
399 // Transactions and listeners that can be deleted by class methods for
401 scoped_ptr<MDnsTransaction> transaction_;
402 scoped_ptr<MDnsListener> listener1_;
403 scoped_ptr<MDnsListener> listener2_;
406 class MockListenerDelegate : public MDnsListener::Delegate {
408 MOCK_METHOD2(OnRecordUpdate,
409 void(MDnsListener::UpdateType update,
410 const RecordParsed* records));
411 MOCK_METHOD2(OnNsecRecord, void(const std::string&, unsigned));
412 MOCK_METHOD0(OnCachePurged, void());
415 MDnsTest::MDnsTest() {
416 socket_factory_ = new StrictMock<MockMDnsSocketFactory>();
417 test_client_.reset(new MDnsClientImpl(
418 scoped_ptr<MDnsConnection::SocketFactory>(socket_factory_)));
421 MDnsTest::~MDnsTest() {
424 void MDnsTest::SetUp() {
425 test_client_->StartListening();
428 void MDnsTest::TearDown() {
431 void MDnsTest::SimulatePacketReceive(const uint8* packet, unsigned size) {
432 socket_factory_->SimulateReceive(packet, size);
435 void MDnsTest::ExpectPacket(const uint8* packet, unsigned size) {
436 EXPECT_CALL(*socket_factory_, OnSendTo(MakeString(packet, size)))
440 void MDnsTest::DeleteTransaction() {
441 transaction_.reset();
444 void MDnsTest::DeleteBothListeners() {
449 void MDnsTest::RunFor(base::TimeDelta time_period) {
450 base::CancelableCallback<void()> callback(base::Bind(&MDnsTest::Stop,
451 base::Unretained(this)));
452 base::MessageLoop::current()->PostDelayedTask(
453 FROM_HERE, callback.callback(), time_period);
455 base::MessageLoop::current()->Run();
459 void MDnsTest::Stop() {
460 base::MessageLoop::current()->Quit();
463 TEST_F(MDnsTest, PassiveListeners) {
464 StrictMock<MockListenerDelegate> delegate_privet;
465 StrictMock<MockListenerDelegate> delegate_printer;
467 PtrRecordCopyContainer record_privet;
468 PtrRecordCopyContainer record_printer;
470 scoped_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
471 dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet);
472 scoped_ptr<MDnsListener> listener_printer = test_client_->CreateListener(
473 dns_protocol::kTypePTR, "_printer._tcp.local", &delegate_printer);
475 ASSERT_TRUE(listener_privet->Start());
476 ASSERT_TRUE(listener_printer->Start());
478 // Send the same packet twice to ensure no records are double-counted.
480 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
484 &PtrRecordCopyContainer::SaveWithDummyArg));
486 EXPECT_CALL(delegate_printer, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
490 &PtrRecordCopyContainer::SaveWithDummyArg));
493 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
494 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
496 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
497 "hello._privet._tcp.local"));
499 EXPECT_TRUE(record_printer.IsRecordWith("_printer._tcp.local",
500 "hello._printer._tcp.local"));
502 listener_privet.reset();
503 listener_printer.reset();
506 TEST_F(MDnsTest, PassiveListenersCacheCleanup) {
507 StrictMock<MockListenerDelegate> delegate_privet;
509 PtrRecordCopyContainer record_privet;
510 PtrRecordCopyContainer record_privet2;
512 scoped_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
513 dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet);
515 ASSERT_TRUE(listener_privet->Start());
517 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
521 &PtrRecordCopyContainer::SaveWithDummyArg));
523 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
525 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
526 "hello._privet._tcp.local"));
528 // Expect record is removed when its TTL expires.
529 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_REMOVED, _))
531 .WillOnce(DoAll(InvokeWithoutArgs(this, &MDnsTest::Stop),
532 Invoke(&record_privet2,
533 &PtrRecordCopyContainer::SaveWithDummyArg)));
535 RunFor(base::TimeDelta::FromSeconds(record_privet.ttl() + 1));
537 EXPECT_TRUE(record_privet2.IsRecordWith("_privet._tcp.local",
538 "hello._privet._tcp.local"));
541 TEST_F(MDnsTest, MalformedPacket) {
542 StrictMock<MockListenerDelegate> delegate_printer;
544 PtrRecordCopyContainer record_printer;
546 scoped_ptr<MDnsListener> listener_printer = test_client_->CreateListener(
547 dns_protocol::kTypePTR, "_printer._tcp.local", &delegate_printer);
549 ASSERT_TRUE(listener_printer->Start());
551 EXPECT_CALL(delegate_printer, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
555 &PtrRecordCopyContainer::SaveWithDummyArg));
557 // First, send unsalvagable packet to ensure we can deal with it.
558 SimulatePacketReceive(kCorruptedPacketUnsalvagable,
559 sizeof(kCorruptedPacketUnsalvagable));
561 // Regression test: send a packet where the question cannot be read.
562 SimulatePacketReceive(kCorruptedPacketBadQuestion,
563 sizeof(kCorruptedPacketBadQuestion));
565 // Then send salvagable packet to ensure we can extract useful records.
566 SimulatePacketReceive(kCorruptedPacketSalvagable,
567 sizeof(kCorruptedPacketSalvagable));
569 EXPECT_TRUE(record_printer.IsRecordWith("_printer._tcp.local",
570 "hello._printer._tcp.local"));
573 TEST_F(MDnsTest, TransactionWithEmptyCache) {
574 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
576 scoped_ptr<MDnsTransaction> transaction_privet =
577 test_client_->CreateTransaction(
578 dns_protocol::kTypePTR, "_privet._tcp.local",
579 MDnsTransaction::QUERY_NETWORK |
580 MDnsTransaction::QUERY_CACHE |
581 MDnsTransaction::SINGLE_RESULT,
582 base::Bind(&MDnsTest::MockableRecordCallback,
583 base::Unretained(this)));
585 ASSERT_TRUE(transaction_privet->Start());
587 PtrRecordCopyContainer record_privet;
589 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD, _))
591 .WillOnce(Invoke(&record_privet,
592 &PtrRecordCopyContainer::SaveWithDummyArg));
594 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
596 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
597 "hello._privet._tcp.local"));
600 TEST_F(MDnsTest, TransactionCacheOnlyNoResult) {
601 scoped_ptr<MDnsTransaction> transaction_privet =
602 test_client_->CreateTransaction(
603 dns_protocol::kTypePTR, "_privet._tcp.local",
604 MDnsTransaction::QUERY_CACHE |
605 MDnsTransaction::SINGLE_RESULT,
606 base::Bind(&MDnsTest::MockableRecordCallback,
607 base::Unretained(this)));
610 MockableRecordCallback(MDnsTransaction::RESULT_NO_RESULTS, _))
613 ASSERT_TRUE(transaction_privet->Start());
616 TEST_F(MDnsTest, TransactionWithCache) {
617 // Listener to force the client to listen
618 StrictMock<MockListenerDelegate> delegate_irrelevant;
619 scoped_ptr<MDnsListener> listener_irrelevant = test_client_->CreateListener(
620 dns_protocol::kTypeA, "codereview.chromium.local",
621 &delegate_irrelevant);
623 ASSERT_TRUE(listener_irrelevant->Start());
625 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
628 PtrRecordCopyContainer record_privet;
630 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD, _))
631 .WillOnce(Invoke(&record_privet,
632 &PtrRecordCopyContainer::SaveWithDummyArg));
634 scoped_ptr<MDnsTransaction> transaction_privet =
635 test_client_->CreateTransaction(
636 dns_protocol::kTypePTR, "_privet._tcp.local",
637 MDnsTransaction::QUERY_NETWORK |
638 MDnsTransaction::QUERY_CACHE |
639 MDnsTransaction::SINGLE_RESULT,
640 base::Bind(&MDnsTest::MockableRecordCallback,
641 base::Unretained(this)));
643 ASSERT_TRUE(transaction_privet->Start());
645 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
646 "hello._privet._tcp.local"));
649 TEST_F(MDnsTest, AdditionalRecords) {
650 StrictMock<MockListenerDelegate> delegate_privet;
652 PtrRecordCopyContainer record_privet;
654 scoped_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
655 dns_protocol::kTypePTR, "_privet._tcp.local",
658 ASSERT_TRUE(listener_privet->Start());
660 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
664 &PtrRecordCopyContainer::SaveWithDummyArg));
666 SimulatePacketReceive(kSamplePacketAdditionalOnly,
667 sizeof(kSamplePacketAdditionalOnly));
669 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
670 "hello._privet._tcp.local"));
673 TEST_F(MDnsTest, TransactionTimeout) {
674 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
676 scoped_ptr<MDnsTransaction> transaction_privet =
677 test_client_->CreateTransaction(
678 dns_protocol::kTypePTR, "_privet._tcp.local",
679 MDnsTransaction::QUERY_NETWORK |
680 MDnsTransaction::QUERY_CACHE |
681 MDnsTransaction::SINGLE_RESULT,
682 base::Bind(&MDnsTest::MockableRecordCallback,
683 base::Unretained(this)));
685 ASSERT_TRUE(transaction_privet->Start());
688 MockableRecordCallback(MDnsTransaction::RESULT_NO_RESULTS, NULL))
690 .WillOnce(InvokeWithoutArgs(this, &MDnsTest::Stop));
692 RunFor(base::TimeDelta::FromSeconds(4));
695 TEST_F(MDnsTest, TransactionMultipleRecords) {
696 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
698 scoped_ptr<MDnsTransaction> transaction_privet =
699 test_client_->CreateTransaction(
700 dns_protocol::kTypePTR, "_privet._tcp.local",
701 MDnsTransaction::QUERY_NETWORK |
702 MDnsTransaction::QUERY_CACHE ,
703 base::Bind(&MDnsTest::MockableRecordCallback,
704 base::Unretained(this)));
706 ASSERT_TRUE(transaction_privet->Start());
708 PtrRecordCopyContainer record_privet;
709 PtrRecordCopyContainer record_privet2;
711 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD, _))
713 .WillOnce(Invoke(&record_privet,
714 &PtrRecordCopyContainer::SaveWithDummyArg))
715 .WillOnce(Invoke(&record_privet2,
716 &PtrRecordCopyContainer::SaveWithDummyArg));
718 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
719 SimulatePacketReceive(kSamplePacket2, sizeof(kSamplePacket2));
721 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
722 "hello._privet._tcp.local"));
724 EXPECT_TRUE(record_privet2.IsRecordWith("_privet._tcp.local",
725 "zzzzz._privet._tcp.local"));
727 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_DONE, NULL))
728 .WillOnce(InvokeWithoutArgs(this, &MDnsTest::Stop));
730 RunFor(base::TimeDelta::FromSeconds(4));
733 TEST_F(MDnsTest, TransactionReentrantDelete) {
734 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
736 transaction_ = test_client_->CreateTransaction(
737 dns_protocol::kTypePTR, "_privet._tcp.local",
738 MDnsTransaction::QUERY_NETWORK |
739 MDnsTransaction::QUERY_CACHE |
740 MDnsTransaction::SINGLE_RESULT,
741 base::Bind(&MDnsTest::MockableRecordCallback,
742 base::Unretained(this)));
744 ASSERT_TRUE(transaction_->Start());
746 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_NO_RESULTS,
749 .WillOnce(DoAll(InvokeWithoutArgs(this, &MDnsTest::DeleteTransaction),
750 InvokeWithoutArgs(this, &MDnsTest::Stop)));
752 RunFor(base::TimeDelta::FromSeconds(4));
754 EXPECT_EQ(NULL, transaction_.get());
757 TEST_F(MDnsTest, TransactionReentrantDeleteFromCache) {
758 StrictMock<MockListenerDelegate> delegate_irrelevant;
759 scoped_ptr<MDnsListener> listener_irrelevant = test_client_->CreateListener(
760 dns_protocol::kTypeA, "codereview.chromium.local",
761 &delegate_irrelevant);
762 ASSERT_TRUE(listener_irrelevant->Start());
764 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
766 transaction_ = test_client_->CreateTransaction(
767 dns_protocol::kTypePTR, "_privet._tcp.local",
768 MDnsTransaction::QUERY_NETWORK |
769 MDnsTransaction::QUERY_CACHE,
770 base::Bind(&MDnsTest::MockableRecordCallback,
771 base::Unretained(this)));
773 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD, _))
775 .WillOnce(InvokeWithoutArgs(this, &MDnsTest::DeleteTransaction));
777 ASSERT_TRUE(transaction_->Start());
779 EXPECT_EQ(NULL, transaction_.get());
782 TEST_F(MDnsTest, TransactionReentrantCacheLookupStart) {
783 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
785 scoped_ptr<MDnsTransaction> transaction1 = test_client_->CreateTransaction(
786 dns_protocol::kTypePTR, "_privet._tcp.local",
787 MDnsTransaction::QUERY_NETWORK |
788 MDnsTransaction::QUERY_CACHE |
789 MDnsTransaction::SINGLE_RESULT,
790 base::Bind(&MDnsTest::MockableRecordCallback,
791 base::Unretained(this)));
793 scoped_ptr<MDnsTransaction> transaction2 = test_client_->CreateTransaction(
794 dns_protocol::kTypePTR, "_printer._tcp.local",
795 MDnsTransaction::QUERY_CACHE |
796 MDnsTransaction::SINGLE_RESULT,
797 base::Bind(&MDnsTest::MockableRecordCallback2,
798 base::Unretained(this)));
800 EXPECT_CALL(*this, MockableRecordCallback2(MDnsTransaction::RESULT_RECORD,
804 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD,
807 .WillOnce(IgnoreResult(InvokeWithoutArgs(transaction2.get(),
808 &MDnsTransaction::Start)));
810 ASSERT_TRUE(transaction1->Start());
812 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
815 TEST_F(MDnsTest, GoodbyePacketNotification) {
816 StrictMock<MockListenerDelegate> delegate_privet;
818 scoped_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
819 dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet);
820 ASSERT_TRUE(listener_privet->Start());
822 SimulatePacketReceive(kSamplePacketGoodbye, sizeof(kSamplePacketGoodbye));
824 RunFor(base::TimeDelta::FromSeconds(2));
827 TEST_F(MDnsTest, GoodbyePacketRemoval) {
828 StrictMock<MockListenerDelegate> delegate_privet;
830 scoped_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
831 dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet);
832 ASSERT_TRUE(listener_privet->Start());
834 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
837 SimulatePacketReceive(kSamplePacket2, sizeof(kSamplePacket2));
839 SimulatePacketReceive(kSamplePacketGoodbye, sizeof(kSamplePacketGoodbye));
841 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_REMOVED, _))
844 RunFor(base::TimeDelta::FromSeconds(2));
847 // In order to reliably test reentrant listener deletes, we create two listeners
848 // and have each of them delete both, so we're guaranteed to try and deliver a
849 // callback to at least one deleted listener.
851 TEST_F(MDnsTest, ListenerReentrantDelete) {
852 StrictMock<MockListenerDelegate> delegate_privet;
854 listener1_ = test_client_->CreateListener(
855 dns_protocol::kTypePTR, "_privet._tcp.local",
858 listener2_ = test_client_->CreateListener(
859 dns_protocol::kTypePTR, "_privet._tcp.local",
862 ASSERT_TRUE(listener1_->Start());
864 ASSERT_TRUE(listener2_->Start());
866 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
868 .WillOnce(InvokeWithoutArgs(this, &MDnsTest::DeleteBothListeners));
870 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
872 EXPECT_EQ(NULL, listener1_.get());
873 EXPECT_EQ(NULL, listener2_.get());
876 ACTION_P(SaveIPAddress, ip_container) {
877 ::testing::StaticAssertTypeEq<const RecordParsed*, arg1_type>();
878 ::testing::StaticAssertTypeEq<IPAddressNumber*, ip_container_type>();
880 *ip_container = arg1->template rdata<ARecordRdata>()->address();
883 TEST_F(MDnsTest, DoubleRecordDisagreeing) {
884 IPAddressNumber address;
885 StrictMock<MockListenerDelegate> delegate_privet;
887 scoped_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
888 dns_protocol::kTypeA, "privet.local", &delegate_privet);
890 ASSERT_TRUE(listener_privet->Start());
892 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
894 .WillOnce(SaveIPAddress(&address));
896 SimulatePacketReceive(kCorruptedPacketDoubleRecord,
897 sizeof(kCorruptedPacketDoubleRecord));
899 EXPECT_EQ("2.3.4.5", IPAddressToString(address));
902 TEST_F(MDnsTest, NsecWithListener) {
903 StrictMock<MockListenerDelegate> delegate_privet;
904 scoped_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
905 dns_protocol::kTypeA, "_privet._tcp.local", &delegate_privet);
907 // Test to make sure nsec callback is NOT called for PTR
908 // (which is marked as existing).
909 StrictMock<MockListenerDelegate> delegate_privet2;
910 scoped_ptr<MDnsListener> listener_privet2 = test_client_->CreateListener(
911 dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet2);
913 ASSERT_TRUE(listener_privet->Start());
915 EXPECT_CALL(delegate_privet,
916 OnNsecRecord("_privet._tcp.local", dns_protocol::kTypeA));
918 SimulatePacketReceive(kSamplePacketNsec,
919 sizeof(kSamplePacketNsec));
922 TEST_F(MDnsTest, NsecWithTransactionFromNetwork) {
923 scoped_ptr<MDnsTransaction> transaction_privet =
924 test_client_->CreateTransaction(
925 dns_protocol::kTypeA, "_privet._tcp.local",
926 MDnsTransaction::QUERY_NETWORK |
927 MDnsTransaction::QUERY_CACHE |
928 MDnsTransaction::SINGLE_RESULT,
929 base::Bind(&MDnsTest::MockableRecordCallback,
930 base::Unretained(this)));
932 EXPECT_CALL(*socket_factory_, OnSendTo(_))
935 ASSERT_TRUE(transaction_privet->Start());
938 MockableRecordCallback(MDnsTransaction::RESULT_NSEC, NULL));
940 SimulatePacketReceive(kSamplePacketNsec,
941 sizeof(kSamplePacketNsec));
944 TEST_F(MDnsTest, NsecWithTransactionFromCache) {
945 // Force mDNS to listen.
946 StrictMock<MockListenerDelegate> delegate_irrelevant;
947 scoped_ptr<MDnsListener> listener_irrelevant =
948 test_client_->CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local",
949 &delegate_irrelevant);
950 listener_irrelevant->Start();
952 SimulatePacketReceive(kSamplePacketNsec,
953 sizeof(kSamplePacketNsec));
956 MockableRecordCallback(MDnsTransaction::RESULT_NSEC, NULL));
958 scoped_ptr<MDnsTransaction> transaction_privet_a =
959 test_client_->CreateTransaction(
960 dns_protocol::kTypeA, "_privet._tcp.local",
961 MDnsTransaction::QUERY_NETWORK |
962 MDnsTransaction::QUERY_CACHE |
963 MDnsTransaction::SINGLE_RESULT,
964 base::Bind(&MDnsTest::MockableRecordCallback,
965 base::Unretained(this)));
967 ASSERT_TRUE(transaction_privet_a->Start());
969 // Test that a PTR transaction does NOT consider the same NSEC record to be a
970 // valid answer to the query
972 scoped_ptr<MDnsTransaction> transaction_privet_ptr =
973 test_client_->CreateTransaction(
974 dns_protocol::kTypePTR, "_privet._tcp.local",
975 MDnsTransaction::QUERY_NETWORK |
976 MDnsTransaction::QUERY_CACHE |
977 MDnsTransaction::SINGLE_RESULT,
978 base::Bind(&MDnsTest::MockableRecordCallback,
979 base::Unretained(this)));
981 EXPECT_CALL(*socket_factory_, OnSendTo(_))
984 ASSERT_TRUE(transaction_privet_ptr->Start());
987 TEST_F(MDnsTest, NsecConflictRemoval) {
988 StrictMock<MockListenerDelegate> delegate_privet;
989 scoped_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
990 dns_protocol::kTypeA, "_privet._tcp.local", &delegate_privet);
992 ASSERT_TRUE(listener_privet->Start());
994 const RecordParsed* record1;
995 const RecordParsed* record2;
997 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
998 .WillOnce(SaveArg<1>(&record1));
1000 SimulatePacketReceive(kSamplePacketAPrivet,
1001 sizeof(kSamplePacketAPrivet));
1003 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_REMOVED, _))
1004 .WillOnce(SaveArg<1>(&record2));
1006 EXPECT_CALL(delegate_privet,
1007 OnNsecRecord("_privet._tcp.local", dns_protocol::kTypeA));
1009 SimulatePacketReceive(kSamplePacketNsec,
1010 sizeof(kSamplePacketNsec));
1012 EXPECT_EQ(record1, record2);
1016 // Note: These tests assume that the ipv4 socket will always be created first.
1017 // This is a simplifying assumption based on the way the code works now.
1019 class SimpleMockSocketFactory
1020 : public MDnsConnection::SocketFactory {
1022 SimpleMockSocketFactory() {
1024 virtual ~SimpleMockSocketFactory() {
1027 virtual scoped_ptr<DatagramServerSocket> CreateSocket() OVERRIDE {
1028 MockMDnsDatagramServerSocket* socket = sockets_.back();
1029 sockets_.weak_erase(sockets_.end() - 1);
1030 return scoped_ptr<DatagramServerSocket>(socket);
1033 void PushSocket(MockMDnsDatagramServerSocket* socket) {
1034 sockets_.push_back(socket);
1038 ScopedVector<MockMDnsDatagramServerSocket> sockets_;
1041 class MockMDnsConnectionDelegate : public MDnsConnection::Delegate {
1043 virtual void HandlePacket(DnsResponse* response, int size) {
1044 HandlePacketInternal(std::string(response->io_buffer()->data(), size));
1047 MOCK_METHOD1(HandlePacketInternal, void(std::string packet));
1049 MOCK_METHOD1(OnConnectionError, void(int error));
1052 class MDnsConnectionTest : public ::testing::Test {
1054 MDnsConnectionTest() : connection_(&delegate_) {
1058 // Follow successful connection initialization.
1059 virtual void SetUp() OVERRIDE {
1060 socket_ipv4_ = new MockMDnsDatagramServerSocket;
1061 socket_ipv6_ = new MockMDnsDatagramServerSocket;
1062 factory_.PushSocket(socket_ipv6_);
1063 factory_.PushSocket(socket_ipv4_);
1066 bool InitConnection() {
1067 EXPECT_CALL(*socket_ipv4_, AllowAddressReuse());
1068 EXPECT_CALL(*socket_ipv6_, AllowAddressReuse());
1070 EXPECT_CALL(*socket_ipv4_, SetMulticastLoopbackMode(false));
1071 EXPECT_CALL(*socket_ipv6_, SetMulticastLoopbackMode(false));
1073 EXPECT_CALL(*socket_ipv4_, ListenInternal("0.0.0.0:5353"))
1074 .WillOnce(Return(OK));
1075 EXPECT_CALL(*socket_ipv6_, ListenInternal("[::]:5353"))
1076 .WillOnce(Return(OK));
1078 EXPECT_CALL(*socket_ipv4_, JoinGroupInternal("224.0.0.251"))
1079 .WillOnce(Return(OK));
1080 EXPECT_CALL(*socket_ipv6_, JoinGroupInternal("ff02::fb"))
1081 .WillOnce(Return(OK));
1083 return connection_.Init(&factory_);
1086 StrictMock<MockMDnsConnectionDelegate> delegate_;
1088 MockMDnsDatagramServerSocket* socket_ipv4_;
1089 MockMDnsDatagramServerSocket* socket_ipv6_;
1090 SimpleMockSocketFactory factory_;
1091 MDnsConnection connection_;
1092 TestCompletionCallback callback_;
1095 TEST_F(MDnsConnectionTest, ReceiveSynchronous) {
1096 std::string sample_packet = MakeString(kSamplePacket1,
1097 sizeof(kSamplePacket1));
1099 socket_ipv6_->SetResponsePacket(sample_packet);
1100 EXPECT_CALL(*socket_ipv4_, RecvFrom(_, _, _, _))
1101 .WillOnce(Return(ERR_IO_PENDING));
1102 EXPECT_CALL(*socket_ipv6_, RecvFrom(_, _, _, _))
1104 Invoke(socket_ipv6_, &MockMDnsDatagramServerSocket::HandleRecvNow))
1105 .WillOnce(Return(ERR_IO_PENDING));
1107 EXPECT_CALL(delegate_, HandlePacketInternal(sample_packet));
1109 ASSERT_TRUE(InitConnection());
1112 TEST_F(MDnsConnectionTest, ReceiveAsynchronous) {
1113 std::string sample_packet = MakeString(kSamplePacket1,
1114 sizeof(kSamplePacket1));
1115 socket_ipv6_->SetResponsePacket(sample_packet);
1116 EXPECT_CALL(*socket_ipv4_, RecvFrom(_, _, _, _))
1117 .WillOnce(Return(ERR_IO_PENDING));
1118 EXPECT_CALL(*socket_ipv6_, RecvFrom(_, _, _, _))
1120 Invoke(socket_ipv6_, &MockMDnsDatagramServerSocket::HandleRecvLater))
1121 .WillOnce(Return(ERR_IO_PENDING));
1123 ASSERT_TRUE(InitConnection());
1125 EXPECT_CALL(delegate_, HandlePacketInternal(sample_packet));
1127 base::MessageLoop::current()->RunUntilIdle();
1130 TEST_F(MDnsConnectionTest, Send) {
1131 std::string sample_packet = MakeString(kSamplePacket1,
1132 sizeof(kSamplePacket1));
1134 scoped_refptr<IOBufferWithSize> buf(
1135 new IOBufferWithSize(sizeof kSamplePacket1));
1136 memcpy(buf->data(), kSamplePacket1, sizeof(kSamplePacket1));
1138 EXPECT_CALL(*socket_ipv4_, RecvFrom(_, _, _, _))
1139 .WillOnce(Return(ERR_IO_PENDING));
1140 EXPECT_CALL(*socket_ipv6_, RecvFrom(_, _, _, _))
1141 .WillOnce(Return(ERR_IO_PENDING));
1143 ASSERT_TRUE(InitConnection());
1145 EXPECT_CALL(*socket_ipv4_,
1146 SendToInternal(sample_packet, "224.0.0.251:5353", _));
1147 EXPECT_CALL(*socket_ipv6_,
1148 SendToInternal(sample_packet, "[ff02::fb]:5353", _));
1150 connection_.Send(buf, buf->size());
1153 TEST_F(MDnsConnectionTest, Error) {
1154 CompletionCallback callback;
1156 EXPECT_CALL(*socket_ipv4_, RecvFrom(_, _, _, _))
1157 .WillOnce(Return(ERR_IO_PENDING));
1158 EXPECT_CALL(*socket_ipv6_, RecvFrom(_, _, _, _))
1159 .WillOnce(DoAll(SaveArg<3>(&callback), Return(ERR_IO_PENDING)));
1161 ASSERT_TRUE(InitConnection());
1163 EXPECT_CALL(delegate_, OnConnectionError(ERR_SOCKET_NOT_CONNECTED));
1164 callback.Run(ERR_SOCKET_NOT_CONNECTED);