• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include <queue>
6 
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"
17 
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;
25 using ::testing::_;
26 
27 namespace net {
28 
29 namespace {
30 
31 const uint8 kSamplePacket1[] = {
32   // Header
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
39 
40   // Answer 1
41   0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
42   0x04, '_', 't', 'c', 'p',
43   0x05, 'l', 'o', 'c', 'a', 'l',
44   0x00,
45   0x00, 0x0c,        // TYPE is PTR.
46   0x00, 0x01,        // CLASS is IN.
47   0x00, 0x00,        // TTL (4 bytes) is 1 second;
48   0x00, 0x01,
49   0x00, 0x08,        // RDLENGTH is 8 bytes.
50   0x05, 'h', 'e', 'l', 'l', 'o',
51   0xc0, 0x0c,
52 
53   // Answer 2
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.
59   0x24, 0x75,
60   0x00, 0x08,        // RDLENGTH is 8 bytes.
61   0x05, 'h', 'e', 'l', 'l', 'o',
62   0xc0, 0x32
63 };
64 
65 const uint8 kCorruptedPacketBadQuestion[] = {
66   // Header
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
73 
74   // Question is corrupted and cannot be read.
75   0x99, 'h', 'e', 'l', 'l', 'o',
76   0x00,
77   0x00, 0x00,
78   0x00, 0x00,
79 
80   // Answer 1
81   0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
82   0x04, '_', 't', 'c', 'p',
83   0x05, 'l', 'o', 'c', 'a', 'l',
84   0x00,
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.
88   0x24, 0x74,
89   0x00, 0x99,        // RDLENGTH is impossible
90   0x05, 'h', 'e', 'l', 'l', 'o',
91   0xc0, 0x0c,
92 
93   // Answer 2
94   0x08, '_', 'p', 'r',  // Useless trailing data.
95 };
96 
97 const uint8 kCorruptedPacketUnsalvagable[] = {
98   // Header
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
105 
106   // Answer 1
107   0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
108   0x04, '_', 't', 'c', 'p',
109   0x05, 'l', 'o', 'c', 'a', 'l',
110   0x00,
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.
114   0x24, 0x74,
115   0x00, 0x99,        // RDLENGTH is impossible
116   0x05, 'h', 'e', 'l', 'l', 'o',
117   0xc0, 0x0c,
118 
119   // Answer 2
120   0x08, '_', 'p', 'r',  // Useless trailing data.
121 };
122 
123 const uint8 kCorruptedPacketDoubleRecord[] = {
124   // Header
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
131 
132   // Answer 1
133   0x06, 'p', 'r', 'i', 'v', 'e', 't',
134   0x05, 'l', 'o', 'c', 'a', 'l',
135   0x00,
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.
139   0x24, 0x74,
140   0x00, 0x04,        // RDLENGTH is 4
141   0x05, 0x03,
142   0xc0, 0x0c,
143 
144   // Answer 2 -- Same key
145   0x06, 'p', 'r', 'i', 'v', 'e', 't',
146   0x05, 'l', 'o', 'c', 'a', 'l',
147   0x00,
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.
151   0x24, 0x74,
152   0x00, 0x04,        // RDLENGTH is 4
153   0x02, 0x03,
154   0x04, 0x05,
155 };
156 
157 const uint8 kCorruptedPacketSalvagable[] = {
158   // Header
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
165 
166   // Answer 1
167   0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
168   0x04, '_', 't', 'c', 'p',
169   0x05, 'l', 'o', 'c', 'a', 'l',
170   0x00,
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.
174   0x24, 0x74,
175   0x00, 0x08,        // RDLENGTH is 8 bytes.
176   0x99, 'h', 'e', 'l', 'l', 'o',   // Bad RDATA format.
177   0xc0, 0x0c,
178 
179   // Answer 2
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.
185   0x24, 0x75,
186   0x00, 0x08,        // RDLENGTH is 8 bytes.
187   0x05, 'h', 'e', 'l', 'l', 'o',
188   0xc0, 0x32
189 };
190 
191 const uint8 kSamplePacket2[] = {
192   // Header
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
199 
200   // Answer 1
201   0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
202   0x04, '_', 't', 'c', 'p',
203   0x05, 'l', 'o', 'c', 'a', 'l',
204   0x00,
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.
208   0x24, 0x74,
209   0x00, 0x08,        // RDLENGTH is 8 bytes.
210   0x05, 'z', 'z', 'z', 'z', 'z',
211   0xc0, 0x0c,
212 
213   // Answer 2
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.
219   0x24, 0x74,
220   0x00, 0x08,        // RDLENGTH is 8 bytes.
221   0x05, 'z', 'z', 'z', 'z', 'z',
222   0xc0, 0x32
223 };
224 
225 const uint8 kQueryPacketPrivet[] = {
226   // Header
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
233 
234   // Question
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',
239   0x00,
240   0x00, 0x0c,        // TYPE is PTR.
241   0x00, 0x01,        // CLASS is IN.
242 };
243 
244 const uint8 kSamplePacketAdditionalOnly[] = {
245   // Header
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
252 
253   // Answer 1
254   0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
255   0x04, '_', 't', 'c', 'p',
256   0x05, 'l', 'o', 'c', 'a', 'l',
257   0x00,
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.
261   0x24, 0x74,
262   0x00, 0x08,        // RDLENGTH is 8 bytes.
263   0x05, 'h', 'e', 'l', 'l', 'o',
264   0xc0, 0x0c,
265 };
266 
267 const uint8 kSamplePacketNsec[] = {
268   // Header
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
275 
276   // Answer 1
277   0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
278   0x04, '_', 't', 'c', 'p',
279   0x05, 'l', 'o', 'c', 'a', 'l',
280   0x00,
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.
284   0x24, 0x74,
285   0x00, 0x06,        // RDLENGTH is 6 bytes.
286   0xc0, 0x0c,
287   0x00, 0x02, 0x00, 0x08  // Only A record present
288 };
289 
290 const uint8 kSamplePacketAPrivet[] = {
291   // Header
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
298 
299   // Answer 1
300   0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
301   0x04, '_', 't', 'c', 'p',
302   0x05, 'l', 'o', 'c', 'a', 'l',
303   0x00,
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.
307   0x24, 0x74,
308   0x00, 0x04,        // RDLENGTH is 4 bytes.
309   0xc0, 0x0c,
310   0x00, 0x02,
311 };
312 
313 const uint8 kSamplePacketGoodbye[] = {
314   // Header
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
321 
322   // Answer 1
323   0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
324   0x04, '_', 't', 'c', 'p',
325   0x05, 'l', 'o', 'c', 'a', 'l',
326   0x00,
327   0x00, 0x0c,        // TYPE is PTR.
328   0x00, 0x01,        // CLASS is IN.
329   0x00, 0x00,        // TTL (4 bytes) is zero;
330   0x00, 0x00,
331   0x00, 0x08,        // RDLENGTH is 8 bytes.
332   0x05, 'z', 'z', 'z', 'z', 'z',
333   0xc0, 0x0c,
334 };
335 
MakeString(const uint8 * data,unsigned size)336 std::string MakeString(const uint8* data, unsigned size) {
337   return std::string(reinterpret_cast<const char*>(data), size);
338 }
339 
340 class PtrRecordCopyContainer {
341  public:
PtrRecordCopyContainer()342   PtrRecordCopyContainer() {}
~PtrRecordCopyContainer()343   ~PtrRecordCopyContainer() {}
344 
is_set() const345   bool is_set() const { return set_; }
346 
SaveWithDummyArg(int unused,const RecordParsed * value)347   void SaveWithDummyArg(int unused, const RecordParsed* value) {
348     Save(value);
349   }
350 
Save(const RecordParsed * value)351   void Save(const RecordParsed* value) {
352     set_ = true;
353     name_ = value->name();
354     ptrdomain_ = value->rdata<PtrRecordRdata>()->ptrdomain();
355     ttl_ = value->ttl();
356   }
357 
IsRecordWith(std::string name,std::string ptrdomain)358   bool IsRecordWith(std::string name, std::string ptrdomain) {
359     return set_ && name_ == name && ptrdomain_ == ptrdomain;
360   }
361 
name()362   const std::string& name() { return name_; }
ptrdomain()363   const std::string& ptrdomain() { return ptrdomain_; }
ttl()364   int ttl() { return ttl_; }
365 
366  private:
367   bool set_;
368   std::string name_;
369   std::string ptrdomain_;
370   int ttl_;
371 };
372 
373 class MDnsTest : public ::testing::Test {
374  public:
375   virtual void SetUp() OVERRIDE;
376   void DeleteTransaction();
377   void DeleteBothListeners();
378   void RunFor(base::TimeDelta time_period);
379   void Stop();
380 
381   MOCK_METHOD2(MockableRecordCallback, void(MDnsTransaction::Result result,
382                                             const RecordParsed* record));
383 
384   MOCK_METHOD2(MockableRecordCallback2, void(MDnsTransaction::Result result,
385                                              const RecordParsed* record));
386 
387 
388  protected:
389   void ExpectPacket(const uint8* packet, unsigned size);
390   void SimulatePacketReceive(const uint8* packet, unsigned size);
391 
392   MDnsClientImpl test_client_;
393   IPEndPoint mdns_ipv4_endpoint_;
394   StrictMock<MockMDnsSocketFactory> socket_factory_;
395 
396   // Transactions and listeners that can be deleted by class methods for
397   // reentrancy tests.
398   scoped_ptr<MDnsTransaction> transaction_;
399   scoped_ptr<MDnsListener> listener1_;
400   scoped_ptr<MDnsListener> listener2_;
401 };
402 
403 class MockListenerDelegate : public MDnsListener::Delegate {
404  public:
405   MOCK_METHOD2(OnRecordUpdate,
406                void(MDnsListener::UpdateType update,
407                     const RecordParsed* records));
408   MOCK_METHOD2(OnNsecRecord, void(const std::string&, unsigned));
409   MOCK_METHOD0(OnCachePurged, void());
410 };
411 
SetUp()412 void MDnsTest::SetUp() {
413   test_client_.StartListening(&socket_factory_);
414 }
415 
SimulatePacketReceive(const uint8 * packet,unsigned size)416 void MDnsTest::SimulatePacketReceive(const uint8* packet, unsigned size) {
417   socket_factory_.SimulateReceive(packet, size);
418 }
419 
ExpectPacket(const uint8 * packet,unsigned size)420 void MDnsTest::ExpectPacket(const uint8* packet, unsigned size) {
421   EXPECT_CALL(socket_factory_, OnSendTo(MakeString(packet, size)))
422       .Times(2);
423 }
424 
DeleteTransaction()425 void MDnsTest::DeleteTransaction() {
426   transaction_.reset();
427 }
428 
DeleteBothListeners()429 void MDnsTest::DeleteBothListeners() {
430   listener1_.reset();
431   listener2_.reset();
432 }
433 
RunFor(base::TimeDelta time_period)434 void MDnsTest::RunFor(base::TimeDelta time_period) {
435   base::CancelableCallback<void()> callback(base::Bind(&MDnsTest::Stop,
436                                                        base::Unretained(this)));
437   base::MessageLoop::current()->PostDelayedTask(
438       FROM_HERE, callback.callback(), time_period);
439 
440   base::MessageLoop::current()->Run();
441   callback.Cancel();
442 }
443 
Stop()444 void MDnsTest::Stop() {
445   base::MessageLoop::current()->Quit();
446 }
447 
TEST_F(MDnsTest,PassiveListeners)448 TEST_F(MDnsTest, PassiveListeners) {
449   StrictMock<MockListenerDelegate> delegate_privet;
450   StrictMock<MockListenerDelegate> delegate_printer;
451 
452   PtrRecordCopyContainer record_privet;
453   PtrRecordCopyContainer record_printer;
454 
455   scoped_ptr<MDnsListener> listener_privet =
456       test_client_.CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local",
457                                   &delegate_privet);
458   scoped_ptr<MDnsListener> listener_printer =
459       test_client_.CreateListener(dns_protocol::kTypePTR, "_printer._tcp.local",
460                                   &delegate_printer);
461 
462   ASSERT_TRUE(listener_privet->Start());
463   ASSERT_TRUE(listener_printer->Start());
464 
465   // Send the same packet twice to ensure no records are double-counted.
466 
467   EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
468       .Times(Exactly(1))
469       .WillOnce(Invoke(
470           &record_privet,
471           &PtrRecordCopyContainer::SaveWithDummyArg));
472 
473   EXPECT_CALL(delegate_printer, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
474       .Times(Exactly(1))
475       .WillOnce(Invoke(
476           &record_printer,
477           &PtrRecordCopyContainer::SaveWithDummyArg));
478 
479 
480   SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
481   SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
482 
483   EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
484                                          "hello._privet._tcp.local"));
485 
486   EXPECT_TRUE(record_printer.IsRecordWith("_printer._tcp.local",
487                                           "hello._printer._tcp.local"));
488 
489   listener_privet.reset();
490   listener_printer.reset();
491 }
492 
TEST_F(MDnsTest,PassiveListenersCacheCleanup)493 TEST_F(MDnsTest, PassiveListenersCacheCleanup) {
494   StrictMock<MockListenerDelegate> delegate_privet;
495 
496   PtrRecordCopyContainer record_privet;
497   PtrRecordCopyContainer record_privet2;
498 
499   scoped_ptr<MDnsListener> listener_privet =
500       test_client_.CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local",
501                                   &delegate_privet);
502 
503   ASSERT_TRUE(listener_privet->Start());
504 
505   EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
506       .Times(Exactly(1))
507       .WillOnce(Invoke(
508           &record_privet,
509           &PtrRecordCopyContainer::SaveWithDummyArg));
510 
511   SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
512 
513   EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
514                                          "hello._privet._tcp.local"));
515 
516   // Expect record is removed when its TTL expires.
517   EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_REMOVED, _))
518       .Times(Exactly(1))
519       .WillOnce(DoAll(InvokeWithoutArgs(this, &MDnsTest::Stop),
520                       Invoke(&record_privet2,
521                              &PtrRecordCopyContainer::SaveWithDummyArg)));
522 
523   RunFor(base::TimeDelta::FromSeconds(record_privet.ttl() + 1));
524 
525   EXPECT_TRUE(record_privet2.IsRecordWith("_privet._tcp.local",
526                                           "hello._privet._tcp.local"));
527 }
528 
TEST_F(MDnsTest,MalformedPacket)529 TEST_F(MDnsTest, MalformedPacket) {
530   StrictMock<MockListenerDelegate> delegate_printer;
531 
532   PtrRecordCopyContainer record_printer;
533 
534   scoped_ptr<MDnsListener> listener_printer =
535       test_client_.CreateListener(dns_protocol::kTypePTR, "_printer._tcp.local",
536                                   &delegate_printer);
537 
538   ASSERT_TRUE(listener_printer->Start());
539 
540   EXPECT_CALL(delegate_printer, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
541       .Times(Exactly(1))
542       .WillOnce(Invoke(
543           &record_printer,
544           &PtrRecordCopyContainer::SaveWithDummyArg));
545 
546   // First, send unsalvagable packet to ensure we can deal with it.
547   SimulatePacketReceive(kCorruptedPacketUnsalvagable,
548                         sizeof(kCorruptedPacketUnsalvagable));
549 
550   // Regression test: send a packet where the question cannot be read.
551   SimulatePacketReceive(kCorruptedPacketBadQuestion,
552                         sizeof(kCorruptedPacketBadQuestion));
553 
554   // Then send salvagable packet to ensure we can extract useful records.
555   SimulatePacketReceive(kCorruptedPacketSalvagable,
556                         sizeof(kCorruptedPacketSalvagable));
557 
558   EXPECT_TRUE(record_printer.IsRecordWith("_printer._tcp.local",
559                                           "hello._printer._tcp.local"));
560 }
561 
TEST_F(MDnsTest,TransactionWithEmptyCache)562 TEST_F(MDnsTest, TransactionWithEmptyCache) {
563   ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
564 
565   scoped_ptr<MDnsTransaction> transaction_privet =
566       test_client_.CreateTransaction(
567           dns_protocol::kTypePTR, "_privet._tcp.local",
568           MDnsTransaction::QUERY_NETWORK |
569           MDnsTransaction::QUERY_CACHE |
570           MDnsTransaction::SINGLE_RESULT,
571           base::Bind(&MDnsTest::MockableRecordCallback,
572                      base::Unretained(this)));
573 
574   ASSERT_TRUE(transaction_privet->Start());
575 
576   PtrRecordCopyContainer record_privet;
577 
578   EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD, _))
579       .Times(Exactly(1))
580       .WillOnce(Invoke(&record_privet,
581                        &PtrRecordCopyContainer::SaveWithDummyArg));
582 
583   SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
584 
585   EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
586                                          "hello._privet._tcp.local"));
587 }
588 
TEST_F(MDnsTest,TransactionCacheOnlyNoResult)589 TEST_F(MDnsTest, TransactionCacheOnlyNoResult) {
590   scoped_ptr<MDnsTransaction> transaction_privet =
591       test_client_.CreateTransaction(
592           dns_protocol::kTypePTR, "_privet._tcp.local",
593           MDnsTransaction::QUERY_CACHE |
594           MDnsTransaction::SINGLE_RESULT,
595           base::Bind(&MDnsTest::MockableRecordCallback,
596                      base::Unretained(this)));
597 
598   EXPECT_CALL(*this,
599               MockableRecordCallback(MDnsTransaction::RESULT_NO_RESULTS, _))
600       .Times(Exactly(1));
601 
602   ASSERT_TRUE(transaction_privet->Start());
603 }
604 
TEST_F(MDnsTest,TransactionWithCache)605 TEST_F(MDnsTest, TransactionWithCache) {
606   // Listener to force the client to listen
607   StrictMock<MockListenerDelegate> delegate_irrelevant;
608   scoped_ptr<MDnsListener> listener_irrelevant =
609       test_client_.CreateListener(dns_protocol::kTypeA,
610                                   "codereview.chromium.local",
611                                   &delegate_irrelevant);
612 
613   ASSERT_TRUE(listener_irrelevant->Start());
614 
615   SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
616 
617 
618   PtrRecordCopyContainer record_privet;
619 
620   EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD, _))
621       .WillOnce(Invoke(&record_privet,
622                        &PtrRecordCopyContainer::SaveWithDummyArg));
623 
624   scoped_ptr<MDnsTransaction> transaction_privet =
625       test_client_.CreateTransaction(
626           dns_protocol::kTypePTR, "_privet._tcp.local",
627           MDnsTransaction::QUERY_NETWORK |
628           MDnsTransaction::QUERY_CACHE |
629           MDnsTransaction::SINGLE_RESULT,
630           base::Bind(&MDnsTest::MockableRecordCallback,
631                      base::Unretained(this)));
632 
633   ASSERT_TRUE(transaction_privet->Start());
634 
635   EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
636                                          "hello._privet._tcp.local"));
637 }
638 
TEST_F(MDnsTest,AdditionalRecords)639 TEST_F(MDnsTest, AdditionalRecords) {
640   StrictMock<MockListenerDelegate> delegate_privet;
641 
642   PtrRecordCopyContainer record_privet;
643 
644   scoped_ptr<MDnsListener> listener_privet =
645       test_client_.CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local",
646                                   &delegate_privet);
647 
648   ASSERT_TRUE(listener_privet->Start());
649 
650   EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
651       .Times(Exactly(1))
652       .WillOnce(Invoke(
653           &record_privet,
654           &PtrRecordCopyContainer::SaveWithDummyArg));
655 
656   SimulatePacketReceive(kSamplePacketAdditionalOnly,
657                         sizeof(kSamplePacketAdditionalOnly));
658 
659   EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
660                                          "hello._privet._tcp.local"));
661 }
662 
TEST_F(MDnsTest,TransactionTimeout)663 TEST_F(MDnsTest, TransactionTimeout) {
664   ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
665 
666   scoped_ptr<MDnsTransaction> transaction_privet =
667       test_client_.CreateTransaction(
668           dns_protocol::kTypePTR, "_privet._tcp.local",
669           MDnsTransaction::QUERY_NETWORK |
670           MDnsTransaction::QUERY_CACHE |
671           MDnsTransaction::SINGLE_RESULT,
672           base::Bind(&MDnsTest::MockableRecordCallback,
673                      base::Unretained(this)));
674 
675   ASSERT_TRUE(transaction_privet->Start());
676 
677   EXPECT_CALL(*this,
678               MockableRecordCallback(MDnsTransaction::RESULT_NO_RESULTS, NULL))
679       .Times(Exactly(1))
680       .WillOnce(InvokeWithoutArgs(this, &MDnsTest::Stop));
681 
682   RunFor(base::TimeDelta::FromSeconds(4));
683 }
684 
TEST_F(MDnsTest,TransactionMultipleRecords)685 TEST_F(MDnsTest, TransactionMultipleRecords) {
686   ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
687 
688   scoped_ptr<MDnsTransaction> transaction_privet =
689       test_client_.CreateTransaction(
690           dns_protocol::kTypePTR, "_privet._tcp.local",
691           MDnsTransaction::QUERY_NETWORK |
692           MDnsTransaction::QUERY_CACHE ,
693           base::Bind(&MDnsTest::MockableRecordCallback,
694                      base::Unretained(this)));
695 
696   ASSERT_TRUE(transaction_privet->Start());
697 
698   PtrRecordCopyContainer record_privet;
699   PtrRecordCopyContainer record_privet2;
700 
701   EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD, _))
702       .Times(Exactly(2))
703       .WillOnce(Invoke(&record_privet,
704                        &PtrRecordCopyContainer::SaveWithDummyArg))
705       .WillOnce(Invoke(&record_privet2,
706                        &PtrRecordCopyContainer::SaveWithDummyArg));
707 
708   SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
709   SimulatePacketReceive(kSamplePacket2, sizeof(kSamplePacket2));
710 
711   EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
712                                          "hello._privet._tcp.local"));
713 
714   EXPECT_TRUE(record_privet2.IsRecordWith("_privet._tcp.local",
715                                           "zzzzz._privet._tcp.local"));
716 
717   EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_DONE, NULL))
718       .WillOnce(InvokeWithoutArgs(this, &MDnsTest::Stop));
719 
720   RunFor(base::TimeDelta::FromSeconds(4));
721 }
722 
TEST_F(MDnsTest,TransactionReentrantDelete)723 TEST_F(MDnsTest, TransactionReentrantDelete) {
724   ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
725 
726   transaction_ = test_client_.CreateTransaction(
727       dns_protocol::kTypePTR, "_privet._tcp.local",
728       MDnsTransaction::QUERY_NETWORK |
729       MDnsTransaction::QUERY_CACHE |
730       MDnsTransaction::SINGLE_RESULT,
731       base::Bind(&MDnsTest::MockableRecordCallback,
732                  base::Unretained(this)));
733 
734   ASSERT_TRUE(transaction_->Start());
735 
736   EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_NO_RESULTS,
737                                             NULL))
738       .Times(Exactly(1))
739       .WillOnce(DoAll(InvokeWithoutArgs(this, &MDnsTest::DeleteTransaction),
740                       InvokeWithoutArgs(this, &MDnsTest::Stop)));
741 
742   RunFor(base::TimeDelta::FromSeconds(4));
743 
744   EXPECT_EQ(NULL, transaction_.get());
745 }
746 
TEST_F(MDnsTest,TransactionReentrantDeleteFromCache)747 TEST_F(MDnsTest, TransactionReentrantDeleteFromCache) {
748   StrictMock<MockListenerDelegate> delegate_irrelevant;
749   scoped_ptr<MDnsListener> listener_irrelevant = test_client_.CreateListener(
750       dns_protocol::kTypeA, "codereview.chromium.local",
751       &delegate_irrelevant);
752   ASSERT_TRUE(listener_irrelevant->Start());
753 
754   SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
755 
756   transaction_ = test_client_.CreateTransaction(
757       dns_protocol::kTypePTR, "_privet._tcp.local",
758       MDnsTransaction::QUERY_NETWORK |
759       MDnsTransaction::QUERY_CACHE,
760       base::Bind(&MDnsTest::MockableRecordCallback,
761                  base::Unretained(this)));
762 
763   EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD, _))
764       .Times(Exactly(1))
765       .WillOnce(InvokeWithoutArgs(this, &MDnsTest::DeleteTransaction));
766 
767   ASSERT_TRUE(transaction_->Start());
768 
769   EXPECT_EQ(NULL, transaction_.get());
770 }
771 
TEST_F(MDnsTest,TransactionReentrantCacheLookupStart)772 TEST_F(MDnsTest, TransactionReentrantCacheLookupStart) {
773   ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
774 
775   scoped_ptr<MDnsTransaction> transaction1 =
776       test_client_.CreateTransaction(
777           dns_protocol::kTypePTR, "_privet._tcp.local",
778           MDnsTransaction::QUERY_NETWORK |
779           MDnsTransaction::QUERY_CACHE |
780           MDnsTransaction::SINGLE_RESULT,
781           base::Bind(&MDnsTest::MockableRecordCallback,
782                      base::Unretained(this)));
783 
784   scoped_ptr<MDnsTransaction> transaction2 =
785       test_client_.CreateTransaction(
786           dns_protocol::kTypePTR, "_printer._tcp.local",
787           MDnsTransaction::QUERY_CACHE |
788           MDnsTransaction::SINGLE_RESULT,
789           base::Bind(&MDnsTest::MockableRecordCallback2,
790                      base::Unretained(this)));
791 
792   EXPECT_CALL(*this, MockableRecordCallback2(MDnsTransaction::RESULT_RECORD,
793                                              _))
794       .Times(Exactly(1));
795 
796   EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD,
797                                             _))
798       .Times(Exactly(1))
799       .WillOnce(IgnoreResult(InvokeWithoutArgs(transaction2.get(),
800                                                &MDnsTransaction::Start)));
801 
802   ASSERT_TRUE(transaction1->Start());
803 
804   SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
805 }
806 
TEST_F(MDnsTest,GoodbyePacketNotification)807 TEST_F(MDnsTest, GoodbyePacketNotification) {
808   StrictMock<MockListenerDelegate> delegate_privet;
809 
810   scoped_ptr<MDnsListener> listener_privet = test_client_.CreateListener(
811       dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet);
812   ASSERT_TRUE(listener_privet->Start());
813 
814   SimulatePacketReceive(kSamplePacketGoodbye, sizeof(kSamplePacketGoodbye));
815 
816   RunFor(base::TimeDelta::FromSeconds(2));
817 }
818 
TEST_F(MDnsTest,GoodbyePacketRemoval)819 TEST_F(MDnsTest, GoodbyePacketRemoval) {
820   StrictMock<MockListenerDelegate> delegate_privet;
821 
822   scoped_ptr<MDnsListener> listener_privet =
823       test_client_.CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local",
824                                   &delegate_privet);
825   ASSERT_TRUE(listener_privet->Start());
826 
827   EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
828       .Times(Exactly(1));
829 
830   SimulatePacketReceive(kSamplePacket2, sizeof(kSamplePacket2));
831 
832   SimulatePacketReceive(kSamplePacketGoodbye, sizeof(kSamplePacketGoodbye));
833 
834   EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_REMOVED, _))
835       .Times(Exactly(1));
836 
837   RunFor(base::TimeDelta::FromSeconds(2));
838 }
839 
840 // In order to reliably test reentrant listener deletes, we create two listeners
841 // and have each of them delete both, so we're guaranteed to try and deliver a
842 // callback to at least one deleted listener.
843 
TEST_F(MDnsTest,ListenerReentrantDelete)844 TEST_F(MDnsTest, ListenerReentrantDelete) {
845   StrictMock<MockListenerDelegate> delegate_privet;
846 
847   listener1_ = test_client_.CreateListener(dns_protocol::kTypePTR,
848                                            "_privet._tcp.local",
849                                            &delegate_privet);
850 
851   listener2_ = test_client_.CreateListener(dns_protocol::kTypePTR,
852                                            "_privet._tcp.local",
853                                            &delegate_privet);
854 
855   ASSERT_TRUE(listener1_->Start());
856 
857   ASSERT_TRUE(listener2_->Start());
858 
859   EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
860       .Times(Exactly(1))
861       .WillOnce(InvokeWithoutArgs(this, &MDnsTest::DeleteBothListeners));
862 
863   SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
864 
865   EXPECT_EQ(NULL, listener1_.get());
866   EXPECT_EQ(NULL, listener2_.get());
867 }
868 
ACTION_P(SaveIPAddress,ip_container)869 ACTION_P(SaveIPAddress, ip_container) {
870   ::testing::StaticAssertTypeEq<const RecordParsed*, arg1_type>();
871   ::testing::StaticAssertTypeEq<IPAddressNumber*, ip_container_type>();
872 
873   *ip_container = arg1->template rdata<ARecordRdata>()->address();
874 }
875 
TEST_F(MDnsTest,DoubleRecordDisagreeing)876 TEST_F(MDnsTest, DoubleRecordDisagreeing) {
877   IPAddressNumber address;
878   StrictMock<MockListenerDelegate> delegate_privet;
879 
880   scoped_ptr<MDnsListener> listener_privet =
881       test_client_.CreateListener(dns_protocol::kTypeA, "privet.local",
882                                   &delegate_privet);
883 
884   ASSERT_TRUE(listener_privet->Start());
885 
886   EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
887       .Times(Exactly(1))
888       .WillOnce(SaveIPAddress(&address));
889 
890   SimulatePacketReceive(kCorruptedPacketDoubleRecord,
891                         sizeof(kCorruptedPacketDoubleRecord));
892 
893   EXPECT_EQ("2.3.4.5", IPAddressToString(address));
894 }
895 
TEST_F(MDnsTest,NsecWithListener)896 TEST_F(MDnsTest, NsecWithListener) {
897   StrictMock<MockListenerDelegate> delegate_privet;
898   scoped_ptr<MDnsListener> listener_privet =
899       test_client_.CreateListener(dns_protocol::kTypeA, "_privet._tcp.local",
900                                   &delegate_privet);
901 
902   // Test to make sure nsec callback is NOT called for PTR
903   // (which is marked as existing).
904   StrictMock<MockListenerDelegate> delegate_privet2;
905   scoped_ptr<MDnsListener> listener_privet2 =
906       test_client_.CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local",
907                                   &delegate_privet2);
908 
909   ASSERT_TRUE(listener_privet->Start());
910 
911   EXPECT_CALL(delegate_privet,
912               OnNsecRecord("_privet._tcp.local", dns_protocol::kTypeA));
913 
914   SimulatePacketReceive(kSamplePacketNsec,
915                         sizeof(kSamplePacketNsec));
916 }
917 
TEST_F(MDnsTest,NsecWithTransactionFromNetwork)918 TEST_F(MDnsTest, NsecWithTransactionFromNetwork) {
919   scoped_ptr<MDnsTransaction> transaction_privet =
920       test_client_.CreateTransaction(
921           dns_protocol::kTypeA, "_privet._tcp.local",
922           MDnsTransaction::QUERY_NETWORK |
923           MDnsTransaction::QUERY_CACHE |
924           MDnsTransaction::SINGLE_RESULT,
925           base::Bind(&MDnsTest::MockableRecordCallback,
926                      base::Unretained(this)));
927 
928   EXPECT_CALL(socket_factory_, OnSendTo(_)).Times(2);
929 
930   ASSERT_TRUE(transaction_privet->Start());
931 
932   EXPECT_CALL(*this,
933               MockableRecordCallback(MDnsTransaction::RESULT_NSEC, NULL));
934 
935   SimulatePacketReceive(kSamplePacketNsec,
936                         sizeof(kSamplePacketNsec));
937 }
938 
TEST_F(MDnsTest,NsecWithTransactionFromCache)939 TEST_F(MDnsTest, NsecWithTransactionFromCache) {
940   // Force mDNS to listen.
941   StrictMock<MockListenerDelegate> delegate_irrelevant;
942   scoped_ptr<MDnsListener> listener_irrelevant =
943       test_client_.CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local",
944                                   &delegate_irrelevant);
945   listener_irrelevant->Start();
946 
947   SimulatePacketReceive(kSamplePacketNsec,
948                         sizeof(kSamplePacketNsec));
949 
950   EXPECT_CALL(*this,
951               MockableRecordCallback(MDnsTransaction::RESULT_NSEC, NULL));
952 
953   scoped_ptr<MDnsTransaction> transaction_privet_a =
954       test_client_.CreateTransaction(
955           dns_protocol::kTypeA, "_privet._tcp.local",
956           MDnsTransaction::QUERY_NETWORK |
957           MDnsTransaction::QUERY_CACHE |
958           MDnsTransaction::SINGLE_RESULT,
959           base::Bind(&MDnsTest::MockableRecordCallback,
960                      base::Unretained(this)));
961 
962   ASSERT_TRUE(transaction_privet_a->Start());
963 
964   // Test that a PTR transaction does NOT consider the same NSEC record to be a
965   // valid answer to the query
966 
967   scoped_ptr<MDnsTransaction> transaction_privet_ptr =
968       test_client_.CreateTransaction(
969           dns_protocol::kTypePTR, "_privet._tcp.local",
970           MDnsTransaction::QUERY_NETWORK |
971           MDnsTransaction::QUERY_CACHE |
972           MDnsTransaction::SINGLE_RESULT,
973           base::Bind(&MDnsTest::MockableRecordCallback,
974                      base::Unretained(this)));
975 
976   EXPECT_CALL(socket_factory_, OnSendTo(_)).Times(2);
977 
978   ASSERT_TRUE(transaction_privet_ptr->Start());
979 }
980 
TEST_F(MDnsTest,NsecConflictRemoval)981 TEST_F(MDnsTest, NsecConflictRemoval) {
982   StrictMock<MockListenerDelegate> delegate_privet;
983   scoped_ptr<MDnsListener> listener_privet =
984       test_client_.CreateListener(dns_protocol::kTypeA, "_privet._tcp.local",
985                                   &delegate_privet);
986 
987   ASSERT_TRUE(listener_privet->Start());
988 
989   const RecordParsed* record1;
990   const RecordParsed* record2;
991 
992   EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
993       .WillOnce(SaveArg<1>(&record1));
994 
995   SimulatePacketReceive(kSamplePacketAPrivet,
996                         sizeof(kSamplePacketAPrivet));
997 
998   EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_REMOVED, _))
999       .WillOnce(SaveArg<1>(&record2));
1000 
1001   EXPECT_CALL(delegate_privet,
1002               OnNsecRecord("_privet._tcp.local", dns_protocol::kTypeA));
1003 
1004   SimulatePacketReceive(kSamplePacketNsec,
1005                         sizeof(kSamplePacketNsec));
1006 
1007   EXPECT_EQ(record1, record2);
1008 }
1009 
1010 
1011 // Note: These tests assume that the ipv4 socket will always be created first.
1012 // This is a simplifying assumption based on the way the code works now.
1013 class SimpleMockSocketFactory : public MDnsSocketFactory {
1014  public:
CreateSockets(ScopedVector<DatagramServerSocket> * sockets)1015   virtual void CreateSockets(
1016       ScopedVector<DatagramServerSocket>* sockets) OVERRIDE {
1017     sockets->clear();
1018     sockets->swap(sockets_);
1019   }
1020 
PushSocket(DatagramServerSocket * socket)1021   void PushSocket(DatagramServerSocket* socket) {
1022     sockets_.push_back(socket);
1023   }
1024 
1025  private:
1026   ScopedVector<DatagramServerSocket> sockets_;
1027 };
1028 
1029 class MockMDnsConnectionDelegate : public MDnsConnection::Delegate {
1030  public:
HandlePacket(DnsResponse * response,int size)1031   virtual void HandlePacket(DnsResponse* response, int size) {
1032     HandlePacketInternal(std::string(response->io_buffer()->data(), size));
1033   }
1034 
1035   MOCK_METHOD1(HandlePacketInternal, void(std::string packet));
1036 
1037   MOCK_METHOD1(OnConnectionError, void(int error));
1038 };
1039 
1040 class MDnsConnectionTest : public ::testing::Test {
1041  public:
MDnsConnectionTest()1042   MDnsConnectionTest() : connection_(&delegate_) {
1043   }
1044 
1045  protected:
1046   // Follow successful connection initialization.
SetUp()1047   virtual void SetUp() OVERRIDE {
1048     socket_ipv4_ = new MockMDnsDatagramServerSocket(ADDRESS_FAMILY_IPV4);
1049     socket_ipv6_ = new MockMDnsDatagramServerSocket(ADDRESS_FAMILY_IPV6);
1050     factory_.PushSocket(socket_ipv6_);
1051     factory_.PushSocket(socket_ipv4_);
1052   }
1053 
InitConnection()1054   bool InitConnection() {
1055     return connection_.Init(&factory_);
1056   }
1057 
1058   StrictMock<MockMDnsConnectionDelegate> delegate_;
1059 
1060   MockMDnsDatagramServerSocket* socket_ipv4_;
1061   MockMDnsDatagramServerSocket* socket_ipv6_;
1062   SimpleMockSocketFactory factory_;
1063   MDnsConnection connection_;
1064   TestCompletionCallback callback_;
1065 };
1066 
TEST_F(MDnsConnectionTest,ReceiveSynchronous)1067 TEST_F(MDnsConnectionTest, ReceiveSynchronous) {
1068   std::string sample_packet = MakeString(kSamplePacket1,
1069       sizeof(kSamplePacket1));
1070 
1071   socket_ipv6_->SetResponsePacket(sample_packet);
1072   EXPECT_CALL(*socket_ipv4_, RecvFrom(_, _, _, _))
1073       .WillOnce(Return(ERR_IO_PENDING));
1074   EXPECT_CALL(*socket_ipv6_, RecvFrom(_, _, _, _))
1075       .WillOnce(
1076           Invoke(socket_ipv6_, &MockMDnsDatagramServerSocket::HandleRecvNow))
1077       .WillOnce(Return(ERR_IO_PENDING));
1078 
1079   EXPECT_CALL(delegate_, HandlePacketInternal(sample_packet));
1080 
1081   ASSERT_TRUE(InitConnection());
1082 }
1083 
TEST_F(MDnsConnectionTest,ReceiveAsynchronous)1084 TEST_F(MDnsConnectionTest, ReceiveAsynchronous) {
1085   std::string sample_packet = MakeString(kSamplePacket1,
1086       sizeof(kSamplePacket1));
1087   socket_ipv6_->SetResponsePacket(sample_packet);
1088   EXPECT_CALL(*socket_ipv4_, RecvFrom(_, _, _, _))
1089       .WillOnce(Return(ERR_IO_PENDING));
1090   EXPECT_CALL(*socket_ipv6_, RecvFrom(_, _, _, _))
1091       .WillOnce(
1092           Invoke(socket_ipv6_, &MockMDnsDatagramServerSocket::HandleRecvLater))
1093       .WillOnce(Return(ERR_IO_PENDING));
1094 
1095   ASSERT_TRUE(InitConnection());
1096 
1097   EXPECT_CALL(delegate_, HandlePacketInternal(sample_packet));
1098 
1099   base::MessageLoop::current()->RunUntilIdle();
1100 }
1101 
TEST_F(MDnsConnectionTest,Send)1102 TEST_F(MDnsConnectionTest, Send) {
1103   std::string sample_packet = MakeString(kSamplePacket1,
1104       sizeof(kSamplePacket1));
1105 
1106   scoped_refptr<IOBufferWithSize> buf(
1107       new IOBufferWithSize(sizeof kSamplePacket1));
1108   memcpy(buf->data(), kSamplePacket1, sizeof(kSamplePacket1));
1109 
1110   EXPECT_CALL(*socket_ipv4_, RecvFrom(_, _, _, _))
1111       .WillOnce(Return(ERR_IO_PENDING));
1112   EXPECT_CALL(*socket_ipv6_, RecvFrom(_, _, _, _))
1113       .WillOnce(Return(ERR_IO_PENDING));
1114 
1115   ASSERT_TRUE(InitConnection());
1116 
1117   EXPECT_CALL(*socket_ipv4_,
1118               SendToInternal(sample_packet, "224.0.0.251:5353", _));
1119   EXPECT_CALL(*socket_ipv6_,
1120               SendToInternal(sample_packet, "[ff02::fb]:5353", _));
1121 
1122   connection_.Send(buf, buf->size());
1123 }
1124 
TEST_F(MDnsConnectionTest,Error)1125 TEST_F(MDnsConnectionTest, Error) {
1126   CompletionCallback callback;
1127 
1128   EXPECT_CALL(*socket_ipv4_, RecvFrom(_, _, _, _))
1129       .WillOnce(Return(ERR_IO_PENDING));
1130   EXPECT_CALL(*socket_ipv6_, RecvFrom(_, _, _, _))
1131       .WillOnce(DoAll(SaveArg<3>(&callback),  Return(ERR_IO_PENDING)));
1132 
1133   ASSERT_TRUE(InitConnection());
1134 
1135   EXPECT_CALL(delegate_, OnConnectionError(ERR_SOCKET_NOT_CONNECTED));
1136   callback.Run(ERR_SOCKET_NOT_CONNECTED);
1137 }
1138 
1139 }  // namespace
1140 
1141 }  // namespace net
1142