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