• 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 kQueryPacketPrivetA[] = {
245   // Header
246   0x00, 0x00,               // ID is zeroed out
247   0x00, 0x00,               // No flags.
248   0x00, 0x01,               // One question.
249   0x00, 0x00,               // 0 RRs (answers)
250   0x00, 0x00,               // 0 authority RRs
251   0x00, 0x00,               // 0 additional RRs
252 
253   // Question
254   // This part is echoed back from the respective query.
255   0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
256   0x04, '_', 't', 'c', 'p',
257   0x05, 'l', 'o', 'c', 'a', 'l',
258   0x00,
259   0x00, 0x01,        // TYPE is A.
260   0x00, 0x01,        // CLASS is IN.
261 };
262 
263 const uint8 kSamplePacketAdditionalOnly[] = {
264   // Header
265   0x00, 0x00,               // ID is zeroed out
266   0x81, 0x80,               // Standard query response, RA, no error
267   0x00, 0x00,               // No questions (for simplicity)
268   0x00, 0x00,               // 2 RRs (answers)
269   0x00, 0x00,               // 0 authority RRs
270   0x00, 0x01,               // 0 additional RRs
271 
272   // Answer 1
273   0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
274   0x04, '_', 't', 'c', 'p',
275   0x05, 'l', 'o', 'c', 'a', 'l',
276   0x00,
277   0x00, 0x0c,        // TYPE is PTR.
278   0x00, 0x01,        // CLASS is IN.
279   0x00, 0x01,        // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
280   0x24, 0x74,
281   0x00, 0x08,        // RDLENGTH is 8 bytes.
282   0x05, 'h', 'e', 'l', 'l', 'o',
283   0xc0, 0x0c,
284 };
285 
286 const uint8 kSamplePacketNsec[] = {
287   // Header
288   0x00, 0x00,               // ID is zeroed out
289   0x81, 0x80,               // Standard query response, RA, no error
290   0x00, 0x00,               // No questions (for simplicity)
291   0x00, 0x01,               // 1 RR (answers)
292   0x00, 0x00,               // 0 authority RRs
293   0x00, 0x00,               // 0 additional RRs
294 
295   // Answer 1
296   0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
297   0x04, '_', 't', 'c', 'p',
298   0x05, 'l', 'o', 'c', 'a', 'l',
299   0x00,
300   0x00, 0x2f,        // TYPE is NSEC.
301   0x00, 0x01,        // CLASS is IN.
302   0x00, 0x01,        // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
303   0x24, 0x74,
304   0x00, 0x06,        // RDLENGTH is 6 bytes.
305   0xc0, 0x0c,
306   0x00, 0x02, 0x00, 0x08  // Only A record present
307 };
308 
309 const uint8 kSamplePacketAPrivet[] = {
310   // Header
311   0x00, 0x00,               // ID is zeroed out
312   0x81, 0x80,               // Standard query response, RA, no error
313   0x00, 0x00,               // No questions (for simplicity)
314   0x00, 0x01,               // 1 RR (answers)
315   0x00, 0x00,               // 0 authority RRs
316   0x00, 0x00,               // 0 additional RRs
317 
318   // Answer 1
319   0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
320   0x04, '_', 't', 'c', 'p',
321   0x05, 'l', 'o', 'c', 'a', 'l',
322   0x00,
323   0x00, 0x01,        // TYPE is A.
324   0x00, 0x01,        // CLASS is IN.
325   0x00, 0x00,        // TTL (4 bytes) is 5 seconds
326   0x00, 0x05,
327   0x00, 0x04,        // RDLENGTH is 4 bytes.
328   0xc0, 0x0c,
329   0x00, 0x02,
330 };
331 
332 const uint8 kSamplePacketGoodbye[] = {
333   // Header
334   0x00, 0x00,               // ID is zeroed out
335   0x81, 0x80,               // Standard query response, RA, no error
336   0x00, 0x00,               // No questions (for simplicity)
337   0x00, 0x01,               // 2 RRs (answers)
338   0x00, 0x00,               // 0 authority RRs
339   0x00, 0x00,               // 0 additional RRs
340 
341   // Answer 1
342   0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
343   0x04, '_', 't', 'c', 'p',
344   0x05, 'l', 'o', 'c', 'a', 'l',
345   0x00,
346   0x00, 0x0c,        // TYPE is PTR.
347   0x00, 0x01,        // CLASS is IN.
348   0x00, 0x00,        // TTL (4 bytes) is zero;
349   0x00, 0x00,
350   0x00, 0x08,        // RDLENGTH is 8 bytes.
351   0x05, 'z', 'z', 'z', 'z', 'z',
352   0xc0, 0x0c,
353 };
354 
MakeString(const uint8 * data,unsigned size)355 std::string MakeString(const uint8* data, unsigned size) {
356   return std::string(reinterpret_cast<const char*>(data), size);
357 }
358 
359 class PtrRecordCopyContainer {
360  public:
PtrRecordCopyContainer()361   PtrRecordCopyContainer() {}
~PtrRecordCopyContainer()362   ~PtrRecordCopyContainer() {}
363 
is_set() const364   bool is_set() const { return set_; }
365 
SaveWithDummyArg(int unused,const RecordParsed * value)366   void SaveWithDummyArg(int unused, const RecordParsed* value) {
367     Save(value);
368   }
369 
Save(const RecordParsed * value)370   void Save(const RecordParsed* value) {
371     set_ = true;
372     name_ = value->name();
373     ptrdomain_ = value->rdata<PtrRecordRdata>()->ptrdomain();
374     ttl_ = value->ttl();
375   }
376 
IsRecordWith(std::string name,std::string ptrdomain)377   bool IsRecordWith(std::string name, std::string ptrdomain) {
378     return set_ && name_ == name && ptrdomain_ == ptrdomain;
379   }
380 
name()381   const std::string& name() { return name_; }
ptrdomain()382   const std::string& ptrdomain() { return ptrdomain_; }
ttl()383   int ttl() { return ttl_; }
384 
385  private:
386   bool set_;
387   std::string name_;
388   std::string ptrdomain_;
389   int ttl_;
390 };
391 
392 class MDnsTest : public ::testing::Test {
393  public:
394   virtual void SetUp() OVERRIDE;
395   void DeleteTransaction();
396   void DeleteBothListeners();
397   void RunFor(base::TimeDelta time_period);
398   void Stop();
399 
400   MOCK_METHOD2(MockableRecordCallback, void(MDnsTransaction::Result result,
401                                             const RecordParsed* record));
402 
403   MOCK_METHOD2(MockableRecordCallback2, void(MDnsTransaction::Result result,
404                                              const RecordParsed* record));
405 
406 
407  protected:
408   void ExpectPacket(const uint8* packet, unsigned size);
409   void SimulatePacketReceive(const uint8* packet, unsigned size);
410 
411   MDnsClientImpl test_client_;
412   IPEndPoint mdns_ipv4_endpoint_;
413   StrictMock<MockMDnsSocketFactory> socket_factory_;
414 
415   // Transactions and listeners that can be deleted by class methods for
416   // reentrancy tests.
417   scoped_ptr<MDnsTransaction> transaction_;
418   scoped_ptr<MDnsListener> listener1_;
419   scoped_ptr<MDnsListener> listener2_;
420 };
421 
422 class MockListenerDelegate : public MDnsListener::Delegate {
423  public:
424   MOCK_METHOD2(OnRecordUpdate,
425                void(MDnsListener::UpdateType update,
426                     const RecordParsed* records));
427   MOCK_METHOD2(OnNsecRecord, void(const std::string&, unsigned));
428   MOCK_METHOD0(OnCachePurged, void());
429 };
430 
SetUp()431 void MDnsTest::SetUp() {
432   test_client_.StartListening(&socket_factory_);
433 }
434 
SimulatePacketReceive(const uint8 * packet,unsigned size)435 void MDnsTest::SimulatePacketReceive(const uint8* packet, unsigned size) {
436   socket_factory_.SimulateReceive(packet, size);
437 }
438 
ExpectPacket(const uint8 * packet,unsigned size)439 void MDnsTest::ExpectPacket(const uint8* packet, unsigned size) {
440   EXPECT_CALL(socket_factory_, OnSendTo(MakeString(packet, size)))
441       .Times(2);
442 }
443 
DeleteTransaction()444 void MDnsTest::DeleteTransaction() {
445   transaction_.reset();
446 }
447 
DeleteBothListeners()448 void MDnsTest::DeleteBothListeners() {
449   listener1_.reset();
450   listener2_.reset();
451 }
452 
RunFor(base::TimeDelta time_period)453 void MDnsTest::RunFor(base::TimeDelta time_period) {
454   base::CancelableCallback<void()> callback(base::Bind(&MDnsTest::Stop,
455                                                        base::Unretained(this)));
456   base::MessageLoop::current()->PostDelayedTask(
457       FROM_HERE, callback.callback(), time_period);
458 
459   base::MessageLoop::current()->Run();
460   callback.Cancel();
461 }
462 
Stop()463 void MDnsTest::Stop() {
464   base::MessageLoop::current()->Quit();
465 }
466 
TEST_F(MDnsTest,PassiveListeners)467 TEST_F(MDnsTest, PassiveListeners) {
468   StrictMock<MockListenerDelegate> delegate_privet;
469   StrictMock<MockListenerDelegate> delegate_printer;
470 
471   PtrRecordCopyContainer record_privet;
472   PtrRecordCopyContainer record_printer;
473 
474   scoped_ptr<MDnsListener> listener_privet =
475       test_client_.CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local",
476                                   &delegate_privet);
477   scoped_ptr<MDnsListener> listener_printer =
478       test_client_.CreateListener(dns_protocol::kTypePTR, "_printer._tcp.local",
479                                   &delegate_printer);
480 
481   ASSERT_TRUE(listener_privet->Start());
482   ASSERT_TRUE(listener_printer->Start());
483 
484   // Send the same packet twice to ensure no records are double-counted.
485 
486   EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
487       .Times(Exactly(1))
488       .WillOnce(Invoke(
489           &record_privet,
490           &PtrRecordCopyContainer::SaveWithDummyArg));
491 
492   EXPECT_CALL(delegate_printer, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
493       .Times(Exactly(1))
494       .WillOnce(Invoke(
495           &record_printer,
496           &PtrRecordCopyContainer::SaveWithDummyArg));
497 
498 
499   SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
500   SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
501 
502   EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
503                                          "hello._privet._tcp.local"));
504 
505   EXPECT_TRUE(record_printer.IsRecordWith("_printer._tcp.local",
506                                           "hello._printer._tcp.local"));
507 
508   listener_privet.reset();
509   listener_printer.reset();
510 }
511 
TEST_F(MDnsTest,PassiveListenersCacheCleanup)512 TEST_F(MDnsTest, PassiveListenersCacheCleanup) {
513   StrictMock<MockListenerDelegate> delegate_privet;
514 
515   PtrRecordCopyContainer record_privet;
516   PtrRecordCopyContainer record_privet2;
517 
518   scoped_ptr<MDnsListener> listener_privet =
519       test_client_.CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local",
520                                   &delegate_privet);
521 
522   ASSERT_TRUE(listener_privet->Start());
523 
524   EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
525       .Times(Exactly(1))
526       .WillOnce(Invoke(
527           &record_privet,
528           &PtrRecordCopyContainer::SaveWithDummyArg));
529 
530   SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
531 
532   EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
533                                          "hello._privet._tcp.local"));
534 
535   // Expect record is removed when its TTL expires.
536   EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_REMOVED, _))
537       .Times(Exactly(1))
538       .WillOnce(DoAll(InvokeWithoutArgs(this, &MDnsTest::Stop),
539                       Invoke(&record_privet2,
540                              &PtrRecordCopyContainer::SaveWithDummyArg)));
541 
542   RunFor(base::TimeDelta::FromSeconds(record_privet.ttl() + 1));
543 
544   EXPECT_TRUE(record_privet2.IsRecordWith("_privet._tcp.local",
545                                           "hello._privet._tcp.local"));
546 }
547 
TEST_F(MDnsTest,MalformedPacket)548 TEST_F(MDnsTest, MalformedPacket) {
549   StrictMock<MockListenerDelegate> delegate_printer;
550 
551   PtrRecordCopyContainer record_printer;
552 
553   scoped_ptr<MDnsListener> listener_printer =
554       test_client_.CreateListener(dns_protocol::kTypePTR, "_printer._tcp.local",
555                                   &delegate_printer);
556 
557   ASSERT_TRUE(listener_printer->Start());
558 
559   EXPECT_CALL(delegate_printer, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
560       .Times(Exactly(1))
561       .WillOnce(Invoke(
562           &record_printer,
563           &PtrRecordCopyContainer::SaveWithDummyArg));
564 
565   // First, send unsalvagable packet to ensure we can deal with it.
566   SimulatePacketReceive(kCorruptedPacketUnsalvagable,
567                         sizeof(kCorruptedPacketUnsalvagable));
568 
569   // Regression test: send a packet where the question cannot be read.
570   SimulatePacketReceive(kCorruptedPacketBadQuestion,
571                         sizeof(kCorruptedPacketBadQuestion));
572 
573   // Then send salvagable packet to ensure we can extract useful records.
574   SimulatePacketReceive(kCorruptedPacketSalvagable,
575                         sizeof(kCorruptedPacketSalvagable));
576 
577   EXPECT_TRUE(record_printer.IsRecordWith("_printer._tcp.local",
578                                           "hello._printer._tcp.local"));
579 }
580 
TEST_F(MDnsTest,TransactionWithEmptyCache)581 TEST_F(MDnsTest, TransactionWithEmptyCache) {
582   ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
583 
584   scoped_ptr<MDnsTransaction> transaction_privet =
585       test_client_.CreateTransaction(
586           dns_protocol::kTypePTR, "_privet._tcp.local",
587           MDnsTransaction::QUERY_NETWORK |
588           MDnsTransaction::QUERY_CACHE |
589           MDnsTransaction::SINGLE_RESULT,
590           base::Bind(&MDnsTest::MockableRecordCallback,
591                      base::Unretained(this)));
592 
593   ASSERT_TRUE(transaction_privet->Start());
594 
595   PtrRecordCopyContainer record_privet;
596 
597   EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD, _))
598       .Times(Exactly(1))
599       .WillOnce(Invoke(&record_privet,
600                        &PtrRecordCopyContainer::SaveWithDummyArg));
601 
602   SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
603 
604   EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
605                                          "hello._privet._tcp.local"));
606 }
607 
TEST_F(MDnsTest,TransactionCacheOnlyNoResult)608 TEST_F(MDnsTest, TransactionCacheOnlyNoResult) {
609   scoped_ptr<MDnsTransaction> transaction_privet =
610       test_client_.CreateTransaction(
611           dns_protocol::kTypePTR, "_privet._tcp.local",
612           MDnsTransaction::QUERY_CACHE |
613           MDnsTransaction::SINGLE_RESULT,
614           base::Bind(&MDnsTest::MockableRecordCallback,
615                      base::Unretained(this)));
616 
617   EXPECT_CALL(*this,
618               MockableRecordCallback(MDnsTransaction::RESULT_NO_RESULTS, _))
619       .Times(Exactly(1));
620 
621   ASSERT_TRUE(transaction_privet->Start());
622 }
623 
TEST_F(MDnsTest,TransactionWithCache)624 TEST_F(MDnsTest, TransactionWithCache) {
625   // Listener to force the client to listen
626   StrictMock<MockListenerDelegate> delegate_irrelevant;
627   scoped_ptr<MDnsListener> listener_irrelevant =
628       test_client_.CreateListener(dns_protocol::kTypeA,
629                                   "codereview.chromium.local",
630                                   &delegate_irrelevant);
631 
632   ASSERT_TRUE(listener_irrelevant->Start());
633 
634   SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
635 
636 
637   PtrRecordCopyContainer record_privet;
638 
639   EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD, _))
640       .WillOnce(Invoke(&record_privet,
641                        &PtrRecordCopyContainer::SaveWithDummyArg));
642 
643   scoped_ptr<MDnsTransaction> transaction_privet =
644       test_client_.CreateTransaction(
645           dns_protocol::kTypePTR, "_privet._tcp.local",
646           MDnsTransaction::QUERY_NETWORK |
647           MDnsTransaction::QUERY_CACHE |
648           MDnsTransaction::SINGLE_RESULT,
649           base::Bind(&MDnsTest::MockableRecordCallback,
650                      base::Unretained(this)));
651 
652   ASSERT_TRUE(transaction_privet->Start());
653 
654   EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
655                                          "hello._privet._tcp.local"));
656 }
657 
TEST_F(MDnsTest,AdditionalRecords)658 TEST_F(MDnsTest, AdditionalRecords) {
659   StrictMock<MockListenerDelegate> delegate_privet;
660 
661   PtrRecordCopyContainer record_privet;
662 
663   scoped_ptr<MDnsListener> listener_privet =
664       test_client_.CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local",
665                                   &delegate_privet);
666 
667   ASSERT_TRUE(listener_privet->Start());
668 
669   EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
670       .Times(Exactly(1))
671       .WillOnce(Invoke(
672           &record_privet,
673           &PtrRecordCopyContainer::SaveWithDummyArg));
674 
675   SimulatePacketReceive(kSamplePacketAdditionalOnly,
676                         sizeof(kSamplePacketAdditionalOnly));
677 
678   EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
679                                          "hello._privet._tcp.local"));
680 }
681 
TEST_F(MDnsTest,TransactionTimeout)682 TEST_F(MDnsTest, TransactionTimeout) {
683   ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
684 
685   scoped_ptr<MDnsTransaction> transaction_privet =
686       test_client_.CreateTransaction(
687           dns_protocol::kTypePTR, "_privet._tcp.local",
688           MDnsTransaction::QUERY_NETWORK |
689           MDnsTransaction::QUERY_CACHE |
690           MDnsTransaction::SINGLE_RESULT,
691           base::Bind(&MDnsTest::MockableRecordCallback,
692                      base::Unretained(this)));
693 
694   ASSERT_TRUE(transaction_privet->Start());
695 
696   EXPECT_CALL(*this,
697               MockableRecordCallback(MDnsTransaction::RESULT_NO_RESULTS, NULL))
698       .Times(Exactly(1))
699       .WillOnce(InvokeWithoutArgs(this, &MDnsTest::Stop));
700 
701   RunFor(base::TimeDelta::FromSeconds(4));
702 }
703 
TEST_F(MDnsTest,TransactionMultipleRecords)704 TEST_F(MDnsTest, TransactionMultipleRecords) {
705   ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
706 
707   scoped_ptr<MDnsTransaction> transaction_privet =
708       test_client_.CreateTransaction(
709           dns_protocol::kTypePTR, "_privet._tcp.local",
710           MDnsTransaction::QUERY_NETWORK |
711           MDnsTransaction::QUERY_CACHE ,
712           base::Bind(&MDnsTest::MockableRecordCallback,
713                      base::Unretained(this)));
714 
715   ASSERT_TRUE(transaction_privet->Start());
716 
717   PtrRecordCopyContainer record_privet;
718   PtrRecordCopyContainer record_privet2;
719 
720   EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD, _))
721       .Times(Exactly(2))
722       .WillOnce(Invoke(&record_privet,
723                        &PtrRecordCopyContainer::SaveWithDummyArg))
724       .WillOnce(Invoke(&record_privet2,
725                        &PtrRecordCopyContainer::SaveWithDummyArg));
726 
727   SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
728   SimulatePacketReceive(kSamplePacket2, sizeof(kSamplePacket2));
729 
730   EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
731                                          "hello._privet._tcp.local"));
732 
733   EXPECT_TRUE(record_privet2.IsRecordWith("_privet._tcp.local",
734                                           "zzzzz._privet._tcp.local"));
735 
736   EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_DONE, NULL))
737       .WillOnce(InvokeWithoutArgs(this, &MDnsTest::Stop));
738 
739   RunFor(base::TimeDelta::FromSeconds(4));
740 }
741 
TEST_F(MDnsTest,TransactionReentrantDelete)742 TEST_F(MDnsTest, TransactionReentrantDelete) {
743   ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
744 
745   transaction_ = test_client_.CreateTransaction(
746       dns_protocol::kTypePTR, "_privet._tcp.local",
747       MDnsTransaction::QUERY_NETWORK |
748       MDnsTransaction::QUERY_CACHE |
749       MDnsTransaction::SINGLE_RESULT,
750       base::Bind(&MDnsTest::MockableRecordCallback,
751                  base::Unretained(this)));
752 
753   ASSERT_TRUE(transaction_->Start());
754 
755   EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_NO_RESULTS,
756                                             NULL))
757       .Times(Exactly(1))
758       .WillOnce(DoAll(InvokeWithoutArgs(this, &MDnsTest::DeleteTransaction),
759                       InvokeWithoutArgs(this, &MDnsTest::Stop)));
760 
761   RunFor(base::TimeDelta::FromSeconds(4));
762 
763   EXPECT_EQ(NULL, transaction_.get());
764 }
765 
TEST_F(MDnsTest,TransactionReentrantDeleteFromCache)766 TEST_F(MDnsTest, TransactionReentrantDeleteFromCache) {
767   StrictMock<MockListenerDelegate> delegate_irrelevant;
768   scoped_ptr<MDnsListener> listener_irrelevant = test_client_.CreateListener(
769       dns_protocol::kTypeA, "codereview.chromium.local",
770       &delegate_irrelevant);
771   ASSERT_TRUE(listener_irrelevant->Start());
772 
773   SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
774 
775   transaction_ = test_client_.CreateTransaction(
776       dns_protocol::kTypePTR, "_privet._tcp.local",
777       MDnsTransaction::QUERY_NETWORK |
778       MDnsTransaction::QUERY_CACHE,
779       base::Bind(&MDnsTest::MockableRecordCallback,
780                  base::Unretained(this)));
781 
782   EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD, _))
783       .Times(Exactly(1))
784       .WillOnce(InvokeWithoutArgs(this, &MDnsTest::DeleteTransaction));
785 
786   ASSERT_TRUE(transaction_->Start());
787 
788   EXPECT_EQ(NULL, transaction_.get());
789 }
790 
TEST_F(MDnsTest,TransactionReentrantCacheLookupStart)791 TEST_F(MDnsTest, TransactionReentrantCacheLookupStart) {
792   ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
793 
794   scoped_ptr<MDnsTransaction> transaction1 =
795       test_client_.CreateTransaction(
796           dns_protocol::kTypePTR, "_privet._tcp.local",
797           MDnsTransaction::QUERY_NETWORK |
798           MDnsTransaction::QUERY_CACHE |
799           MDnsTransaction::SINGLE_RESULT,
800           base::Bind(&MDnsTest::MockableRecordCallback,
801                      base::Unretained(this)));
802 
803   scoped_ptr<MDnsTransaction> transaction2 =
804       test_client_.CreateTransaction(
805           dns_protocol::kTypePTR, "_printer._tcp.local",
806           MDnsTransaction::QUERY_CACHE |
807           MDnsTransaction::SINGLE_RESULT,
808           base::Bind(&MDnsTest::MockableRecordCallback2,
809                      base::Unretained(this)));
810 
811   EXPECT_CALL(*this, MockableRecordCallback2(MDnsTransaction::RESULT_RECORD,
812                                              _))
813       .Times(Exactly(1));
814 
815   EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD,
816                                             _))
817       .Times(Exactly(1))
818       .WillOnce(IgnoreResult(InvokeWithoutArgs(transaction2.get(),
819                                                &MDnsTransaction::Start)));
820 
821   ASSERT_TRUE(transaction1->Start());
822 
823   SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
824 }
825 
TEST_F(MDnsTest,GoodbyePacketNotification)826 TEST_F(MDnsTest, GoodbyePacketNotification) {
827   StrictMock<MockListenerDelegate> delegate_privet;
828 
829   scoped_ptr<MDnsListener> listener_privet = test_client_.CreateListener(
830       dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet);
831   ASSERT_TRUE(listener_privet->Start());
832 
833   SimulatePacketReceive(kSamplePacketGoodbye, sizeof(kSamplePacketGoodbye));
834 
835   RunFor(base::TimeDelta::FromSeconds(2));
836 }
837 
TEST_F(MDnsTest,GoodbyePacketRemoval)838 TEST_F(MDnsTest, GoodbyePacketRemoval) {
839   StrictMock<MockListenerDelegate> delegate_privet;
840 
841   scoped_ptr<MDnsListener> listener_privet =
842       test_client_.CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local",
843                                   &delegate_privet);
844   ASSERT_TRUE(listener_privet->Start());
845 
846   EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
847       .Times(Exactly(1));
848 
849   SimulatePacketReceive(kSamplePacket2, sizeof(kSamplePacket2));
850 
851   SimulatePacketReceive(kSamplePacketGoodbye, sizeof(kSamplePacketGoodbye));
852 
853   EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_REMOVED, _))
854       .Times(Exactly(1));
855 
856   RunFor(base::TimeDelta::FromSeconds(2));
857 }
858 
859 // In order to reliably test reentrant listener deletes, we create two listeners
860 // and have each of them delete both, so we're guaranteed to try and deliver a
861 // callback to at least one deleted listener.
862 
TEST_F(MDnsTest,ListenerReentrantDelete)863 TEST_F(MDnsTest, ListenerReentrantDelete) {
864   StrictMock<MockListenerDelegate> delegate_privet;
865 
866   listener1_ = test_client_.CreateListener(dns_protocol::kTypePTR,
867                                            "_privet._tcp.local",
868                                            &delegate_privet);
869 
870   listener2_ = test_client_.CreateListener(dns_protocol::kTypePTR,
871                                            "_privet._tcp.local",
872                                            &delegate_privet);
873 
874   ASSERT_TRUE(listener1_->Start());
875 
876   ASSERT_TRUE(listener2_->Start());
877 
878   EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
879       .Times(Exactly(1))
880       .WillOnce(InvokeWithoutArgs(this, &MDnsTest::DeleteBothListeners));
881 
882   SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
883 
884   EXPECT_EQ(NULL, listener1_.get());
885   EXPECT_EQ(NULL, listener2_.get());
886 }
887 
ACTION_P(SaveIPAddress,ip_container)888 ACTION_P(SaveIPAddress, ip_container) {
889   ::testing::StaticAssertTypeEq<const RecordParsed*, arg1_type>();
890   ::testing::StaticAssertTypeEq<IPAddressNumber*, ip_container_type>();
891 
892   *ip_container = arg1->template rdata<ARecordRdata>()->address();
893 }
894 
TEST_F(MDnsTest,DoubleRecordDisagreeing)895 TEST_F(MDnsTest, DoubleRecordDisagreeing) {
896   IPAddressNumber address;
897   StrictMock<MockListenerDelegate> delegate_privet;
898 
899   scoped_ptr<MDnsListener> listener_privet =
900       test_client_.CreateListener(dns_protocol::kTypeA, "privet.local",
901                                   &delegate_privet);
902 
903   ASSERT_TRUE(listener_privet->Start());
904 
905   EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
906       .Times(Exactly(1))
907       .WillOnce(SaveIPAddress(&address));
908 
909   SimulatePacketReceive(kCorruptedPacketDoubleRecord,
910                         sizeof(kCorruptedPacketDoubleRecord));
911 
912   EXPECT_EQ("2.3.4.5", IPAddressToString(address));
913 }
914 
TEST_F(MDnsTest,NsecWithListener)915 TEST_F(MDnsTest, NsecWithListener) {
916   StrictMock<MockListenerDelegate> delegate_privet;
917   scoped_ptr<MDnsListener> listener_privet =
918       test_client_.CreateListener(dns_protocol::kTypeA, "_privet._tcp.local",
919                                   &delegate_privet);
920 
921   // Test to make sure nsec callback is NOT called for PTR
922   // (which is marked as existing).
923   StrictMock<MockListenerDelegate> delegate_privet2;
924   scoped_ptr<MDnsListener> listener_privet2 =
925       test_client_.CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local",
926                                   &delegate_privet2);
927 
928   ASSERT_TRUE(listener_privet->Start());
929 
930   EXPECT_CALL(delegate_privet,
931               OnNsecRecord("_privet._tcp.local", dns_protocol::kTypeA));
932 
933   SimulatePacketReceive(kSamplePacketNsec,
934                         sizeof(kSamplePacketNsec));
935 }
936 
TEST_F(MDnsTest,NsecWithTransactionFromNetwork)937 TEST_F(MDnsTest, NsecWithTransactionFromNetwork) {
938   scoped_ptr<MDnsTransaction> transaction_privet =
939       test_client_.CreateTransaction(
940           dns_protocol::kTypeA, "_privet._tcp.local",
941           MDnsTransaction::QUERY_NETWORK |
942           MDnsTransaction::QUERY_CACHE |
943           MDnsTransaction::SINGLE_RESULT,
944           base::Bind(&MDnsTest::MockableRecordCallback,
945                      base::Unretained(this)));
946 
947   EXPECT_CALL(socket_factory_, OnSendTo(_)).Times(2);
948 
949   ASSERT_TRUE(transaction_privet->Start());
950 
951   EXPECT_CALL(*this,
952               MockableRecordCallback(MDnsTransaction::RESULT_NSEC, NULL));
953 
954   SimulatePacketReceive(kSamplePacketNsec,
955                         sizeof(kSamplePacketNsec));
956 }
957 
TEST_F(MDnsTest,NsecWithTransactionFromCache)958 TEST_F(MDnsTest, NsecWithTransactionFromCache) {
959   // Force mDNS to listen.
960   StrictMock<MockListenerDelegate> delegate_irrelevant;
961   scoped_ptr<MDnsListener> listener_irrelevant =
962       test_client_.CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local",
963                                   &delegate_irrelevant);
964   listener_irrelevant->Start();
965 
966   SimulatePacketReceive(kSamplePacketNsec,
967                         sizeof(kSamplePacketNsec));
968 
969   EXPECT_CALL(*this,
970               MockableRecordCallback(MDnsTransaction::RESULT_NSEC, NULL));
971 
972   scoped_ptr<MDnsTransaction> transaction_privet_a =
973       test_client_.CreateTransaction(
974           dns_protocol::kTypeA, "_privet._tcp.local",
975           MDnsTransaction::QUERY_NETWORK |
976           MDnsTransaction::QUERY_CACHE |
977           MDnsTransaction::SINGLE_RESULT,
978           base::Bind(&MDnsTest::MockableRecordCallback,
979                      base::Unretained(this)));
980 
981   ASSERT_TRUE(transaction_privet_a->Start());
982 
983   // Test that a PTR transaction does NOT consider the same NSEC record to be a
984   // valid answer to the query
985 
986   scoped_ptr<MDnsTransaction> transaction_privet_ptr =
987       test_client_.CreateTransaction(
988           dns_protocol::kTypePTR, "_privet._tcp.local",
989           MDnsTransaction::QUERY_NETWORK |
990           MDnsTransaction::QUERY_CACHE |
991           MDnsTransaction::SINGLE_RESULT,
992           base::Bind(&MDnsTest::MockableRecordCallback,
993                      base::Unretained(this)));
994 
995   EXPECT_CALL(socket_factory_, OnSendTo(_)).Times(2);
996 
997   ASSERT_TRUE(transaction_privet_ptr->Start());
998 }
999 
TEST_F(MDnsTest,NsecConflictRemoval)1000 TEST_F(MDnsTest, NsecConflictRemoval) {
1001   StrictMock<MockListenerDelegate> delegate_privet;
1002   scoped_ptr<MDnsListener> listener_privet =
1003       test_client_.CreateListener(dns_protocol::kTypeA, "_privet._tcp.local",
1004                                   &delegate_privet);
1005 
1006   ASSERT_TRUE(listener_privet->Start());
1007 
1008   const RecordParsed* record1;
1009   const RecordParsed* record2;
1010 
1011   EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
1012       .WillOnce(SaveArg<1>(&record1));
1013 
1014   SimulatePacketReceive(kSamplePacketAPrivet,
1015                         sizeof(kSamplePacketAPrivet));
1016 
1017   EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_REMOVED, _))
1018       .WillOnce(SaveArg<1>(&record2));
1019 
1020   EXPECT_CALL(delegate_privet,
1021               OnNsecRecord("_privet._tcp.local", dns_protocol::kTypeA));
1022 
1023   SimulatePacketReceive(kSamplePacketNsec,
1024                         sizeof(kSamplePacketNsec));
1025 
1026   EXPECT_EQ(record1, record2);
1027 }
1028 
1029 
TEST_F(MDnsTest,RefreshQuery)1030 TEST_F(MDnsTest, RefreshQuery) {
1031   StrictMock<MockListenerDelegate> delegate_privet;
1032   scoped_ptr<MDnsListener> listener_privet =
1033       test_client_.CreateListener(dns_protocol::kTypeA, "_privet._tcp.local",
1034                                   &delegate_privet);
1035 
1036   listener_privet->SetActiveRefresh(true);
1037   ASSERT_TRUE(listener_privet->Start());
1038 
1039   EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _));
1040 
1041   SimulatePacketReceive(kSamplePacketAPrivet,
1042                         sizeof(kSamplePacketAPrivet));
1043 
1044   // Expecting 2 calls (one for ipv4 and one for ipv6) for each of the 2
1045   // scheduled refresh queries.
1046   EXPECT_CALL(socket_factory_, OnSendTo(
1047       MakeString(kQueryPacketPrivetA, sizeof(kQueryPacketPrivetA))))
1048       .Times(4);
1049 
1050   EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_REMOVED, _));
1051 
1052   RunFor(base::TimeDelta::FromSeconds(6));
1053 }
1054 
1055 // Note: These tests assume that the ipv4 socket will always be created first.
1056 // This is a simplifying assumption based on the way the code works now.
1057 class SimpleMockSocketFactory : public MDnsSocketFactory {
1058  public:
CreateSockets(ScopedVector<DatagramServerSocket> * sockets)1059   virtual void CreateSockets(
1060       ScopedVector<DatagramServerSocket>* sockets) OVERRIDE {
1061     sockets->clear();
1062     sockets->swap(sockets_);
1063   }
1064 
PushSocket(DatagramServerSocket * socket)1065   void PushSocket(DatagramServerSocket* socket) {
1066     sockets_.push_back(socket);
1067   }
1068 
1069  private:
1070   ScopedVector<DatagramServerSocket> sockets_;
1071 };
1072 
1073 class MockMDnsConnectionDelegate : public MDnsConnection::Delegate {
1074  public:
HandlePacket(DnsResponse * response,int size)1075   virtual void HandlePacket(DnsResponse* response, int size) {
1076     HandlePacketInternal(std::string(response->io_buffer()->data(), size));
1077   }
1078 
1079   MOCK_METHOD1(HandlePacketInternal, void(std::string packet));
1080 
1081   MOCK_METHOD1(OnConnectionError, void(int error));
1082 };
1083 
1084 class MDnsConnectionTest : public ::testing::Test {
1085  public:
MDnsConnectionTest()1086   MDnsConnectionTest() : connection_(&delegate_) {
1087   }
1088 
1089  protected:
1090   // Follow successful connection initialization.
SetUp()1091   virtual void SetUp() OVERRIDE {
1092     socket_ipv4_ = new MockMDnsDatagramServerSocket(ADDRESS_FAMILY_IPV4);
1093     socket_ipv6_ = new MockMDnsDatagramServerSocket(ADDRESS_FAMILY_IPV6);
1094     factory_.PushSocket(socket_ipv6_);
1095     factory_.PushSocket(socket_ipv4_);
1096     sample_packet_ = MakeString(kSamplePacket1, sizeof(kSamplePacket1));
1097     sample_buffer_ = new StringIOBuffer(sample_packet_);
1098   }
1099 
InitConnection()1100   bool InitConnection() {
1101     return connection_.Init(&factory_);
1102   }
1103 
1104   StrictMock<MockMDnsConnectionDelegate> delegate_;
1105 
1106   MockMDnsDatagramServerSocket* socket_ipv4_;
1107   MockMDnsDatagramServerSocket* socket_ipv6_;
1108   SimpleMockSocketFactory factory_;
1109   MDnsConnection connection_;
1110   TestCompletionCallback callback_;
1111   std::string sample_packet_;
1112   scoped_refptr<IOBuffer> sample_buffer_;
1113 };
1114 
TEST_F(MDnsConnectionTest,ReceiveSynchronous)1115 TEST_F(MDnsConnectionTest, ReceiveSynchronous) {
1116   socket_ipv6_->SetResponsePacket(sample_packet_);
1117   EXPECT_CALL(*socket_ipv4_, RecvFrom(_, _, _, _))
1118       .WillOnce(Return(ERR_IO_PENDING));
1119   EXPECT_CALL(*socket_ipv6_, RecvFrom(_, _, _, _))
1120       .WillOnce(
1121           Invoke(socket_ipv6_, &MockMDnsDatagramServerSocket::HandleRecvNow))
1122       .WillOnce(Return(ERR_IO_PENDING));
1123 
1124   EXPECT_CALL(delegate_, HandlePacketInternal(sample_packet_));
1125   ASSERT_TRUE(InitConnection());
1126 }
1127 
TEST_F(MDnsConnectionTest,ReceiveAsynchronous)1128 TEST_F(MDnsConnectionTest, ReceiveAsynchronous) {
1129   socket_ipv6_->SetResponsePacket(sample_packet_);
1130 
1131   EXPECT_CALL(*socket_ipv4_, RecvFrom(_, _, _, _))
1132       .WillOnce(Return(ERR_IO_PENDING));
1133   EXPECT_CALL(*socket_ipv6_, RecvFrom(_, _, _, _))
1134       .Times(2)
1135       .WillOnce(
1136            Invoke(socket_ipv6_, &MockMDnsDatagramServerSocket::HandleRecvLater))
1137       .WillOnce(Return(ERR_IO_PENDING));
1138 
1139   ASSERT_TRUE(InitConnection());
1140 
1141   EXPECT_CALL(delegate_, HandlePacketInternal(sample_packet_));
1142 
1143   base::MessageLoop::current()->RunUntilIdle();
1144 }
1145 
TEST_F(MDnsConnectionTest,Error)1146 TEST_F(MDnsConnectionTest, Error) {
1147   CompletionCallback callback;
1148 
1149   EXPECT_CALL(*socket_ipv4_, RecvFrom(_, _, _, _))
1150       .WillOnce(Return(ERR_IO_PENDING));
1151   EXPECT_CALL(*socket_ipv6_, RecvFrom(_, _, _, _))
1152       .WillOnce(DoAll(SaveArg<3>(&callback), Return(ERR_IO_PENDING)));
1153 
1154   ASSERT_TRUE(InitConnection());
1155 
1156   EXPECT_CALL(delegate_, OnConnectionError(ERR_SOCKET_NOT_CONNECTED));
1157   callback.Run(ERR_SOCKET_NOT_CONNECTED);
1158   base::MessageLoop::current()->RunUntilIdle();
1159 }
1160 
1161 class MDnsConnectionSendTest : public MDnsConnectionTest {
1162  protected:
SetUp()1163   virtual void SetUp() OVERRIDE {
1164     MDnsConnectionTest::SetUp();
1165     EXPECT_CALL(*socket_ipv4_, RecvFrom(_, _, _, _))
1166         .WillOnce(Return(ERR_IO_PENDING));
1167     EXPECT_CALL(*socket_ipv6_, RecvFrom(_, _, _, _))
1168         .WillOnce(Return(ERR_IO_PENDING));
1169     EXPECT_TRUE(InitConnection());
1170   }
1171 };
1172 
TEST_F(MDnsConnectionSendTest,Send)1173 TEST_F(MDnsConnectionSendTest, Send) {
1174   EXPECT_CALL(*socket_ipv4_,
1175               SendToInternal(sample_packet_, "224.0.0.251:5353", _));
1176   EXPECT_CALL(*socket_ipv6_,
1177               SendToInternal(sample_packet_, "[ff02::fb]:5353", _));
1178 
1179   connection_.Send(sample_buffer_, sample_packet_.size());
1180 }
1181 
TEST_F(MDnsConnectionSendTest,SendError)1182 TEST_F(MDnsConnectionSendTest, SendError) {
1183   CompletionCallback callback;
1184 
1185   EXPECT_CALL(*socket_ipv4_,
1186               SendToInternal(sample_packet_, "224.0.0.251:5353", _));
1187   EXPECT_CALL(*socket_ipv6_,
1188               SendToInternal(sample_packet_, "[ff02::fb]:5353", _))
1189       .WillOnce(DoAll(SaveArg<2>(&callback), Return(ERR_SOCKET_NOT_CONNECTED)));
1190 
1191   connection_.Send(sample_buffer_, sample_packet_.size());
1192   EXPECT_CALL(delegate_, OnConnectionError(ERR_SOCKET_NOT_CONNECTED));
1193   base::MessageLoop::current()->RunUntilIdle();
1194 }
1195 
TEST_F(MDnsConnectionSendTest,SendQueued)1196 TEST_F(MDnsConnectionSendTest, SendQueued) {
1197   // Send data immediately.
1198   EXPECT_CALL(*socket_ipv4_,
1199               SendToInternal(sample_packet_, "224.0.0.251:5353", _))
1200       .Times(2)
1201       .WillRepeatedly(Return(OK));
1202 
1203   CompletionCallback callback;
1204   // Delay sending data. Only the first call should be made.
1205   EXPECT_CALL(*socket_ipv6_,
1206               SendToInternal(sample_packet_, "[ff02::fb]:5353", _))
1207       .WillOnce(DoAll(SaveArg<2>(&callback), Return(ERR_IO_PENDING)));
1208 
1209   connection_.Send(sample_buffer_, sample_packet_.size());
1210   connection_.Send(sample_buffer_, sample_packet_.size());
1211 
1212   // The second IPv6 packed is not sent yet.
1213   EXPECT_CALL(*socket_ipv4_,
1214               SendToInternal(sample_packet_, "224.0.0.251:5353", _))
1215       .Times(0);
1216   // Expect call for the second IPv6 packed.
1217   EXPECT_CALL(*socket_ipv6_,
1218               SendToInternal(sample_packet_, "[ff02::fb]:5353", _))
1219       .WillOnce(Return(OK));
1220   callback.Run(OK);
1221 }
1222 
1223 }  // namespace
1224 
1225 }  // namespace net
1226