1 // Copyright 2013 The Chromium Authors
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 <memory>
6 #include <utility>
7 #include <vector>
8
9 #include "base/functional/bind.h"
10 #include "base/location.h"
11 #include "base/memory/ptr_util.h"
12 #include "base/memory/raw_ptr.h"
13 #include "base/memory/ref_counted.h"
14 #include "base/run_loop.h"
15 #include "base/task/single_thread_task_runner.h"
16 #include "base/test/simple_test_clock.h"
17 #include "base/time/clock.h"
18 #include "base/time/default_clock.h"
19 #include "base/timer/mock_timer.h"
20 #include "base/timer/timer.h"
21 #include "build/build_config.h"
22 #include "net/base/address_family.h"
23 #include "net/base/completion_repeating_callback.h"
24 #include "net/base/ip_address.h"
25 #include "net/base/rand_callback.h"
26 #include "net/base/test_completion_callback.h"
27 #include "net/dns/mdns_client_impl.h"
28 #include "net/dns/mock_mdns_socket_factory.h"
29 #include "net/dns/record_rdata.h"
30 #include "net/log/net_log.h"
31 #include "net/socket/udp_client_socket.h"
32 #include "net/test/gtest_util.h"
33 #include "net/test/test_with_task_environment.h"
34 #include "testing/gmock/include/gmock/gmock.h"
35 #include "testing/gtest/include/gtest/gtest.h"
36
37 using ::testing::_;
38 using ::testing::Assign;
39 using ::testing::AtMost;
40 using ::testing::DoAll;
41 using ::testing::Exactly;
42 using ::testing::IgnoreResult;
43 using ::testing::Invoke;
44 using ::testing::InvokeWithoutArgs;
45 using ::testing::NiceMock;
46 using ::testing::Return;
47 using ::testing::SaveArg;
48 using ::testing::StrictMock;
49
50 namespace net {
51
52 namespace {
53
54 const uint8_t kSamplePacket1[] = {
55 // Header
56 0x00, 0x00, // ID is zeroed out
57 0x81, 0x80, // Standard query response, RA, no error
58 0x00, 0x00, // No questions (for simplicity)
59 0x00, 0x02, // 2 RRs (answers)
60 0x00, 0x00, // 0 authority RRs
61 0x00, 0x00, // 0 additional RRs
62
63 // Answer 1
64 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't', 0x04, '_', 't', 'c', 'p', 0x05,
65 'l', 'o', 'c', 'a', 'l', 0x00, 0x00, 0x0c, // TYPE is PTR.
66 0x00, 0x01, // CLASS is IN.
67 0x00, 0x00, // TTL (4 bytes) is 1 second;
68 0x00, 0x01, 0x00, 0x08, // RDLENGTH is 8 bytes.
69 0x05, 'h', 'e', 'l', 'l', 'o', 0xc0, 0x0c,
70
71 // Answer 2
72 0x08, '_', 'p', 'r', 'i', 'n', 't', 'e', 'r', 0xc0,
73 0x14, // Pointer to "._tcp.local"
74 0x00, 0x0c, // TYPE is PTR.
75 0x00, 0x01, // CLASS is IN.
76 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 49 seconds.
77 0x24, 0x75, 0x00, 0x08, // RDLENGTH is 8 bytes.
78 0x05, 'h', 'e', 'l', 'l', 'o', 0xc0, 0x32};
79
80 const uint8_t kSamplePacket1WithCapitalization[] = {
81 // Header
82 0x00, 0x00, // ID is zeroed out
83 0x81, 0x80, // Standard query response, RA, no error
84 0x00, 0x00, // No questions (for simplicity)
85 0x00, 0x02, // 2 RRs (answers)
86 0x00, 0x00, // 0 authority RRs
87 0x00, 0x00, // 0 additional RRs
88
89 // Answer 1
90 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't', 0x04, '_', 'T', 'C', 'P', 0x05,
91 'l', 'o', 'c', 'a', 'l', 0x00, 0x00, 0x0c, // TYPE is PTR.
92 0x00, 0x01, // CLASS is IN.
93 0x00, 0x00, // TTL (4 bytes) is 1 second;
94 0x00, 0x01, 0x00, 0x08, // RDLENGTH is 8 bytes.
95 0x05, 'h', 'e', 'l', 'l', 'o', 0xc0, 0x0c,
96
97 // Answer 2
98 0x08, '_', 'P', 'r', 'i', 'n', 't', 'e', 'R', 0xc0,
99 0x14, // Pointer to "._tcp.local"
100 0x00, 0x0c, // TYPE is PTR.
101 0x00, 0x01, // CLASS is IN.
102 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 49 seconds.
103 0x24, 0x75, 0x00, 0x08, // RDLENGTH is 8 bytes.
104 0x05, 'h', 'e', 'l', 'l', 'o', 0xc0, 0x32};
105
106 const uint8_t kCorruptedPacketBadQuestion[] = {
107 // Header
108 0x00, 0x00, // ID is zeroed out
109 0x81, 0x80, // Standard query response, RA, no error
110 0x00, 0x01, // One question
111 0x00, 0x02, // 2 RRs (answers)
112 0x00, 0x00, // 0 authority RRs
113 0x00, 0x00, // 0 additional RRs
114
115 // Question is corrupted and cannot be read.
116 0x99, 'h', 'e', 'l', 'l', 'o', 0x00, 0x00, 0x00, 0x00, 0x00,
117
118 // Answer 1
119 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't', 0x04, '_', 't', 'c', 'p', 0x05,
120 'l', 'o', 'c', 'a', 'l', 0x00, 0x00, 0x0c, // TYPE is PTR.
121 0x00, 0x01, // CLASS is IN.
122 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
123 0x24, 0x74, 0x00, 0x99, // RDLENGTH is impossible
124 0x05, 'h', 'e', 'l', 'l', 'o', 0xc0, 0x0c,
125
126 // Answer 2
127 0x08, '_', 'p', 'r', // Useless trailing data.
128 };
129
130 const uint8_t kCorruptedPacketUnsalvagable[] = {
131 // Header
132 0x00, 0x00, // ID is zeroed out
133 0x81, 0x80, // Standard query response, RA, no error
134 0x00, 0x00, // No questions (for simplicity)
135 0x00, 0x02, // 2 RRs (answers)
136 0x00, 0x00, // 0 authority RRs
137 0x00, 0x00, // 0 additional RRs
138
139 // Answer 1
140 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't', 0x04, '_', 't', 'c', 'p', 0x05,
141 'l', 'o', 'c', 'a', 'l', 0x00, 0x00, 0x0c, // TYPE is PTR.
142 0x00, 0x01, // CLASS is IN.
143 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
144 0x24, 0x74, 0x00, 0x99, // RDLENGTH is impossible
145 0x05, 'h', 'e', 'l', 'l', 'o', 0xc0, 0x0c,
146
147 // Answer 2
148 0x08, '_', 'p', 'r', // Useless trailing data.
149 };
150
151 const uint8_t kCorruptedPacketDoubleRecord[] = {
152 // Header
153 0x00, 0x00, // ID is zeroed out
154 0x81, 0x80, // Standard query response, RA, no error
155 0x00, 0x00, // No questions (for simplicity)
156 0x00, 0x02, // 2 RRs (answers)
157 0x00, 0x00, // 0 authority RRs
158 0x00, 0x00, // 0 additional RRs
159
160 // Answer 1
161 0x06, 'p', 'r', 'i', 'v', 'e', 't', 0x05, 'l', 'o', 'c', 'a', 'l', 0x00,
162 0x00, 0x01, // TYPE is A.
163 0x00, 0x01, // CLASS is IN.
164 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
165 0x24, 0x74, 0x00, 0x04, // RDLENGTH is 4
166 0x05, 0x03, 0xc0, 0x0c,
167
168 // Answer 2 -- Same key
169 0x06, 'p', 'r', 'i', 'v', 'e', 't', 0x05, 'l', 'o', 'c', 'a', 'l', 0x00,
170 0x00, 0x01, // TYPE is A.
171 0x00, 0x01, // CLASS is IN.
172 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
173 0x24, 0x74, 0x00, 0x04, // RDLENGTH is 4
174 0x02, 0x03, 0x04, 0x05,
175 };
176
177 const uint8_t kCorruptedPacketSalvagable[] = {
178 // Header
179 0x00, 0x00, // ID is zeroed out
180 0x81, 0x80, // Standard query response, RA, no error
181 0x00, 0x00, // No questions (for simplicity)
182 0x00, 0x02, // 2 RRs (answers)
183 0x00, 0x00, // 0 authority RRs
184 0x00, 0x00, // 0 additional RRs
185
186 // Answer 1
187 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't', 0x04, '_', 't', 'c', 'p', 0x05,
188 'l', 'o', 'c', 'a', 'l', 0x00, 0x00, 0x0c, // TYPE is PTR.
189 0x00, 0x01, // CLASS is IN.
190 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
191 0x24, 0x74, 0x00, 0x08, // RDLENGTH is 8 bytes.
192 0x99, 'h', 'e', 'l', 'l', 'o', // Bad RDATA format.
193 0xc0, 0x0c,
194
195 // Answer 2
196 0x08, '_', 'p', 'r', 'i', 'n', 't', 'e', 'r', 0xc0,
197 0x14, // Pointer to "._tcp.local"
198 0x00, 0x0c, // TYPE is PTR.
199 0x00, 0x01, // CLASS is IN.
200 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 49 seconds.
201 0x24, 0x75, 0x00, 0x08, // RDLENGTH is 8 bytes.
202 0x05, 'h', 'e', 'l', 'l', 'o', 0xc0, 0x32};
203
204 const uint8_t kSamplePacket2[] = {
205 // Header
206 0x00, 0x00, // ID is zeroed out
207 0x81, 0x80, // Standard query response, RA, no error
208 0x00, 0x00, // No questions (for simplicity)
209 0x00, 0x02, // 2 RRs (answers)
210 0x00, 0x00, // 0 authority RRs
211 0x00, 0x00, // 0 additional RRs
212
213 // Answer 1
214 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't', 0x04, '_', 't', 'c', 'p', 0x05,
215 'l', 'o', 'c', 'a', 'l', 0x00, 0x00, 0x0c, // TYPE is PTR.
216 0x00, 0x01, // CLASS is IN.
217 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
218 0x24, 0x74, 0x00, 0x08, // RDLENGTH is 8 bytes.
219 0x05, 'z', 'z', 'z', 'z', 'z', 0xc0, 0x0c,
220
221 // Answer 2
222 0x08, '_', 'p', 'r', 'i', 'n', 't', 'e', 'r', 0xc0,
223 0x14, // Pointer to "._tcp.local"
224 0x00, 0x0c, // TYPE is PTR.
225 0x00, 0x01, // CLASS is IN.
226 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
227 0x24, 0x74, 0x00, 0x08, // RDLENGTH is 8 bytes.
228 0x05, 'z', 'z', 'z', 'z', 'z', 0xc0, 0x32};
229
230 const uint8_t kSamplePacket3[] = {
231 // Header
232 0x00, 0x00, // ID is zeroed out
233 0x81, 0x80, // Standard query response, RA, no error
234 0x00, 0x00, // No questions (for simplicity)
235 0x00, 0x02, // 2 RRs (answers)
236 0x00, 0x00, // 0 authority RRs
237 0x00, 0x00, // 0 additional RRs
238
239 // Answer 1
240 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't', //
241 0x04, '_', 't', 'c', 'p', //
242 0x05, 'l', 'o', 'c', 'a', 'l', //
243 0x00, 0x00, 0x0c, // TYPE is PTR.
244 0x00, 0x01, // CLASS is IN.
245 0x00, 0x00, // TTL (4 bytes) is 1 second;
246 0x00, 0x01, //
247 0x00, 0x08, // RDLENGTH is 8 bytes.
248 0x05, 'h', 'e', 'l', 'l', 'o', //
249 0xc0, 0x0c, //
250
251 // Answer 2
252 0x08, '_', 'p', 'r', 'i', 'n', 't', 'e', 'r', //
253 0xc0, 0x14, // Pointer to "._tcp.local"
254 0x00, 0x0c, // TYPE is PTR.
255 0x00, 0x01, // CLASS is IN.
256 0x00, 0x00, // TTL (4 bytes) is 3 seconds.
257 0x00, 0x03, //
258 0x00, 0x08, // RDLENGTH is 8 bytes.
259 0x05, 'h', 'e', 'l', 'l', 'o', //
260 0xc0, 0x32};
261
262 const uint8_t kQueryPacketPrivet[] = {
263 // Header
264 0x00, 0x00, // ID is zeroed out
265 0x00, 0x00, // No flags.
266 0x00, 0x01, // One question.
267 0x00, 0x00, // 0 RRs (answers)
268 0x00, 0x00, // 0 authority RRs
269 0x00, 0x00, // 0 additional RRs
270
271 // Question
272 // This part is echoed back from the respective query.
273 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't', 0x04, '_', 't', 'c', 'p', 0x05,
274 'l', 'o', 'c', 'a', 'l', 0x00, 0x00, 0x0c, // TYPE is PTR.
275 0x00, 0x01, // CLASS is IN.
276 };
277
278 const uint8_t kQueryPacketPrivetWithCapitalization[] = {
279 // Header
280 0x00, 0x00, // ID is zeroed out
281 0x00, 0x00, // No flags.
282 0x00, 0x01, // One question.
283 0x00, 0x00, // 0 RRs (answers)
284 0x00, 0x00, // 0 authority RRs
285 0x00, 0x00, // 0 additional RRs
286
287 // Question
288 // This part is echoed back from the respective query.
289 0x07, '_', 'P', 'R', 'I', 'V', 'E', 'T', 0x04, '_', 't', 'c', 'p', 0x05,
290 'l', 'o', 'c', 'a', 'l', 0x00, 0x00, 0x0c, // TYPE is PTR.
291 0x00, 0x01, // CLASS is IN.
292 };
293
294 const uint8_t kQueryPacketPrivetA[] = {
295 // Header
296 0x00, 0x00, // ID is zeroed out
297 0x00, 0x00, // No flags.
298 0x00, 0x01, // One question.
299 0x00, 0x00, // 0 RRs (answers)
300 0x00, 0x00, // 0 authority RRs
301 0x00, 0x00, // 0 additional RRs
302
303 // Question
304 // This part is echoed back from the respective query.
305 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't', 0x04, '_', 't', 'c', 'p', 0x05,
306 'l', 'o', 'c', 'a', 'l', 0x00, 0x00, 0x01, // TYPE is A.
307 0x00, 0x01, // CLASS is IN.
308 };
309
310 const uint8_t kSamplePacketAdditionalOnly[] = {
311 // Header
312 0x00, 0x00, // ID is zeroed out
313 0x81, 0x80, // Standard query response, RA, no error
314 0x00, 0x00, // No questions (for simplicity)
315 0x00, 0x00, // 2 RRs (answers)
316 0x00, 0x00, // 0 authority RRs
317 0x00, 0x01, // 0 additional RRs
318
319 // Answer 1
320 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't', 0x04, '_', 't', 'c', 'p', 0x05,
321 'l', 'o', 'c', 'a', 'l', 0x00, 0x00, 0x0c, // TYPE is PTR.
322 0x00, 0x01, // CLASS is IN.
323 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
324 0x24, 0x74, 0x00, 0x08, // RDLENGTH is 8 bytes.
325 0x05, 'h', 'e', 'l', 'l', 'o', 0xc0, 0x0c,
326 };
327
328 const uint8_t kSamplePacketNsec[] = {
329 // Header
330 0x00, 0x00, // ID is zeroed out
331 0x81, 0x80, // Standard query response, RA, no error
332 0x00, 0x00, // No questions (for simplicity)
333 0x00, 0x01, // 1 RR (answers)
334 0x00, 0x00, // 0 authority RRs
335 0x00, 0x00, // 0 additional RRs
336
337 // Answer 1
338 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't', 0x04, '_', 't', 'c', 'p', 0x05,
339 'l', 'o', 'c', 'a', 'l', 0x00, 0x00, 0x2f, // TYPE is NSEC.
340 0x00, 0x01, // CLASS is IN.
341 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
342 0x24, 0x74, 0x00, 0x06, // RDLENGTH is 6 bytes.
343 0xc0, 0x0c, 0x00, 0x02, 0x00, 0x08 // Only A record present
344 };
345
346 const uint8_t kSamplePacketAPrivet[] = {
347 // Header
348 0x00, 0x00, // ID is zeroed out
349 0x81, 0x80, // Standard query response, RA, no error
350 0x00, 0x00, // No questions (for simplicity)
351 0x00, 0x01, // 1 RR (answers)
352 0x00, 0x00, // 0 authority RRs
353 0x00, 0x00, // 0 additional RRs
354
355 // Answer 1
356 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't', 0x04, '_', 't', 'c', 'p', 0x05,
357 'l', 'o', 'c', 'a', 'l', 0x00, 0x00, 0x01, // TYPE is A.
358 0x00, 0x01, // CLASS is IN.
359 0x00, 0x00, // TTL (4 bytes) is 5 seconds
360 0x00, 0x05, 0x00, 0x04, // RDLENGTH is 4 bytes.
361 0xc0, 0x0c, 0x00, 0x02,
362 };
363
364 const uint8_t kSamplePacketGoodbye[] = {
365 // Header
366 0x00, 0x00, // ID is zeroed out
367 0x81, 0x80, // Standard query response, RA, no error
368 0x00, 0x00, // No questions (for simplicity)
369 0x00, 0x01, // 2 RRs (answers)
370 0x00, 0x00, // 0 authority RRs
371 0x00, 0x00, // 0 additional RRs
372
373 // Answer 1
374 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't', 0x04, '_', 't', 'c', 'p', 0x05,
375 'l', 'o', 'c', 'a', 'l', 0x00, 0x00, 0x0c, // TYPE is PTR.
376 0x00, 0x01, // CLASS is IN.
377 0x00, 0x00, // TTL (4 bytes) is zero;
378 0x00, 0x00, 0x00, 0x08, // RDLENGTH is 8 bytes.
379 0x05, 'z', 'z', 'z', 'z', 'z', 0xc0, 0x0c,
380 };
381
MakeString(const uint8_t * data,unsigned size)382 std::string MakeString(const uint8_t* data, unsigned size) {
383 return std::string(reinterpret_cast<const char*>(data), size);
384 }
385
386 class PtrRecordCopyContainer {
387 public:
388 PtrRecordCopyContainer() = default;
389 ~PtrRecordCopyContainer() = default;
390
is_set() const391 bool is_set() const { return set_; }
392
SaveWithDummyArg(int unused,const RecordParsed * value)393 void SaveWithDummyArg(int unused, const RecordParsed* value) {
394 Save(value);
395 }
396
Save(const RecordParsed * value)397 void Save(const RecordParsed* value) {
398 set_ = true;
399 name_ = value->name();
400 ptrdomain_ = value->rdata<PtrRecordRdata>()->ptrdomain();
401 ttl_ = value->ttl();
402 }
403
IsRecordWith(const std::string & name,const std::string & ptrdomain)404 bool IsRecordWith(const std::string& name, const std::string& ptrdomain) {
405 return set_ && name_ == name && ptrdomain_ == ptrdomain;
406 }
407
name()408 const std::string& name() { return name_; }
ptrdomain()409 const std::string& ptrdomain() { return ptrdomain_; }
ttl()410 int ttl() { return ttl_; }
411
412 private:
413 bool set_;
414 std::string name_;
415 std::string ptrdomain_;
416 int ttl_;
417 };
418
419 class MockClock : public base::Clock {
420 public:
421 MockClock() = default;
422
423 MockClock(const MockClock&) = delete;
424 MockClock& operator=(const MockClock&) = delete;
425
426 ~MockClock() override = default;
427
428 MOCK_CONST_METHOD0(Now, base::Time());
429 };
430
431 class MockTimer : public base::MockOneShotTimer {
432 public:
433 MockTimer() = default;
434
435 MockTimer(const MockTimer&) = delete;
436 MockTimer& operator=(const MockTimer&) = delete;
437
438 ~MockTimer() override = default;
439
Start(const base::Location & posted_from,base::TimeDelta delay,base::OnceClosure user_task)440 void Start(const base::Location& posted_from,
441 base::TimeDelta delay,
442 base::OnceClosure user_task) override {
443 StartObserver(posted_from, delay);
444 base::MockOneShotTimer::Start(posted_from, delay, std::move(user_task));
445 }
446
447 // StartObserver is invoked when MockTimer::Start() is called.
448 // Does not replace the behavior of MockTimer::Start().
449 MOCK_METHOD2(StartObserver,
450 void(const base::Location& posted_from, base::TimeDelta delay));
451 };
452
453 } // namespace
454
455 class MDnsTest : public TestWithTaskEnvironment {
456 public:
457 void SetUp() override;
458 void DeleteTransaction();
459 void DeleteBothListeners();
460 void RunFor(base::TimeDelta time_period);
461 void Stop();
462
463 MOCK_METHOD2(MockableRecordCallback, void(MDnsTransaction::Result result,
464 const RecordParsed* record));
465
466 MOCK_METHOD2(MockableRecordCallback2, void(MDnsTransaction::Result result,
467 const RecordParsed* record));
468
469 protected:
470 void ExpectPacket(const uint8_t* packet, unsigned size);
471 void SimulatePacketReceive(const uint8_t* packet, unsigned size);
472
473 std::unique_ptr<base::Clock> test_clock_; // Must outlive `test_client_`.
474 std::unique_ptr<MDnsClientImpl> test_client_;
475 IPEndPoint mdns_ipv4_endpoint_;
476 StrictMock<MockMDnsSocketFactory> socket_factory_;
477
478 // Transactions and listeners that can be deleted by class methods for
479 // reentrancy tests.
480 std::unique_ptr<MDnsTransaction> transaction_;
481 std::unique_ptr<MDnsListener> listener1_;
482 std::unique_ptr<MDnsListener> listener2_;
483 };
484
485 class MockListenerDelegate : public MDnsListener::Delegate {
486 public:
487 MOCK_METHOD2(OnRecordUpdate,
488 void(MDnsListener::UpdateType update,
489 const RecordParsed* records));
490 MOCK_METHOD2(OnNsecRecord, void(const std::string&, unsigned));
491 MOCK_METHOD0(OnCachePurged, void());
492 };
493
SetUp()494 void MDnsTest::SetUp() {
495 test_client_ = std::make_unique<MDnsClientImpl>();
496 ASSERT_THAT(test_client_->StartListening(&socket_factory_), test::IsOk());
497 }
498
SimulatePacketReceive(const uint8_t * packet,unsigned size)499 void MDnsTest::SimulatePacketReceive(const uint8_t* packet, unsigned size) {
500 socket_factory_.SimulateReceive(packet, size);
501 }
502
ExpectPacket(const uint8_t * packet,unsigned size)503 void MDnsTest::ExpectPacket(const uint8_t* packet, unsigned size) {
504 EXPECT_CALL(socket_factory_, OnSendTo(MakeString(packet, size)))
505 .Times(2);
506 }
507
DeleteTransaction()508 void MDnsTest::DeleteTransaction() {
509 transaction_.reset();
510 }
511
DeleteBothListeners()512 void MDnsTest::DeleteBothListeners() {
513 listener1_.reset();
514 listener2_.reset();
515 }
516
RunFor(base::TimeDelta time_period)517 void MDnsTest::RunFor(base::TimeDelta time_period) {
518 base::CancelableOnceCallback<void()> callback(
519 base::BindOnce(&MDnsTest::Stop, base::Unretained(this)));
520 base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
521 FROM_HERE, callback.callback(), time_period);
522
523 base::RunLoop().Run();
524 callback.Cancel();
525 }
526
Stop()527 void MDnsTest::Stop() {
528 base::RunLoop::QuitCurrentWhenIdleDeprecated();
529 }
530
TEST_F(MDnsTest,PassiveListeners)531 TEST_F(MDnsTest, PassiveListeners) {
532 StrictMock<MockListenerDelegate> delegate_privet;
533 StrictMock<MockListenerDelegate> delegate_printer;
534
535 PtrRecordCopyContainer record_privet;
536 PtrRecordCopyContainer record_printer;
537
538 std::unique_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
539 dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet);
540 std::unique_ptr<MDnsListener> listener_printer = test_client_->CreateListener(
541 dns_protocol::kTypePTR, "_printer._tcp.local", &delegate_printer);
542
543 ASSERT_TRUE(listener_privet->Start());
544 ASSERT_TRUE(listener_printer->Start());
545
546 // Send the same packet twice to ensure no records are double-counted.
547
548 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
549 .Times(Exactly(1))
550 .WillOnce(Invoke(
551 &record_privet,
552 &PtrRecordCopyContainer::SaveWithDummyArg));
553
554 EXPECT_CALL(delegate_printer, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
555 .Times(Exactly(1))
556 .WillOnce(Invoke(
557 &record_printer,
558 &PtrRecordCopyContainer::SaveWithDummyArg));
559
560
561 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
562 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
563
564 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
565 "hello._privet._tcp.local"));
566
567 EXPECT_TRUE(record_printer.IsRecordWith("_printer._tcp.local",
568 "hello._printer._tcp.local"));
569
570 listener_privet.reset();
571 listener_printer.reset();
572 }
573
TEST_F(MDnsTest,PassiveListenersWithCapitalization)574 TEST_F(MDnsTest, PassiveListenersWithCapitalization) {
575 StrictMock<MockListenerDelegate> delegate_privet;
576 StrictMock<MockListenerDelegate> delegate_printer;
577
578 PtrRecordCopyContainer record_privet;
579 PtrRecordCopyContainer record_printer;
580
581 std::unique_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
582 dns_protocol::kTypePTR, "_privet._tcp.LOCAL", &delegate_privet);
583 std::unique_ptr<MDnsListener> listener_printer = test_client_->CreateListener(
584 dns_protocol::kTypePTR, "_prinTER._Tcp.Local", &delegate_printer);
585
586 ASSERT_TRUE(listener_privet->Start());
587 ASSERT_TRUE(listener_printer->Start());
588
589 // Send the same packet twice to ensure no records are double-counted.
590
591 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
592 .Times(Exactly(1))
593 .WillOnce(
594 Invoke(&record_privet, &PtrRecordCopyContainer::SaveWithDummyArg));
595
596 EXPECT_CALL(delegate_printer, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
597 .Times(Exactly(1))
598 .WillOnce(
599 Invoke(&record_printer, &PtrRecordCopyContainer::SaveWithDummyArg));
600
601 SimulatePacketReceive(kSamplePacket1WithCapitalization,
602 sizeof(kSamplePacket1WithCapitalization));
603 SimulatePacketReceive(kSamplePacket1WithCapitalization,
604 sizeof(kSamplePacket1WithCapitalization));
605
606 EXPECT_TRUE(record_privet.IsRecordWith("_privet._TCP.local",
607 "hello._privet._TCP.local"));
608
609 EXPECT_TRUE(record_printer.IsRecordWith("_PrinteR._TCP.local",
610 "hello._PrinteR._TCP.local"));
611
612 listener_privet.reset();
613 listener_printer.reset();
614 }
615
TEST_F(MDnsTest,PassiveListenersCacheCleanup)616 TEST_F(MDnsTest, PassiveListenersCacheCleanup) {
617 StrictMock<MockListenerDelegate> delegate_privet;
618
619 PtrRecordCopyContainer record_privet;
620 PtrRecordCopyContainer record_privet2;
621
622 std::unique_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
623 dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet);
624
625 ASSERT_TRUE(listener_privet->Start());
626
627 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
628 .Times(Exactly(1))
629 .WillOnce(Invoke(
630 &record_privet,
631 &PtrRecordCopyContainer::SaveWithDummyArg));
632
633 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
634
635 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
636 "hello._privet._tcp.local"));
637
638 // Expect record is removed when its TTL expires.
639 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_REMOVED, _))
640 .Times(Exactly(1))
641 .WillOnce(DoAll(InvokeWithoutArgs(this, &MDnsTest::Stop),
642 Invoke(&record_privet2,
643 &PtrRecordCopyContainer::SaveWithDummyArg)));
644
645 RunFor(base::Seconds(record_privet.ttl() + 1));
646
647 EXPECT_TRUE(record_privet2.IsRecordWith("_privet._tcp.local",
648 "hello._privet._tcp.local"));
649 }
650
651 // Ensure that the cleanup task scheduler won't schedule cleanup tasks in the
652 // past if the system clock creeps past the expiration time while in the
653 // cleanup dispatcher.
TEST_F(MDnsTest,CacheCleanupWithShortTTL)654 TEST_F(MDnsTest, CacheCleanupWithShortTTL) {
655 // Use a nonzero starting time as a base.
656 base::Time start_time = base::Time() + base::Seconds(1);
657
658 auto timer = std::make_unique<MockTimer>();
659 MockTimer* timer_ptr = timer.get();
660
661 auto owned_clock = std::make_unique<MockClock>();
662 MockClock* clock = owned_clock.get();
663 test_clock_ = std::move(owned_clock);
664 test_client_ = std::make_unique<MDnsClientImpl>(clock, std::move(timer));
665 ASSERT_THAT(test_client_->StartListening(&socket_factory_), test::IsOk());
666
667 EXPECT_CALL(*timer_ptr, StartObserver(_, _)).Times(1);
668 EXPECT_CALL(*clock, Now())
669 .Times(3)
670 .WillRepeatedly(Return(start_time))
671 .RetiresOnSaturation();
672
673 // Receive two records with different TTL values.
674 // TTL(privet)=1.0s
675 // TTL(printer)=3.0s
676 StrictMock<MockListenerDelegate> delegate_privet;
677 StrictMock<MockListenerDelegate> delegate_printer;
678
679 PtrRecordCopyContainer record_privet;
680 PtrRecordCopyContainer record_printer;
681
682 std::unique_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
683 dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet);
684 std::unique_ptr<MDnsListener> listener_printer = test_client_->CreateListener(
685 dns_protocol::kTypePTR, "_printer._tcp.local", &delegate_printer);
686
687 ASSERT_TRUE(listener_privet->Start());
688 ASSERT_TRUE(listener_printer->Start());
689
690 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
691 .Times(Exactly(1));
692 EXPECT_CALL(delegate_printer, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
693 .Times(Exactly(1));
694
695 SimulatePacketReceive(kSamplePacket3, sizeof(kSamplePacket3));
696
697 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_REMOVED, _))
698 .Times(Exactly(1));
699
700 // Set the clock to 2.0s, which should clean up the 'privet' record, but not
701 // the printer. The mock clock will change Now() mid-execution from 2s to 4s.
702 // Note: expectations are FILO-ordered -- t+2 seconds is returned, then t+4.
703 EXPECT_CALL(*clock, Now())
704 .WillOnce(Return(start_time + base::Seconds(4)))
705 .RetiresOnSaturation();
706 EXPECT_CALL(*clock, Now())
707 .WillOnce(Return(start_time + base::Seconds(2)))
708 .RetiresOnSaturation();
709
710 EXPECT_CALL(*timer_ptr, StartObserver(_, base::TimeDelta()));
711
712 timer_ptr->Fire();
713 }
714
TEST_F(MDnsTest,StopListening)715 TEST_F(MDnsTest, StopListening) {
716 ASSERT_TRUE(test_client_->IsListening());
717
718 test_client_->StopListening();
719 EXPECT_FALSE(test_client_->IsListening());
720 }
721
TEST_F(MDnsTest,StopListening_CacheCleanupScheduled)722 TEST_F(MDnsTest, StopListening_CacheCleanupScheduled) {
723 auto owned_clock = std::make_unique<base::SimpleTestClock>();
724 base::SimpleTestClock* clock = owned_clock.get();
725 test_clock_ = std::move(owned_clock);
726
727 // Use a nonzero starting time as a base.
728 clock->SetNow(base::Time() + base::Seconds(1));
729 auto cleanup_timer = std::make_unique<base::MockOneShotTimer>();
730 base::OneShotTimer* cleanup_timer_ptr = cleanup_timer.get();
731
732 test_client_ =
733 std::make_unique<MDnsClientImpl>(clock, std::move(cleanup_timer));
734 ASSERT_THAT(test_client_->StartListening(&socket_factory_), test::IsOk());
735 ASSERT_TRUE(test_client_->IsListening());
736
737 // Receive one record (privet) with TTL=1s to schedule cleanup.
738 SimulatePacketReceive(kSamplePacket3, sizeof(kSamplePacket3));
739 ASSERT_TRUE(cleanup_timer_ptr->IsRunning());
740
741 test_client_->StopListening();
742 EXPECT_FALSE(test_client_->IsListening());
743
744 // Expect cleanup unscheduled.
745 EXPECT_FALSE(cleanup_timer_ptr->IsRunning());
746 }
747
TEST_F(MDnsTest,MalformedPacket)748 TEST_F(MDnsTest, MalformedPacket) {
749 StrictMock<MockListenerDelegate> delegate_printer;
750
751 PtrRecordCopyContainer record_printer;
752
753 std::unique_ptr<MDnsListener> listener_printer = test_client_->CreateListener(
754 dns_protocol::kTypePTR, "_printer._tcp.local", &delegate_printer);
755
756 ASSERT_TRUE(listener_printer->Start());
757
758 EXPECT_CALL(delegate_printer, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
759 .Times(Exactly(1))
760 .WillOnce(Invoke(
761 &record_printer,
762 &PtrRecordCopyContainer::SaveWithDummyArg));
763
764 // First, send unsalvagable packet to ensure we can deal with it.
765 SimulatePacketReceive(kCorruptedPacketUnsalvagable,
766 sizeof(kCorruptedPacketUnsalvagable));
767
768 // Regression test: send a packet where the question cannot be read.
769 SimulatePacketReceive(kCorruptedPacketBadQuestion,
770 sizeof(kCorruptedPacketBadQuestion));
771
772 // Then send salvagable packet to ensure we can extract useful records.
773 SimulatePacketReceive(kCorruptedPacketSalvagable,
774 sizeof(kCorruptedPacketSalvagable));
775
776 EXPECT_TRUE(record_printer.IsRecordWith("_printer._tcp.local",
777 "hello._printer._tcp.local"));
778 }
779
TEST_F(MDnsTest,TransactionWithEmptyCache)780 TEST_F(MDnsTest, TransactionWithEmptyCache) {
781 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
782
783 std::unique_ptr<MDnsTransaction> transaction_privet =
784 test_client_->CreateTransaction(
785 dns_protocol::kTypePTR, "_privet._tcp.local",
786 MDnsTransaction::QUERY_NETWORK | MDnsTransaction::QUERY_CACHE |
787 MDnsTransaction::SINGLE_RESULT,
788 base::BindRepeating(&MDnsTest::MockableRecordCallback,
789 base::Unretained(this)));
790
791 ASSERT_TRUE(transaction_privet->Start());
792
793 PtrRecordCopyContainer record_privet;
794
795 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD, _))
796 .Times(Exactly(1))
797 .WillOnce(Invoke(&record_privet,
798 &PtrRecordCopyContainer::SaveWithDummyArg));
799
800 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
801
802 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
803 "hello._privet._tcp.local"));
804 }
805
TEST_F(MDnsTest,TransactionWithEmptyCacheAndCapitalization)806 TEST_F(MDnsTest, TransactionWithEmptyCacheAndCapitalization) {
807 ExpectPacket(kQueryPacketPrivetWithCapitalization,
808 sizeof(kQueryPacketPrivetWithCapitalization));
809
810 std::unique_ptr<MDnsTransaction> transaction_privet =
811 test_client_->CreateTransaction(
812 dns_protocol::kTypePTR, "_PRIVET._tcp.local",
813 MDnsTransaction::QUERY_NETWORK | MDnsTransaction::QUERY_CACHE |
814 MDnsTransaction::SINGLE_RESULT,
815 base::BindRepeating(&MDnsTest::MockableRecordCallback,
816 base::Unretained(this)));
817
818 ASSERT_TRUE(transaction_privet->Start());
819
820 PtrRecordCopyContainer record_privet;
821
822 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD, _))
823 .Times(Exactly(1))
824 .WillOnce(
825 Invoke(&record_privet, &PtrRecordCopyContainer::SaveWithDummyArg));
826
827 SimulatePacketReceive(kSamplePacket1WithCapitalization,
828 sizeof(kSamplePacket1WithCapitalization));
829
830 EXPECT_TRUE(record_privet.IsRecordWith("_privet._TCP.local",
831 "hello._privet._TCP.local"));
832 }
833
TEST_F(MDnsTest,TransactionCacheOnlyNoResult)834 TEST_F(MDnsTest, TransactionCacheOnlyNoResult) {
835 std::unique_ptr<MDnsTransaction> transaction_privet =
836 test_client_->CreateTransaction(
837 dns_protocol::kTypePTR, "_privet._tcp.local",
838 MDnsTransaction::QUERY_CACHE | MDnsTransaction::SINGLE_RESULT,
839 base::BindRepeating(&MDnsTest::MockableRecordCallback,
840 base::Unretained(this)));
841
842 EXPECT_CALL(*this,
843 MockableRecordCallback(MDnsTransaction::RESULT_NO_RESULTS, _))
844 .Times(Exactly(1));
845
846 ASSERT_TRUE(transaction_privet->Start());
847 }
848
TEST_F(MDnsTest,TransactionWithCache)849 TEST_F(MDnsTest, TransactionWithCache) {
850 // Listener to force the client to listen
851 StrictMock<MockListenerDelegate> delegate_irrelevant;
852 std::unique_ptr<MDnsListener> listener_irrelevant =
853 test_client_->CreateListener(dns_protocol::kTypeA,
854 "codereview.chromium.local",
855 &delegate_irrelevant);
856
857 ASSERT_TRUE(listener_irrelevant->Start());
858
859 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
860
861
862 PtrRecordCopyContainer record_privet;
863
864 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD, _))
865 .WillOnce(Invoke(&record_privet,
866 &PtrRecordCopyContainer::SaveWithDummyArg));
867
868 std::unique_ptr<MDnsTransaction> transaction_privet =
869 test_client_->CreateTransaction(
870 dns_protocol::kTypePTR, "_privet._tcp.local",
871 MDnsTransaction::QUERY_NETWORK | MDnsTransaction::QUERY_CACHE |
872 MDnsTransaction::SINGLE_RESULT,
873 base::BindRepeating(&MDnsTest::MockableRecordCallback,
874 base::Unretained(this)));
875
876 ASSERT_TRUE(transaction_privet->Start());
877
878 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
879 "hello._privet._tcp.local"));
880 }
881
TEST_F(MDnsTest,AdditionalRecords)882 TEST_F(MDnsTest, AdditionalRecords) {
883 StrictMock<MockListenerDelegate> delegate_privet;
884
885 PtrRecordCopyContainer record_privet;
886
887 std::unique_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
888 dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet);
889
890 ASSERT_TRUE(listener_privet->Start());
891
892 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
893 .Times(Exactly(1))
894 .WillOnce(Invoke(
895 &record_privet,
896 &PtrRecordCopyContainer::SaveWithDummyArg));
897
898 SimulatePacketReceive(kSamplePacketAdditionalOnly,
899 sizeof(kSamplePacketAdditionalOnly));
900
901 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
902 "hello._privet._tcp.local"));
903 }
904
TEST_F(MDnsTest,TransactionTimeout)905 TEST_F(MDnsTest, TransactionTimeout) {
906 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
907
908 std::unique_ptr<MDnsTransaction> transaction_privet =
909 test_client_->CreateTransaction(
910 dns_protocol::kTypePTR, "_privet._tcp.local",
911 MDnsTransaction::QUERY_NETWORK | MDnsTransaction::QUERY_CACHE |
912 MDnsTransaction::SINGLE_RESULT,
913 base::BindRepeating(&MDnsTest::MockableRecordCallback,
914 base::Unretained(this)));
915
916 ASSERT_TRUE(transaction_privet->Start());
917
918 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_NO_RESULTS,
919 nullptr))
920 .Times(Exactly(1))
921 .WillOnce(InvokeWithoutArgs(this, &MDnsTest::Stop));
922
923 RunFor(base::Seconds(4));
924 }
925
TEST_F(MDnsTest,TransactionMultipleRecords)926 TEST_F(MDnsTest, TransactionMultipleRecords) {
927 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
928
929 std::unique_ptr<MDnsTransaction> transaction_privet =
930 test_client_->CreateTransaction(
931 dns_protocol::kTypePTR, "_privet._tcp.local",
932 MDnsTransaction::QUERY_NETWORK | MDnsTransaction::QUERY_CACHE,
933 base::BindRepeating(&MDnsTest::MockableRecordCallback,
934 base::Unretained(this)));
935
936 ASSERT_TRUE(transaction_privet->Start());
937
938 PtrRecordCopyContainer record_privet;
939 PtrRecordCopyContainer record_privet2;
940
941 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD, _))
942 .Times(Exactly(2))
943 .WillOnce(Invoke(&record_privet,
944 &PtrRecordCopyContainer::SaveWithDummyArg))
945 .WillOnce(Invoke(&record_privet2,
946 &PtrRecordCopyContainer::SaveWithDummyArg));
947
948 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
949 SimulatePacketReceive(kSamplePacket2, sizeof(kSamplePacket2));
950
951 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
952 "hello._privet._tcp.local"));
953
954 EXPECT_TRUE(record_privet2.IsRecordWith("_privet._tcp.local",
955 "zzzzz._privet._tcp.local"));
956
957 EXPECT_CALL(*this,
958 MockableRecordCallback(MDnsTransaction::RESULT_DONE, nullptr))
959 .WillOnce(InvokeWithoutArgs(this, &MDnsTest::Stop));
960
961 RunFor(base::Seconds(4));
962 }
963
TEST_F(MDnsTest,TransactionReentrantDelete)964 TEST_F(MDnsTest, TransactionReentrantDelete) {
965 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
966
967 transaction_ = test_client_->CreateTransaction(
968 dns_protocol::kTypePTR, "_privet._tcp.local",
969 MDnsTransaction::QUERY_NETWORK | MDnsTransaction::QUERY_CACHE |
970 MDnsTransaction::SINGLE_RESULT,
971 base::BindRepeating(&MDnsTest::MockableRecordCallback,
972 base::Unretained(this)));
973
974 ASSERT_TRUE(transaction_->Start());
975
976 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_NO_RESULTS,
977 nullptr))
978 .Times(Exactly(1))
979 .WillOnce(DoAll(InvokeWithoutArgs(this, &MDnsTest::DeleteTransaction),
980 InvokeWithoutArgs(this, &MDnsTest::Stop)));
981
982 RunFor(base::Seconds(4));
983
984 EXPECT_EQ(nullptr, transaction_.get());
985 }
986
TEST_F(MDnsTest,TransactionReentrantDeleteFromCache)987 TEST_F(MDnsTest, TransactionReentrantDeleteFromCache) {
988 StrictMock<MockListenerDelegate> delegate_irrelevant;
989 std::unique_ptr<MDnsListener> listener_irrelevant =
990 test_client_->CreateListener(dns_protocol::kTypeA,
991 "codereview.chromium.local",
992 &delegate_irrelevant);
993 ASSERT_TRUE(listener_irrelevant->Start());
994
995 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
996
997 transaction_ = test_client_->CreateTransaction(
998 dns_protocol::kTypePTR, "_privet._tcp.local",
999 MDnsTransaction::QUERY_NETWORK | MDnsTransaction::QUERY_CACHE,
1000 base::BindRepeating(&MDnsTest::MockableRecordCallback,
1001 base::Unretained(this)));
1002
1003 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD, _))
1004 .Times(Exactly(1))
1005 .WillOnce(InvokeWithoutArgs(this, &MDnsTest::DeleteTransaction));
1006
1007 ASSERT_TRUE(transaction_->Start());
1008
1009 EXPECT_EQ(nullptr, transaction_.get());
1010 }
1011
TEST_F(MDnsTest,TransactionReentrantCacheLookupStart)1012 TEST_F(MDnsTest, TransactionReentrantCacheLookupStart) {
1013 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
1014
1015 std::unique_ptr<MDnsTransaction> transaction1 =
1016 test_client_->CreateTransaction(
1017 dns_protocol::kTypePTR, "_privet._tcp.local",
1018 MDnsTransaction::QUERY_NETWORK | MDnsTransaction::QUERY_CACHE |
1019 MDnsTransaction::SINGLE_RESULT,
1020 base::BindRepeating(&MDnsTest::MockableRecordCallback,
1021 base::Unretained(this)));
1022
1023 std::unique_ptr<MDnsTransaction> transaction2 =
1024 test_client_->CreateTransaction(
1025 dns_protocol::kTypePTR, "_printer._tcp.local",
1026 MDnsTransaction::QUERY_CACHE | MDnsTransaction::SINGLE_RESULT,
1027 base::BindRepeating(&MDnsTest::MockableRecordCallback2,
1028 base::Unretained(this)));
1029
1030 EXPECT_CALL(*this, MockableRecordCallback2(MDnsTransaction::RESULT_RECORD,
1031 _))
1032 .Times(Exactly(1));
1033
1034 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD,
1035 _))
1036 .Times(Exactly(1))
1037 .WillOnce(IgnoreResult(InvokeWithoutArgs(transaction2.get(),
1038 &MDnsTransaction::Start)));
1039
1040 ASSERT_TRUE(transaction1->Start());
1041
1042 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
1043 }
1044
TEST_F(MDnsTest,GoodbyePacketNotification)1045 TEST_F(MDnsTest, GoodbyePacketNotification) {
1046 StrictMock<MockListenerDelegate> delegate_privet;
1047
1048 std::unique_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
1049 dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet);
1050 ASSERT_TRUE(listener_privet->Start());
1051
1052 SimulatePacketReceive(kSamplePacketGoodbye, sizeof(kSamplePacketGoodbye));
1053
1054 RunFor(base::Seconds(2));
1055 }
1056
TEST_F(MDnsTest,GoodbyePacketRemoval)1057 TEST_F(MDnsTest, GoodbyePacketRemoval) {
1058 StrictMock<MockListenerDelegate> delegate_privet;
1059
1060 std::unique_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
1061 dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet);
1062 ASSERT_TRUE(listener_privet->Start());
1063
1064 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
1065 .Times(Exactly(1));
1066
1067 SimulatePacketReceive(kSamplePacket2, sizeof(kSamplePacket2));
1068
1069 SimulatePacketReceive(kSamplePacketGoodbye, sizeof(kSamplePacketGoodbye));
1070
1071 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_REMOVED, _))
1072 .Times(Exactly(1));
1073
1074 RunFor(base::Seconds(2));
1075 }
1076
1077 // In order to reliably test reentrant listener deletes, we create two listeners
1078 // and have each of them delete both, so we're guaranteed to try and deliver a
1079 // callback to at least one deleted listener.
1080
TEST_F(MDnsTest,ListenerReentrantDelete)1081 TEST_F(MDnsTest, ListenerReentrantDelete) {
1082 StrictMock<MockListenerDelegate> delegate_privet;
1083
1084 listener1_ = test_client_->CreateListener(
1085 dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet);
1086
1087 listener2_ = test_client_->CreateListener(
1088 dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet);
1089
1090 ASSERT_TRUE(listener1_->Start());
1091
1092 ASSERT_TRUE(listener2_->Start());
1093
1094 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
1095 .Times(Exactly(1))
1096 .WillOnce(InvokeWithoutArgs(this, &MDnsTest::DeleteBothListeners));
1097
1098 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
1099
1100 EXPECT_EQ(nullptr, listener1_.get());
1101 EXPECT_EQ(nullptr, listener2_.get());
1102 }
1103
ACTION_P(SaveIPAddress,ip_container)1104 ACTION_P(SaveIPAddress, ip_container) {
1105 ::testing::StaticAssertTypeEq<const RecordParsed*, arg1_type>();
1106 ::testing::StaticAssertTypeEq<IPAddress*, ip_container_type>();
1107
1108 *ip_container = arg1->template rdata<ARecordRdata>()->address();
1109 }
1110
TEST_F(MDnsTest,DoubleRecordDisagreeing)1111 TEST_F(MDnsTest, DoubleRecordDisagreeing) {
1112 IPAddress address;
1113 StrictMock<MockListenerDelegate> delegate_privet;
1114
1115 std::unique_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
1116 dns_protocol::kTypeA, "privet.local", &delegate_privet);
1117
1118 ASSERT_TRUE(listener_privet->Start());
1119
1120 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
1121 .Times(Exactly(1))
1122 .WillOnce(SaveIPAddress(&address));
1123
1124 SimulatePacketReceive(kCorruptedPacketDoubleRecord,
1125 sizeof(kCorruptedPacketDoubleRecord));
1126
1127 EXPECT_EQ("2.3.4.5", address.ToString());
1128 }
1129
TEST_F(MDnsTest,NsecWithListener)1130 TEST_F(MDnsTest, NsecWithListener) {
1131 StrictMock<MockListenerDelegate> delegate_privet;
1132 std::unique_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
1133 dns_protocol::kTypeA, "_privet._tcp.local", &delegate_privet);
1134
1135 // Test to make sure nsec callback is NOT called for PTR
1136 // (which is marked as existing).
1137 StrictMock<MockListenerDelegate> delegate_privet2;
1138 std::unique_ptr<MDnsListener> listener_privet2 = test_client_->CreateListener(
1139 dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet2);
1140
1141 ASSERT_TRUE(listener_privet->Start());
1142
1143 EXPECT_CALL(delegate_privet,
1144 OnNsecRecord("_privet._tcp.local", dns_protocol::kTypeA));
1145
1146 SimulatePacketReceive(kSamplePacketNsec,
1147 sizeof(kSamplePacketNsec));
1148 }
1149
TEST_F(MDnsTest,NsecWithTransactionFromNetwork)1150 TEST_F(MDnsTest, NsecWithTransactionFromNetwork) {
1151 std::unique_ptr<MDnsTransaction> transaction_privet =
1152 test_client_->CreateTransaction(
1153 dns_protocol::kTypeA, "_privet._tcp.local",
1154 MDnsTransaction::QUERY_NETWORK | MDnsTransaction::QUERY_CACHE |
1155 MDnsTransaction::SINGLE_RESULT,
1156 base::BindRepeating(&MDnsTest::MockableRecordCallback,
1157 base::Unretained(this)));
1158
1159 EXPECT_CALL(socket_factory_, OnSendTo(_)).Times(2);
1160
1161 ASSERT_TRUE(transaction_privet->Start());
1162
1163 EXPECT_CALL(*this,
1164 MockableRecordCallback(MDnsTransaction::RESULT_NSEC, nullptr));
1165
1166 SimulatePacketReceive(kSamplePacketNsec,
1167 sizeof(kSamplePacketNsec));
1168 }
1169
TEST_F(MDnsTest,NsecWithTransactionFromCache)1170 TEST_F(MDnsTest, NsecWithTransactionFromCache) {
1171 // Force mDNS to listen.
1172 StrictMock<MockListenerDelegate> delegate_irrelevant;
1173 std::unique_ptr<MDnsListener> listener_irrelevant =
1174 test_client_->CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local",
1175 &delegate_irrelevant);
1176 listener_irrelevant->Start();
1177
1178 SimulatePacketReceive(kSamplePacketNsec,
1179 sizeof(kSamplePacketNsec));
1180
1181 EXPECT_CALL(*this,
1182 MockableRecordCallback(MDnsTransaction::RESULT_NSEC, nullptr));
1183
1184 std::unique_ptr<MDnsTransaction> transaction_privet_a =
1185 test_client_->CreateTransaction(
1186 dns_protocol::kTypeA, "_privet._tcp.local",
1187 MDnsTransaction::QUERY_NETWORK | MDnsTransaction::QUERY_CACHE |
1188 MDnsTransaction::SINGLE_RESULT,
1189 base::BindRepeating(&MDnsTest::MockableRecordCallback,
1190 base::Unretained(this)));
1191
1192 ASSERT_TRUE(transaction_privet_a->Start());
1193
1194 // Test that a PTR transaction does NOT consider the same NSEC record to be a
1195 // valid answer to the query
1196
1197 std::unique_ptr<MDnsTransaction> transaction_privet_ptr =
1198 test_client_->CreateTransaction(
1199 dns_protocol::kTypePTR, "_privet._tcp.local",
1200 MDnsTransaction::QUERY_NETWORK | MDnsTransaction::QUERY_CACHE |
1201 MDnsTransaction::SINGLE_RESULT,
1202 base::BindRepeating(&MDnsTest::MockableRecordCallback,
1203 base::Unretained(this)));
1204
1205 EXPECT_CALL(socket_factory_, OnSendTo(_)).Times(2);
1206
1207 ASSERT_TRUE(transaction_privet_ptr->Start());
1208 }
1209
TEST_F(MDnsTest,NsecConflictRemoval)1210 TEST_F(MDnsTest, NsecConflictRemoval) {
1211 StrictMock<MockListenerDelegate> delegate_privet;
1212 std::unique_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
1213 dns_protocol::kTypeA, "_privet._tcp.local", &delegate_privet);
1214
1215 ASSERT_TRUE(listener_privet->Start());
1216
1217 const RecordParsed* record1;
1218 const RecordParsed* record2;
1219
1220 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
1221 .WillOnce(SaveArg<1>(&record1));
1222
1223 SimulatePacketReceive(kSamplePacketAPrivet,
1224 sizeof(kSamplePacketAPrivet));
1225
1226 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_REMOVED, _))
1227 .WillOnce(SaveArg<1>(&record2));
1228
1229 EXPECT_CALL(delegate_privet,
1230 OnNsecRecord("_privet._tcp.local", dns_protocol::kTypeA));
1231
1232 SimulatePacketReceive(kSamplePacketNsec,
1233 sizeof(kSamplePacketNsec));
1234
1235 EXPECT_EQ(record1, record2);
1236 }
1237
1238 // TODO(https://crbug.com/1274091): Flaky on fuchsia.
1239 #if BUILDFLAG(IS_FUCHSIA)
1240 #define MAYBE_RefreshQuery DISABLED_RefreshQuery
1241 #else
1242 #define MAYBE_RefreshQuery RefreshQuery
1243 #endif
TEST_F(MDnsTest,MAYBE_RefreshQuery)1244 TEST_F(MDnsTest, MAYBE_RefreshQuery) {
1245 StrictMock<MockListenerDelegate> delegate_privet;
1246 std::unique_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
1247 dns_protocol::kTypeA, "_privet._tcp.local", &delegate_privet);
1248
1249 listener_privet->SetActiveRefresh(true);
1250 ASSERT_TRUE(listener_privet->Start());
1251
1252 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _));
1253
1254 SimulatePacketReceive(kSamplePacketAPrivet,
1255 sizeof(kSamplePacketAPrivet));
1256
1257 // Expecting 2 calls (one for ipv4 and one for ipv6) for each of the 2
1258 // scheduled refresh queries.
1259 EXPECT_CALL(socket_factory_, OnSendTo(
1260 MakeString(kQueryPacketPrivetA, sizeof(kQueryPacketPrivetA))))
1261 .Times(4);
1262
1263 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_REMOVED, _));
1264
1265 RunFor(base::Seconds(6));
1266 }
1267
1268 // MDnsSocketFactory implementation that creates a single socket that will
1269 // always fail on RecvFrom. Passing this to MdnsClient is expected to result in
1270 // the client failing to start listening.
1271 class FailingSocketFactory : public MDnsSocketFactory {
CreateSockets(std::vector<std::unique_ptr<DatagramServerSocket>> * sockets)1272 void CreateSockets(
1273 std::vector<std::unique_ptr<DatagramServerSocket>>* sockets) override {
1274 auto socket =
1275 std::make_unique<MockMDnsDatagramServerSocket>(ADDRESS_FAMILY_IPV4);
1276 EXPECT_CALL(*socket, RecvFrom(_, _, _, _))
1277 .WillRepeatedly(Return(ERR_FAILED));
1278 sockets->push_back(std::move(socket));
1279 }
1280 };
1281
TEST_F(MDnsTest,StartListeningFailure)1282 TEST_F(MDnsTest, StartListeningFailure) {
1283 test_client_ = std::make_unique<MDnsClientImpl>();
1284 FailingSocketFactory socket_factory;
1285
1286 EXPECT_THAT(test_client_->StartListening(&socket_factory),
1287 test::IsError(ERR_FAILED));
1288 }
1289
1290 // Test that the cache is cleared when it gets filled to unreasonable sizes.
TEST_F(MDnsTest,ClearOverfilledCache)1291 TEST_F(MDnsTest, ClearOverfilledCache) {
1292 test_client_->core()->cache_for_testing()->set_entry_limit_for_testing(1);
1293
1294 StrictMock<MockListenerDelegate> delegate_privet;
1295 StrictMock<MockListenerDelegate> delegate_printer;
1296
1297 PtrRecordCopyContainer record_privet;
1298 PtrRecordCopyContainer record_printer;
1299
1300 std::unique_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
1301 dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet);
1302 std::unique_ptr<MDnsListener> listener_printer = test_client_->CreateListener(
1303 dns_protocol::kTypePTR, "_printer._tcp.local", &delegate_printer);
1304
1305 ASSERT_TRUE(listener_privet->Start());
1306 ASSERT_TRUE(listener_printer->Start());
1307
1308 bool privet_added = false;
1309 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
1310 .Times(AtMost(1))
1311 .WillOnce(Assign(&privet_added, true));
1312 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_REMOVED, _))
1313 .WillRepeatedly(Assign(&privet_added, false));
1314
1315 bool printer_added = false;
1316 EXPECT_CALL(delegate_printer, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
1317 .Times(AtMost(1))
1318 .WillOnce(Assign(&printer_added, true));
1319 EXPECT_CALL(delegate_printer, OnRecordUpdate(MDnsListener::RECORD_REMOVED, _))
1320 .WillRepeatedly(Assign(&printer_added, false));
1321
1322 // Fill past capacity and expect everything to eventually be removed.
1323 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
1324 base::RunLoop().RunUntilIdle();
1325 EXPECT_FALSE(privet_added);
1326 EXPECT_FALSE(printer_added);
1327 }
1328
1329 // Note: These tests assume that the ipv4 socket will always be created first.
1330 // This is a simplifying assumption based on the way the code works now.
1331 class SimpleMockSocketFactory : public MDnsSocketFactory {
1332 public:
CreateSockets(std::vector<std::unique_ptr<DatagramServerSocket>> * sockets)1333 void CreateSockets(
1334 std::vector<std::unique_ptr<DatagramServerSocket>>* sockets) override {
1335 sockets->clear();
1336 sockets->swap(sockets_);
1337 }
1338
PushSocket(std::unique_ptr<DatagramServerSocket> socket)1339 void PushSocket(std::unique_ptr<DatagramServerSocket> socket) {
1340 sockets_.push_back(std::move(socket));
1341 }
1342
1343 private:
1344 std::vector<std::unique_ptr<DatagramServerSocket>> sockets_;
1345 };
1346
1347 class MockMDnsConnectionDelegate : public MDnsConnection::Delegate {
1348 public:
HandlePacket(DnsResponse * response,int size)1349 void HandlePacket(DnsResponse* response, int size) override {
1350 HandlePacketInternal(std::string(response->io_buffer()->data(), size));
1351 }
1352
1353 MOCK_METHOD1(HandlePacketInternal, void(std::string packet));
1354
1355 MOCK_METHOD1(OnConnectionError, void(int error));
1356 };
1357
1358 class MDnsConnectionTest : public TestWithTaskEnvironment {
1359 public:
MDnsConnectionTest()1360 MDnsConnectionTest() : connection_(&delegate_) {
1361 }
1362
1363 protected:
1364 // Follow successful connection initialization.
SetUp()1365 void SetUp() override {
1366 auto socket_ipv4 =
1367 std::make_unique<MockMDnsDatagramServerSocket>(ADDRESS_FAMILY_IPV4);
1368 auto socket_ipv6 =
1369 std::make_unique<MockMDnsDatagramServerSocket>(ADDRESS_FAMILY_IPV6);
1370 socket_ipv4_ptr_ = socket_ipv4.get();
1371 socket_ipv6_ptr_ = socket_ipv6.get();
1372 factory_.PushSocket(std::move(socket_ipv4));
1373 factory_.PushSocket(std::move(socket_ipv6));
1374 sample_packet_ = MakeString(kSamplePacket1, sizeof(kSamplePacket1));
1375 sample_buffer_ = base::MakeRefCounted<StringIOBuffer>(sample_packet_);
1376 }
1377
InitConnection()1378 int InitConnection() { return connection_.Init(&factory_); }
1379
1380 StrictMock<MockMDnsConnectionDelegate> delegate_;
1381
1382 raw_ptr<MockMDnsDatagramServerSocket, DanglingUntriaged> socket_ipv4_ptr_;
1383 raw_ptr<MockMDnsDatagramServerSocket, DanglingUntriaged> socket_ipv6_ptr_;
1384 SimpleMockSocketFactory factory_;
1385 MDnsConnection connection_;
1386 TestCompletionCallback callback_;
1387 std::string sample_packet_;
1388 scoped_refptr<IOBuffer> sample_buffer_;
1389 };
1390
TEST_F(MDnsConnectionTest,ReceiveSynchronous)1391 TEST_F(MDnsConnectionTest, ReceiveSynchronous) {
1392 socket_ipv6_ptr_->SetResponsePacket(sample_packet_);
1393 EXPECT_CALL(*socket_ipv4_ptr_, RecvFrom(_, _, _, _))
1394 .WillOnce(Return(ERR_IO_PENDING));
1395 EXPECT_CALL(*socket_ipv6_ptr_, RecvFrom(_, _, _, _))
1396 .WillOnce(Invoke(socket_ipv6_ptr_.get(),
1397 &MockMDnsDatagramServerSocket::HandleRecvNow))
1398 .WillOnce(Return(ERR_IO_PENDING));
1399
1400 EXPECT_CALL(delegate_, HandlePacketInternal(sample_packet_));
1401 EXPECT_THAT(InitConnection(), test::IsOk());
1402 }
1403
TEST_F(MDnsConnectionTest,ReceiveAsynchronous)1404 TEST_F(MDnsConnectionTest, ReceiveAsynchronous) {
1405 socket_ipv6_ptr_->SetResponsePacket(sample_packet_);
1406
1407 EXPECT_CALL(*socket_ipv4_ptr_, RecvFrom(_, _, _, _))
1408 .WillOnce(Return(ERR_IO_PENDING));
1409 EXPECT_CALL(*socket_ipv6_ptr_, RecvFrom(_, _, _, _))
1410 .Times(2)
1411 .WillOnce(Invoke(socket_ipv6_ptr_.get(),
1412 &MockMDnsDatagramServerSocket::HandleRecvLater))
1413 .WillOnce(Return(ERR_IO_PENDING));
1414
1415 ASSERT_THAT(InitConnection(), test::IsOk());
1416
1417 EXPECT_CALL(delegate_, HandlePacketInternal(sample_packet_));
1418
1419 base::RunLoop().RunUntilIdle();
1420 }
1421
TEST_F(MDnsConnectionTest,Error)1422 TEST_F(MDnsConnectionTest, Error) {
1423 CompletionOnceCallback callback;
1424
1425 EXPECT_CALL(*socket_ipv4_ptr_, RecvFrom(_, _, _, _))
1426 .WillOnce(Return(ERR_IO_PENDING));
1427 EXPECT_CALL(*socket_ipv6_ptr_, RecvFrom(_, _, _, _))
1428 .WillOnce([&](auto, auto, auto, auto cb) {
1429 callback = std::move(cb);
1430 return ERR_IO_PENDING;
1431 });
1432
1433 ASSERT_THAT(InitConnection(), test::IsOk());
1434
1435 EXPECT_CALL(delegate_, OnConnectionError(ERR_SOCKET_NOT_CONNECTED));
1436 std::move(callback).Run(ERR_SOCKET_NOT_CONNECTED);
1437 base::RunLoop().RunUntilIdle();
1438 }
1439
1440 class MDnsConnectionSendTest : public MDnsConnectionTest {
1441 protected:
SetUp()1442 void SetUp() override {
1443 MDnsConnectionTest::SetUp();
1444 EXPECT_CALL(*socket_ipv4_ptr_, RecvFrom(_, _, _, _))
1445 .WillOnce(Return(ERR_IO_PENDING));
1446 EXPECT_CALL(*socket_ipv6_ptr_, RecvFrom(_, _, _, _))
1447 .WillOnce(Return(ERR_IO_PENDING));
1448 EXPECT_THAT(InitConnection(), test::IsOk());
1449 }
1450 };
1451
TEST_F(MDnsConnectionSendTest,Send)1452 TEST_F(MDnsConnectionSendTest, Send) {
1453 EXPECT_CALL(*socket_ipv4_ptr_,
1454 SendToInternal(sample_packet_, "224.0.0.251:5353", _));
1455 EXPECT_CALL(*socket_ipv6_ptr_,
1456 SendToInternal(sample_packet_, "[ff02::fb]:5353", _));
1457
1458 connection_.Send(sample_buffer_, sample_packet_.size());
1459 }
1460
TEST_F(MDnsConnectionSendTest,SendError)1461 TEST_F(MDnsConnectionSendTest, SendError) {
1462 EXPECT_CALL(*socket_ipv4_ptr_,
1463 SendToInternal(sample_packet_, "224.0.0.251:5353", _));
1464 EXPECT_CALL(*socket_ipv6_ptr_,
1465 SendToInternal(sample_packet_, "[ff02::fb]:5353", _))
1466 .WillOnce(Return(ERR_SOCKET_NOT_CONNECTED));
1467
1468 connection_.Send(sample_buffer_, sample_packet_.size());
1469 EXPECT_CALL(delegate_, OnConnectionError(ERR_SOCKET_NOT_CONNECTED));
1470 base::RunLoop().RunUntilIdle();
1471 }
1472
TEST_F(MDnsConnectionSendTest,SendQueued)1473 TEST_F(MDnsConnectionSendTest, SendQueued) {
1474 // Send data immediately.
1475 EXPECT_CALL(*socket_ipv4_ptr_,
1476 SendToInternal(sample_packet_, "224.0.0.251:5353", _))
1477 .Times(2)
1478 .WillRepeatedly(Return(OK));
1479
1480 CompletionOnceCallback callback;
1481 // Delay sending data. Only the first call should be made.
1482 EXPECT_CALL(*socket_ipv6_ptr_,
1483 SendToInternal(sample_packet_, "[ff02::fb]:5353", _))
1484 .WillOnce([&](auto, auto, auto cb) {
1485 callback = std::move(cb);
1486 return ERR_IO_PENDING;
1487 });
1488
1489 connection_.Send(sample_buffer_, sample_packet_.size());
1490 connection_.Send(sample_buffer_, sample_packet_.size());
1491
1492 // The second IPv6 packet is not sent yet.
1493 EXPECT_CALL(*socket_ipv4_ptr_,
1494 SendToInternal(sample_packet_, "224.0.0.251:5353", _))
1495 .Times(0);
1496 // Expect call for the second IPv6 packet.
1497 EXPECT_CALL(*socket_ipv6_ptr_,
1498 SendToInternal(sample_packet_, "[ff02::fb]:5353", _))
1499 .WillOnce(Return(OK));
1500 std::move(callback).Run(OK);
1501 }
1502
TEST(MDnsSocketTest,CreateSocket)1503 TEST(MDnsSocketTest, CreateSocket) {
1504 // Verifies that socket creation hasn't been broken.
1505 auto socket = CreateAndBindMDnsSocket(AddressFamily::ADDRESS_FAMILY_IPV4, 1,
1506 net::NetLog::Get());
1507 EXPECT_TRUE(socket);
1508 socket->Close();
1509 }
1510
1511 } // namespace net
1512