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 base::RunLoop loop_;
484 };
485
486 class MockListenerDelegate : public MDnsListener::Delegate {
487 public:
488 MOCK_METHOD2(OnRecordUpdate,
489 void(MDnsListener::UpdateType update,
490 const RecordParsed* records));
491 MOCK_METHOD2(OnNsecRecord, void(const std::string&, unsigned));
492 MOCK_METHOD0(OnCachePurged, void());
493 };
494
SetUp()495 void MDnsTest::SetUp() {
496 test_client_ = std::make_unique<MDnsClientImpl>();
497 ASSERT_THAT(test_client_->StartListening(&socket_factory_), test::IsOk());
498 }
499
SimulatePacketReceive(const uint8_t * packet,unsigned size)500 void MDnsTest::SimulatePacketReceive(const uint8_t* packet, unsigned size) {
501 socket_factory_.SimulateReceive(packet, size);
502 }
503
ExpectPacket(const uint8_t * packet,unsigned size)504 void MDnsTest::ExpectPacket(const uint8_t* packet, unsigned size) {
505 EXPECT_CALL(socket_factory_, OnSendTo(MakeString(packet, size)))
506 .Times(2);
507 }
508
DeleteTransaction()509 void MDnsTest::DeleteTransaction() {
510 transaction_.reset();
511 }
512
DeleteBothListeners()513 void MDnsTest::DeleteBothListeners() {
514 listener1_.reset();
515 listener2_.reset();
516 }
517
RunFor(base::TimeDelta time_period)518 void MDnsTest::RunFor(base::TimeDelta time_period) {
519 base::CancelableOnceCallback<void()> callback(
520 base::BindOnce(&MDnsTest::Stop, base::Unretained(this)));
521 base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
522 FROM_HERE, callback.callback(), time_period);
523
524 loop_.Run();
525 callback.Cancel();
526 }
527
Stop()528 void MDnsTest::Stop() {
529 loop_.QuitWhenIdle();
530 }
531
TEST_F(MDnsTest,PassiveListeners)532 TEST_F(MDnsTest, PassiveListeners) {
533 StrictMock<MockListenerDelegate> delegate_privet;
534 StrictMock<MockListenerDelegate> delegate_printer;
535
536 PtrRecordCopyContainer record_privet;
537 PtrRecordCopyContainer record_printer;
538
539 std::unique_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
540 dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet);
541 std::unique_ptr<MDnsListener> listener_printer = test_client_->CreateListener(
542 dns_protocol::kTypePTR, "_printer._tcp.local", &delegate_printer);
543
544 ASSERT_TRUE(listener_privet->Start());
545 ASSERT_TRUE(listener_printer->Start());
546
547 // Send the same packet twice to ensure no records are double-counted.
548
549 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
550 .Times(Exactly(1))
551 .WillOnce(Invoke(
552 &record_privet,
553 &PtrRecordCopyContainer::SaveWithDummyArg));
554
555 EXPECT_CALL(delegate_printer, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
556 .Times(Exactly(1))
557 .WillOnce(Invoke(
558 &record_printer,
559 &PtrRecordCopyContainer::SaveWithDummyArg));
560
561
562 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
563 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
564
565 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
566 "hello._privet._tcp.local"));
567
568 EXPECT_TRUE(record_printer.IsRecordWith("_printer._tcp.local",
569 "hello._printer._tcp.local"));
570
571 listener_privet.reset();
572 listener_printer.reset();
573 }
574
TEST_F(MDnsTest,PassiveListenersWithCapitalization)575 TEST_F(MDnsTest, PassiveListenersWithCapitalization) {
576 StrictMock<MockListenerDelegate> delegate_privet;
577 StrictMock<MockListenerDelegate> delegate_printer;
578
579 PtrRecordCopyContainer record_privet;
580 PtrRecordCopyContainer record_printer;
581
582 std::unique_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
583 dns_protocol::kTypePTR, "_privet._tcp.LOCAL", &delegate_privet);
584 std::unique_ptr<MDnsListener> listener_printer = test_client_->CreateListener(
585 dns_protocol::kTypePTR, "_prinTER._Tcp.Local", &delegate_printer);
586
587 ASSERT_TRUE(listener_privet->Start());
588 ASSERT_TRUE(listener_printer->Start());
589
590 // Send the same packet twice to ensure no records are double-counted.
591
592 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
593 .Times(Exactly(1))
594 .WillOnce(
595 Invoke(&record_privet, &PtrRecordCopyContainer::SaveWithDummyArg));
596
597 EXPECT_CALL(delegate_printer, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
598 .Times(Exactly(1))
599 .WillOnce(
600 Invoke(&record_printer, &PtrRecordCopyContainer::SaveWithDummyArg));
601
602 SimulatePacketReceive(kSamplePacket1WithCapitalization,
603 sizeof(kSamplePacket1WithCapitalization));
604 SimulatePacketReceive(kSamplePacket1WithCapitalization,
605 sizeof(kSamplePacket1WithCapitalization));
606
607 EXPECT_TRUE(record_privet.IsRecordWith("_privet._TCP.local",
608 "hello._privet._TCP.local"));
609
610 EXPECT_TRUE(record_printer.IsRecordWith("_PrinteR._TCP.local",
611 "hello._PrinteR._TCP.local"));
612
613 listener_privet.reset();
614 listener_printer.reset();
615 }
616
TEST_F(MDnsTest,PassiveListenersCacheCleanup)617 TEST_F(MDnsTest, PassiveListenersCacheCleanup) {
618 StrictMock<MockListenerDelegate> delegate_privet;
619
620 PtrRecordCopyContainer record_privet;
621 PtrRecordCopyContainer record_privet2;
622
623 std::unique_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
624 dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet);
625
626 ASSERT_TRUE(listener_privet->Start());
627
628 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
629 .Times(Exactly(1))
630 .WillOnce(Invoke(
631 &record_privet,
632 &PtrRecordCopyContainer::SaveWithDummyArg));
633
634 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
635
636 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
637 "hello._privet._tcp.local"));
638
639 // Expect record is removed when its TTL expires.
640 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_REMOVED, _))
641 .Times(Exactly(1))
642 .WillOnce(DoAll(InvokeWithoutArgs(this, &MDnsTest::Stop),
643 Invoke(&record_privet2,
644 &PtrRecordCopyContainer::SaveWithDummyArg)));
645
646 RunFor(base::Seconds(record_privet.ttl() + 1));
647
648 EXPECT_TRUE(record_privet2.IsRecordWith("_privet._tcp.local",
649 "hello._privet._tcp.local"));
650 }
651
652 // Ensure that the cleanup task scheduler won't schedule cleanup tasks in the
653 // past if the system clock creeps past the expiration time while in the
654 // cleanup dispatcher.
TEST_F(MDnsTest,CacheCleanupWithShortTTL)655 TEST_F(MDnsTest, CacheCleanupWithShortTTL) {
656 // Use a nonzero starting time as a base.
657 base::Time start_time = base::Time() + base::Seconds(1);
658
659 auto timer = std::make_unique<MockTimer>();
660 MockTimer* timer_ptr = timer.get();
661
662 auto owned_clock = std::make_unique<MockClock>();
663 MockClock* clock = owned_clock.get();
664 test_clock_ = std::move(owned_clock);
665 test_client_ = std::make_unique<MDnsClientImpl>(clock, std::move(timer));
666 ASSERT_THAT(test_client_->StartListening(&socket_factory_), test::IsOk());
667
668 EXPECT_CALL(*timer_ptr, StartObserver(_, _)).Times(1);
669 EXPECT_CALL(*clock, Now())
670 .Times(3)
671 .WillRepeatedly(Return(start_time))
672 .RetiresOnSaturation();
673
674 // Receive two records with different TTL values.
675 // TTL(privet)=1.0s
676 // TTL(printer)=3.0s
677 StrictMock<MockListenerDelegate> delegate_privet;
678 StrictMock<MockListenerDelegate> delegate_printer;
679
680 PtrRecordCopyContainer record_privet;
681 PtrRecordCopyContainer record_printer;
682
683 std::unique_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
684 dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet);
685 std::unique_ptr<MDnsListener> listener_printer = test_client_->CreateListener(
686 dns_protocol::kTypePTR, "_printer._tcp.local", &delegate_printer);
687
688 ASSERT_TRUE(listener_privet->Start());
689 ASSERT_TRUE(listener_printer->Start());
690
691 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
692 .Times(Exactly(1));
693 EXPECT_CALL(delegate_printer, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
694 .Times(Exactly(1));
695
696 SimulatePacketReceive(kSamplePacket3, sizeof(kSamplePacket3));
697
698 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_REMOVED, _))
699 .Times(Exactly(1));
700
701 // Set the clock to 2.0s, which should clean up the 'privet' record, but not
702 // the printer. The mock clock will change Now() mid-execution from 2s to 4s.
703 // Note: expectations are FILO-ordered -- t+2 seconds is returned, then t+4.
704 EXPECT_CALL(*clock, Now())
705 .WillOnce(Return(start_time + base::Seconds(4)))
706 .RetiresOnSaturation();
707 EXPECT_CALL(*clock, Now())
708 .WillOnce(Return(start_time + base::Seconds(2)))
709 .RetiresOnSaturation();
710
711 EXPECT_CALL(*timer_ptr, StartObserver(_, base::TimeDelta()));
712
713 timer_ptr->Fire();
714 }
715
TEST_F(MDnsTest,StopListening)716 TEST_F(MDnsTest, StopListening) {
717 ASSERT_TRUE(test_client_->IsListening());
718
719 test_client_->StopListening();
720 EXPECT_FALSE(test_client_->IsListening());
721 }
722
TEST_F(MDnsTest,StopListening_CacheCleanupScheduled)723 TEST_F(MDnsTest, StopListening_CacheCleanupScheduled) {
724 auto owned_clock = std::make_unique<base::SimpleTestClock>();
725 base::SimpleTestClock* clock = owned_clock.get();
726 test_clock_ = std::move(owned_clock);
727
728 // Use a nonzero starting time as a base.
729 clock->SetNow(base::Time() + base::Seconds(1));
730 auto cleanup_timer = std::make_unique<base::MockOneShotTimer>();
731 base::OneShotTimer* cleanup_timer_ptr = cleanup_timer.get();
732
733 test_client_ =
734 std::make_unique<MDnsClientImpl>(clock, std::move(cleanup_timer));
735 ASSERT_THAT(test_client_->StartListening(&socket_factory_), test::IsOk());
736 ASSERT_TRUE(test_client_->IsListening());
737
738 // Receive one record (privet) with TTL=1s to schedule cleanup.
739 SimulatePacketReceive(kSamplePacket3, sizeof(kSamplePacket3));
740 ASSERT_TRUE(cleanup_timer_ptr->IsRunning());
741
742 test_client_->StopListening();
743 EXPECT_FALSE(test_client_->IsListening());
744
745 // Expect cleanup unscheduled.
746 EXPECT_FALSE(cleanup_timer_ptr->IsRunning());
747 }
748
TEST_F(MDnsTest,MalformedPacket)749 TEST_F(MDnsTest, MalformedPacket) {
750 StrictMock<MockListenerDelegate> delegate_printer;
751
752 PtrRecordCopyContainer record_printer;
753
754 std::unique_ptr<MDnsListener> listener_printer = test_client_->CreateListener(
755 dns_protocol::kTypePTR, "_printer._tcp.local", &delegate_printer);
756
757 ASSERT_TRUE(listener_printer->Start());
758
759 EXPECT_CALL(delegate_printer, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
760 .Times(Exactly(1))
761 .WillOnce(Invoke(
762 &record_printer,
763 &PtrRecordCopyContainer::SaveWithDummyArg));
764
765 // First, send unsalvagable packet to ensure we can deal with it.
766 SimulatePacketReceive(kCorruptedPacketUnsalvagable,
767 sizeof(kCorruptedPacketUnsalvagable));
768
769 // Regression test: send a packet where the question cannot be read.
770 SimulatePacketReceive(kCorruptedPacketBadQuestion,
771 sizeof(kCorruptedPacketBadQuestion));
772
773 // Then send salvagable packet to ensure we can extract useful records.
774 SimulatePacketReceive(kCorruptedPacketSalvagable,
775 sizeof(kCorruptedPacketSalvagable));
776
777 EXPECT_TRUE(record_printer.IsRecordWith("_printer._tcp.local",
778 "hello._printer._tcp.local"));
779 }
780
TEST_F(MDnsTest,TransactionWithEmptyCache)781 TEST_F(MDnsTest, TransactionWithEmptyCache) {
782 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
783
784 std::unique_ptr<MDnsTransaction> transaction_privet =
785 test_client_->CreateTransaction(
786 dns_protocol::kTypePTR, "_privet._tcp.local",
787 MDnsTransaction::QUERY_NETWORK | MDnsTransaction::QUERY_CACHE |
788 MDnsTransaction::SINGLE_RESULT,
789 base::BindRepeating(&MDnsTest::MockableRecordCallback,
790 base::Unretained(this)));
791
792 ASSERT_TRUE(transaction_privet->Start());
793
794 PtrRecordCopyContainer record_privet;
795
796 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD, _))
797 .Times(Exactly(1))
798 .WillOnce(Invoke(&record_privet,
799 &PtrRecordCopyContainer::SaveWithDummyArg));
800
801 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
802
803 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
804 "hello._privet._tcp.local"));
805 }
806
TEST_F(MDnsTest,TransactionWithEmptyCacheAndCapitalization)807 TEST_F(MDnsTest, TransactionWithEmptyCacheAndCapitalization) {
808 ExpectPacket(kQueryPacketPrivetWithCapitalization,
809 sizeof(kQueryPacketPrivetWithCapitalization));
810
811 std::unique_ptr<MDnsTransaction> transaction_privet =
812 test_client_->CreateTransaction(
813 dns_protocol::kTypePTR, "_PRIVET._tcp.local",
814 MDnsTransaction::QUERY_NETWORK | MDnsTransaction::QUERY_CACHE |
815 MDnsTransaction::SINGLE_RESULT,
816 base::BindRepeating(&MDnsTest::MockableRecordCallback,
817 base::Unretained(this)));
818
819 ASSERT_TRUE(transaction_privet->Start());
820
821 PtrRecordCopyContainer record_privet;
822
823 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD, _))
824 .Times(Exactly(1))
825 .WillOnce(
826 Invoke(&record_privet, &PtrRecordCopyContainer::SaveWithDummyArg));
827
828 SimulatePacketReceive(kSamplePacket1WithCapitalization,
829 sizeof(kSamplePacket1WithCapitalization));
830
831 EXPECT_TRUE(record_privet.IsRecordWith("_privet._TCP.local",
832 "hello._privet._TCP.local"));
833 }
834
TEST_F(MDnsTest,TransactionCacheOnlyNoResult)835 TEST_F(MDnsTest, TransactionCacheOnlyNoResult) {
836 std::unique_ptr<MDnsTransaction> transaction_privet =
837 test_client_->CreateTransaction(
838 dns_protocol::kTypePTR, "_privet._tcp.local",
839 MDnsTransaction::QUERY_CACHE | MDnsTransaction::SINGLE_RESULT,
840 base::BindRepeating(&MDnsTest::MockableRecordCallback,
841 base::Unretained(this)));
842
843 EXPECT_CALL(*this,
844 MockableRecordCallback(MDnsTransaction::RESULT_NO_RESULTS, _))
845 .Times(Exactly(1));
846
847 ASSERT_TRUE(transaction_privet->Start());
848 }
849
TEST_F(MDnsTest,TransactionWithCache)850 TEST_F(MDnsTest, TransactionWithCache) {
851 // Listener to force the client to listen
852 StrictMock<MockListenerDelegate> delegate_irrelevant;
853 std::unique_ptr<MDnsListener> listener_irrelevant =
854 test_client_->CreateListener(dns_protocol::kTypeA,
855 "codereview.chromium.local",
856 &delegate_irrelevant);
857
858 ASSERT_TRUE(listener_irrelevant->Start());
859
860 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
861
862
863 PtrRecordCopyContainer record_privet;
864
865 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD, _))
866 .WillOnce(Invoke(&record_privet,
867 &PtrRecordCopyContainer::SaveWithDummyArg));
868
869 std::unique_ptr<MDnsTransaction> transaction_privet =
870 test_client_->CreateTransaction(
871 dns_protocol::kTypePTR, "_privet._tcp.local",
872 MDnsTransaction::QUERY_NETWORK | MDnsTransaction::QUERY_CACHE |
873 MDnsTransaction::SINGLE_RESULT,
874 base::BindRepeating(&MDnsTest::MockableRecordCallback,
875 base::Unretained(this)));
876
877 ASSERT_TRUE(transaction_privet->Start());
878
879 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
880 "hello._privet._tcp.local"));
881 }
882
TEST_F(MDnsTest,AdditionalRecords)883 TEST_F(MDnsTest, AdditionalRecords) {
884 StrictMock<MockListenerDelegate> delegate_privet;
885
886 PtrRecordCopyContainer record_privet;
887
888 std::unique_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
889 dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet);
890
891 ASSERT_TRUE(listener_privet->Start());
892
893 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
894 .Times(Exactly(1))
895 .WillOnce(Invoke(
896 &record_privet,
897 &PtrRecordCopyContainer::SaveWithDummyArg));
898
899 SimulatePacketReceive(kSamplePacketAdditionalOnly,
900 sizeof(kSamplePacketAdditionalOnly));
901
902 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
903 "hello._privet._tcp.local"));
904 }
905
TEST_F(MDnsTest,TransactionTimeout)906 TEST_F(MDnsTest, TransactionTimeout) {
907 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
908
909 std::unique_ptr<MDnsTransaction> transaction_privet =
910 test_client_->CreateTransaction(
911 dns_protocol::kTypePTR, "_privet._tcp.local",
912 MDnsTransaction::QUERY_NETWORK | MDnsTransaction::QUERY_CACHE |
913 MDnsTransaction::SINGLE_RESULT,
914 base::BindRepeating(&MDnsTest::MockableRecordCallback,
915 base::Unretained(this)));
916
917 ASSERT_TRUE(transaction_privet->Start());
918
919 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_NO_RESULTS,
920 nullptr))
921 .Times(Exactly(1))
922 .WillOnce(InvokeWithoutArgs(this, &MDnsTest::Stop));
923
924 RunFor(base::Seconds(4));
925 }
926
TEST_F(MDnsTest,TransactionMultipleRecords)927 TEST_F(MDnsTest, TransactionMultipleRecords) {
928 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
929
930 std::unique_ptr<MDnsTransaction> transaction_privet =
931 test_client_->CreateTransaction(
932 dns_protocol::kTypePTR, "_privet._tcp.local",
933 MDnsTransaction::QUERY_NETWORK | MDnsTransaction::QUERY_CACHE,
934 base::BindRepeating(&MDnsTest::MockableRecordCallback,
935 base::Unretained(this)));
936
937 ASSERT_TRUE(transaction_privet->Start());
938
939 PtrRecordCopyContainer record_privet;
940 PtrRecordCopyContainer record_privet2;
941
942 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD, _))
943 .Times(Exactly(2))
944 .WillOnce(Invoke(&record_privet,
945 &PtrRecordCopyContainer::SaveWithDummyArg))
946 .WillOnce(Invoke(&record_privet2,
947 &PtrRecordCopyContainer::SaveWithDummyArg));
948
949 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
950 SimulatePacketReceive(kSamplePacket2, sizeof(kSamplePacket2));
951
952 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
953 "hello._privet._tcp.local"));
954
955 EXPECT_TRUE(record_privet2.IsRecordWith("_privet._tcp.local",
956 "zzzzz._privet._tcp.local"));
957
958 EXPECT_CALL(*this,
959 MockableRecordCallback(MDnsTransaction::RESULT_DONE, nullptr))
960 .WillOnce(InvokeWithoutArgs(this, &MDnsTest::Stop));
961
962 RunFor(base::Seconds(4));
963 }
964
TEST_F(MDnsTest,TransactionReentrantDelete)965 TEST_F(MDnsTest, TransactionReentrantDelete) {
966 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
967
968 transaction_ = test_client_->CreateTransaction(
969 dns_protocol::kTypePTR, "_privet._tcp.local",
970 MDnsTransaction::QUERY_NETWORK | MDnsTransaction::QUERY_CACHE |
971 MDnsTransaction::SINGLE_RESULT,
972 base::BindRepeating(&MDnsTest::MockableRecordCallback,
973 base::Unretained(this)));
974
975 ASSERT_TRUE(transaction_->Start());
976
977 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_NO_RESULTS,
978 nullptr))
979 .Times(Exactly(1))
980 .WillOnce(DoAll(InvokeWithoutArgs(this, &MDnsTest::DeleteTransaction),
981 InvokeWithoutArgs(this, &MDnsTest::Stop)));
982
983 RunFor(base::Seconds(4));
984
985 EXPECT_EQ(nullptr, transaction_.get());
986 }
987
TEST_F(MDnsTest,TransactionReentrantDeleteFromCache)988 TEST_F(MDnsTest, TransactionReentrantDeleteFromCache) {
989 StrictMock<MockListenerDelegate> delegate_irrelevant;
990 std::unique_ptr<MDnsListener> listener_irrelevant =
991 test_client_->CreateListener(dns_protocol::kTypeA,
992 "codereview.chromium.local",
993 &delegate_irrelevant);
994 ASSERT_TRUE(listener_irrelevant->Start());
995
996 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
997
998 transaction_ = test_client_->CreateTransaction(
999 dns_protocol::kTypePTR, "_privet._tcp.local",
1000 MDnsTransaction::QUERY_NETWORK | MDnsTransaction::QUERY_CACHE,
1001 base::BindRepeating(&MDnsTest::MockableRecordCallback,
1002 base::Unretained(this)));
1003
1004 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD, _))
1005 .Times(Exactly(1))
1006 .WillOnce(InvokeWithoutArgs(this, &MDnsTest::DeleteTransaction));
1007
1008 ASSERT_TRUE(transaction_->Start());
1009
1010 EXPECT_EQ(nullptr, transaction_.get());
1011 }
1012
TEST_F(MDnsTest,TransactionReentrantCacheLookupStart)1013 TEST_F(MDnsTest, TransactionReentrantCacheLookupStart) {
1014 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
1015
1016 std::unique_ptr<MDnsTransaction> transaction1 =
1017 test_client_->CreateTransaction(
1018 dns_protocol::kTypePTR, "_privet._tcp.local",
1019 MDnsTransaction::QUERY_NETWORK | MDnsTransaction::QUERY_CACHE |
1020 MDnsTransaction::SINGLE_RESULT,
1021 base::BindRepeating(&MDnsTest::MockableRecordCallback,
1022 base::Unretained(this)));
1023
1024 std::unique_ptr<MDnsTransaction> transaction2 =
1025 test_client_->CreateTransaction(
1026 dns_protocol::kTypePTR, "_printer._tcp.local",
1027 MDnsTransaction::QUERY_CACHE | MDnsTransaction::SINGLE_RESULT,
1028 base::BindRepeating(&MDnsTest::MockableRecordCallback2,
1029 base::Unretained(this)));
1030
1031 EXPECT_CALL(*this, MockableRecordCallback2(MDnsTransaction::RESULT_RECORD,
1032 _))
1033 .Times(Exactly(1));
1034
1035 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD,
1036 _))
1037 .Times(Exactly(1))
1038 .WillOnce(IgnoreResult(InvokeWithoutArgs(transaction2.get(),
1039 &MDnsTransaction::Start)));
1040
1041 ASSERT_TRUE(transaction1->Start());
1042
1043 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
1044 }
1045
TEST_F(MDnsTest,GoodbyePacketNotification)1046 TEST_F(MDnsTest, GoodbyePacketNotification) {
1047 StrictMock<MockListenerDelegate> delegate_privet;
1048
1049 std::unique_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
1050 dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet);
1051 ASSERT_TRUE(listener_privet->Start());
1052
1053 SimulatePacketReceive(kSamplePacketGoodbye, sizeof(kSamplePacketGoodbye));
1054
1055 RunFor(base::Seconds(2));
1056 }
1057
TEST_F(MDnsTest,GoodbyePacketRemoval)1058 TEST_F(MDnsTest, GoodbyePacketRemoval) {
1059 StrictMock<MockListenerDelegate> delegate_privet;
1060
1061 std::unique_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
1062 dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet);
1063 ASSERT_TRUE(listener_privet->Start());
1064
1065 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
1066 .Times(Exactly(1));
1067
1068 SimulatePacketReceive(kSamplePacket2, sizeof(kSamplePacket2));
1069
1070 SimulatePacketReceive(kSamplePacketGoodbye, sizeof(kSamplePacketGoodbye));
1071
1072 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_REMOVED, _))
1073 .Times(Exactly(1));
1074
1075 RunFor(base::Seconds(2));
1076 }
1077
1078 // In order to reliably test reentrant listener deletes, we create two listeners
1079 // and have each of them delete both, so we're guaranteed to try and deliver a
1080 // callback to at least one deleted listener.
1081
TEST_F(MDnsTest,ListenerReentrantDelete)1082 TEST_F(MDnsTest, ListenerReentrantDelete) {
1083 StrictMock<MockListenerDelegate> delegate_privet;
1084
1085 listener1_ = test_client_->CreateListener(
1086 dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet);
1087
1088 listener2_ = test_client_->CreateListener(
1089 dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet);
1090
1091 ASSERT_TRUE(listener1_->Start());
1092
1093 ASSERT_TRUE(listener2_->Start());
1094
1095 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
1096 .Times(Exactly(1))
1097 .WillOnce(InvokeWithoutArgs(this, &MDnsTest::DeleteBothListeners));
1098
1099 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
1100
1101 EXPECT_EQ(nullptr, listener1_.get());
1102 EXPECT_EQ(nullptr, listener2_.get());
1103 }
1104
ACTION_P(SaveIPAddress,ip_container)1105 ACTION_P(SaveIPAddress, ip_container) {
1106 ::testing::StaticAssertTypeEq<const RecordParsed*, arg1_type>();
1107 ::testing::StaticAssertTypeEq<IPAddress*, ip_container_type>();
1108
1109 *ip_container = arg1->template rdata<ARecordRdata>()->address();
1110 }
1111
TEST_F(MDnsTest,DoubleRecordDisagreeing)1112 TEST_F(MDnsTest, DoubleRecordDisagreeing) {
1113 IPAddress address;
1114 StrictMock<MockListenerDelegate> delegate_privet;
1115
1116 std::unique_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
1117 dns_protocol::kTypeA, "privet.local", &delegate_privet);
1118
1119 ASSERT_TRUE(listener_privet->Start());
1120
1121 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
1122 .Times(Exactly(1))
1123 .WillOnce(SaveIPAddress(&address));
1124
1125 SimulatePacketReceive(kCorruptedPacketDoubleRecord,
1126 sizeof(kCorruptedPacketDoubleRecord));
1127
1128 EXPECT_EQ("2.3.4.5", address.ToString());
1129 }
1130
TEST_F(MDnsTest,NsecWithListener)1131 TEST_F(MDnsTest, NsecWithListener) {
1132 StrictMock<MockListenerDelegate> delegate_privet;
1133 std::unique_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
1134 dns_protocol::kTypeA, "_privet._tcp.local", &delegate_privet);
1135
1136 // Test to make sure nsec callback is NOT called for PTR
1137 // (which is marked as existing).
1138 StrictMock<MockListenerDelegate> delegate_privet2;
1139 std::unique_ptr<MDnsListener> listener_privet2 = test_client_->CreateListener(
1140 dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet2);
1141
1142 ASSERT_TRUE(listener_privet->Start());
1143
1144 EXPECT_CALL(delegate_privet,
1145 OnNsecRecord("_privet._tcp.local", dns_protocol::kTypeA));
1146
1147 SimulatePacketReceive(kSamplePacketNsec,
1148 sizeof(kSamplePacketNsec));
1149 }
1150
TEST_F(MDnsTest,NsecWithTransactionFromNetwork)1151 TEST_F(MDnsTest, NsecWithTransactionFromNetwork) {
1152 std::unique_ptr<MDnsTransaction> transaction_privet =
1153 test_client_->CreateTransaction(
1154 dns_protocol::kTypeA, "_privet._tcp.local",
1155 MDnsTransaction::QUERY_NETWORK | MDnsTransaction::QUERY_CACHE |
1156 MDnsTransaction::SINGLE_RESULT,
1157 base::BindRepeating(&MDnsTest::MockableRecordCallback,
1158 base::Unretained(this)));
1159
1160 EXPECT_CALL(socket_factory_, OnSendTo(_)).Times(2);
1161
1162 ASSERT_TRUE(transaction_privet->Start());
1163
1164 EXPECT_CALL(*this,
1165 MockableRecordCallback(MDnsTransaction::RESULT_NSEC, nullptr));
1166
1167 SimulatePacketReceive(kSamplePacketNsec,
1168 sizeof(kSamplePacketNsec));
1169 }
1170
TEST_F(MDnsTest,NsecWithTransactionFromCache)1171 TEST_F(MDnsTest, NsecWithTransactionFromCache) {
1172 // Force mDNS to listen.
1173 StrictMock<MockListenerDelegate> delegate_irrelevant;
1174 std::unique_ptr<MDnsListener> listener_irrelevant =
1175 test_client_->CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local",
1176 &delegate_irrelevant);
1177 listener_irrelevant->Start();
1178
1179 SimulatePacketReceive(kSamplePacketNsec,
1180 sizeof(kSamplePacketNsec));
1181
1182 EXPECT_CALL(*this,
1183 MockableRecordCallback(MDnsTransaction::RESULT_NSEC, nullptr));
1184
1185 std::unique_ptr<MDnsTransaction> transaction_privet_a =
1186 test_client_->CreateTransaction(
1187 dns_protocol::kTypeA, "_privet._tcp.local",
1188 MDnsTransaction::QUERY_NETWORK | MDnsTransaction::QUERY_CACHE |
1189 MDnsTransaction::SINGLE_RESULT,
1190 base::BindRepeating(&MDnsTest::MockableRecordCallback,
1191 base::Unretained(this)));
1192
1193 ASSERT_TRUE(transaction_privet_a->Start());
1194
1195 // Test that a PTR transaction does NOT consider the same NSEC record to be a
1196 // valid answer to the query
1197
1198 std::unique_ptr<MDnsTransaction> transaction_privet_ptr =
1199 test_client_->CreateTransaction(
1200 dns_protocol::kTypePTR, "_privet._tcp.local",
1201 MDnsTransaction::QUERY_NETWORK | MDnsTransaction::QUERY_CACHE |
1202 MDnsTransaction::SINGLE_RESULT,
1203 base::BindRepeating(&MDnsTest::MockableRecordCallback,
1204 base::Unretained(this)));
1205
1206 EXPECT_CALL(socket_factory_, OnSendTo(_)).Times(2);
1207
1208 ASSERT_TRUE(transaction_privet_ptr->Start());
1209 }
1210
TEST_F(MDnsTest,NsecConflictRemoval)1211 TEST_F(MDnsTest, NsecConflictRemoval) {
1212 StrictMock<MockListenerDelegate> delegate_privet;
1213 std::unique_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
1214 dns_protocol::kTypeA, "_privet._tcp.local", &delegate_privet);
1215
1216 ASSERT_TRUE(listener_privet->Start());
1217
1218 const RecordParsed* record1;
1219 const RecordParsed* record2;
1220
1221 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
1222 .WillOnce(SaveArg<1>(&record1));
1223
1224 SimulatePacketReceive(kSamplePacketAPrivet,
1225 sizeof(kSamplePacketAPrivet));
1226
1227 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_REMOVED, _))
1228 .WillOnce(SaveArg<1>(&record2));
1229
1230 EXPECT_CALL(delegate_privet,
1231 OnNsecRecord("_privet._tcp.local", dns_protocol::kTypeA));
1232
1233 SimulatePacketReceive(kSamplePacketNsec,
1234 sizeof(kSamplePacketNsec));
1235
1236 EXPECT_EQ(record1, record2);
1237 }
1238
1239 // TODO(https://crbug.com/1274091): Flaky on fuchsia.
1240 #if BUILDFLAG(IS_FUCHSIA)
1241 #define MAYBE_RefreshQuery DISABLED_RefreshQuery
1242 #else
1243 #define MAYBE_RefreshQuery RefreshQuery
1244 #endif
TEST_F(MDnsTest,MAYBE_RefreshQuery)1245 TEST_F(MDnsTest, MAYBE_RefreshQuery) {
1246 StrictMock<MockListenerDelegate> delegate_privet;
1247 std::unique_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
1248 dns_protocol::kTypeA, "_privet._tcp.local", &delegate_privet);
1249
1250 listener_privet->SetActiveRefresh(true);
1251 ASSERT_TRUE(listener_privet->Start());
1252
1253 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _));
1254
1255 SimulatePacketReceive(kSamplePacketAPrivet,
1256 sizeof(kSamplePacketAPrivet));
1257
1258 // Expecting 2 calls (one for ipv4 and one for ipv6) for each of the 2
1259 // scheduled refresh queries.
1260 EXPECT_CALL(socket_factory_, OnSendTo(
1261 MakeString(kQueryPacketPrivetA, sizeof(kQueryPacketPrivetA))))
1262 .Times(4);
1263
1264 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_REMOVED, _));
1265
1266 RunFor(base::Seconds(6));
1267 }
1268
1269 // MDnsSocketFactory implementation that creates a single socket that will
1270 // always fail on RecvFrom. Passing this to MdnsClient is expected to result in
1271 // the client failing to start listening.
1272 class FailingSocketFactory : public MDnsSocketFactory {
CreateSockets(std::vector<std::unique_ptr<DatagramServerSocket>> * sockets)1273 void CreateSockets(
1274 std::vector<std::unique_ptr<DatagramServerSocket>>* sockets) override {
1275 auto socket =
1276 std::make_unique<MockMDnsDatagramServerSocket>(ADDRESS_FAMILY_IPV4);
1277 EXPECT_CALL(*socket, RecvFrom(_, _, _, _))
1278 .WillRepeatedly(Return(ERR_FAILED));
1279 sockets->push_back(std::move(socket));
1280 }
1281 };
1282
TEST_F(MDnsTest,StartListeningFailure)1283 TEST_F(MDnsTest, StartListeningFailure) {
1284 test_client_ = std::make_unique<MDnsClientImpl>();
1285 FailingSocketFactory socket_factory;
1286
1287 EXPECT_THAT(test_client_->StartListening(&socket_factory),
1288 test::IsError(ERR_FAILED));
1289 }
1290
1291 // Test that the cache is cleared when it gets filled to unreasonable sizes.
TEST_F(MDnsTest,ClearOverfilledCache)1292 TEST_F(MDnsTest, ClearOverfilledCache) {
1293 test_client_->core()->cache_for_testing()->set_entry_limit_for_testing(1);
1294
1295 StrictMock<MockListenerDelegate> delegate_privet;
1296 StrictMock<MockListenerDelegate> delegate_printer;
1297
1298 PtrRecordCopyContainer record_privet;
1299 PtrRecordCopyContainer record_printer;
1300
1301 std::unique_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
1302 dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet);
1303 std::unique_ptr<MDnsListener> listener_printer = test_client_->CreateListener(
1304 dns_protocol::kTypePTR, "_printer._tcp.local", &delegate_printer);
1305
1306 ASSERT_TRUE(listener_privet->Start());
1307 ASSERT_TRUE(listener_printer->Start());
1308
1309 bool privet_added = false;
1310 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
1311 .Times(AtMost(1))
1312 .WillOnce(Assign(&privet_added, true));
1313 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_REMOVED, _))
1314 .WillRepeatedly(Assign(&privet_added, false));
1315
1316 bool printer_added = false;
1317 EXPECT_CALL(delegate_printer, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
1318 .Times(AtMost(1))
1319 .WillOnce(Assign(&printer_added, true));
1320 EXPECT_CALL(delegate_printer, OnRecordUpdate(MDnsListener::RECORD_REMOVED, _))
1321 .WillRepeatedly(Assign(&printer_added, false));
1322
1323 // Fill past capacity and expect everything to eventually be removed.
1324 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
1325 base::RunLoop().RunUntilIdle();
1326 EXPECT_FALSE(privet_added);
1327 EXPECT_FALSE(printer_added);
1328 }
1329
1330 // Note: These tests assume that the ipv4 socket will always be created first.
1331 // This is a simplifying assumption based on the way the code works now.
1332 class SimpleMockSocketFactory : public MDnsSocketFactory {
1333 public:
CreateSockets(std::vector<std::unique_ptr<DatagramServerSocket>> * sockets)1334 void CreateSockets(
1335 std::vector<std::unique_ptr<DatagramServerSocket>>* sockets) override {
1336 sockets->clear();
1337 sockets->swap(sockets_);
1338 }
1339
PushSocket(std::unique_ptr<DatagramServerSocket> socket)1340 void PushSocket(std::unique_ptr<DatagramServerSocket> socket) {
1341 sockets_.push_back(std::move(socket));
1342 }
1343
1344 private:
1345 std::vector<std::unique_ptr<DatagramServerSocket>> sockets_;
1346 };
1347
1348 class MockMDnsConnectionDelegate : public MDnsConnection::Delegate {
1349 public:
HandlePacket(DnsResponse * response,int size)1350 void HandlePacket(DnsResponse* response, int size) override {
1351 HandlePacketInternal(std::string(response->io_buffer()->data(), size));
1352 }
1353
1354 MOCK_METHOD1(HandlePacketInternal, void(std::string packet));
1355
1356 MOCK_METHOD1(OnConnectionError, void(int error));
1357 };
1358
1359 class MDnsConnectionTest : public TestWithTaskEnvironment {
1360 public:
MDnsConnectionTest()1361 MDnsConnectionTest() : connection_(&delegate_) {
1362 }
1363
1364 protected:
1365 // Follow successful connection initialization.
SetUp()1366 void SetUp() override {
1367 auto socket_ipv4 =
1368 std::make_unique<MockMDnsDatagramServerSocket>(ADDRESS_FAMILY_IPV4);
1369 auto socket_ipv6 =
1370 std::make_unique<MockMDnsDatagramServerSocket>(ADDRESS_FAMILY_IPV6);
1371 socket_ipv4_ptr_ = socket_ipv4.get();
1372 socket_ipv6_ptr_ = socket_ipv6.get();
1373 factory_.PushSocket(std::move(socket_ipv4));
1374 factory_.PushSocket(std::move(socket_ipv6));
1375 sample_packet_ = MakeString(kSamplePacket1, sizeof(kSamplePacket1));
1376 sample_buffer_ = base::MakeRefCounted<StringIOBuffer>(sample_packet_);
1377 }
1378
InitConnection()1379 int InitConnection() { return connection_.Init(&factory_); }
1380
1381 StrictMock<MockMDnsConnectionDelegate> delegate_;
1382
1383 raw_ptr<MockMDnsDatagramServerSocket, DanglingUntriaged> socket_ipv4_ptr_;
1384 raw_ptr<MockMDnsDatagramServerSocket, DanglingUntriaged> socket_ipv6_ptr_;
1385 SimpleMockSocketFactory factory_;
1386 MDnsConnection connection_;
1387 TestCompletionCallback callback_;
1388 std::string sample_packet_;
1389 scoped_refptr<IOBuffer> sample_buffer_;
1390 };
1391
TEST_F(MDnsConnectionTest,ReceiveSynchronous)1392 TEST_F(MDnsConnectionTest, ReceiveSynchronous) {
1393 socket_ipv6_ptr_->SetResponsePacket(sample_packet_);
1394 EXPECT_CALL(*socket_ipv4_ptr_, RecvFrom(_, _, _, _))
1395 .WillOnce(Return(ERR_IO_PENDING));
1396 EXPECT_CALL(*socket_ipv6_ptr_, RecvFrom(_, _, _, _))
1397 .WillOnce(Invoke(socket_ipv6_ptr_.get(),
1398 &MockMDnsDatagramServerSocket::HandleRecvNow))
1399 .WillOnce(Return(ERR_IO_PENDING));
1400
1401 EXPECT_CALL(delegate_, HandlePacketInternal(sample_packet_));
1402 EXPECT_THAT(InitConnection(), test::IsOk());
1403 }
1404
TEST_F(MDnsConnectionTest,ReceiveAsynchronous)1405 TEST_F(MDnsConnectionTest, ReceiveAsynchronous) {
1406 socket_ipv6_ptr_->SetResponsePacket(sample_packet_);
1407
1408 EXPECT_CALL(*socket_ipv4_ptr_, RecvFrom(_, _, _, _))
1409 .WillOnce(Return(ERR_IO_PENDING));
1410 EXPECT_CALL(*socket_ipv6_ptr_, RecvFrom(_, _, _, _))
1411 .Times(2)
1412 .WillOnce(Invoke(socket_ipv6_ptr_.get(),
1413 &MockMDnsDatagramServerSocket::HandleRecvLater))
1414 .WillOnce(Return(ERR_IO_PENDING));
1415
1416 ASSERT_THAT(InitConnection(), test::IsOk());
1417
1418 EXPECT_CALL(delegate_, HandlePacketInternal(sample_packet_));
1419
1420 base::RunLoop().RunUntilIdle();
1421 }
1422
TEST_F(MDnsConnectionTest,Error)1423 TEST_F(MDnsConnectionTest, Error) {
1424 CompletionOnceCallback callback;
1425
1426 EXPECT_CALL(*socket_ipv4_ptr_, RecvFrom(_, _, _, _))
1427 .WillOnce(Return(ERR_IO_PENDING));
1428 EXPECT_CALL(*socket_ipv6_ptr_, RecvFrom(_, _, _, _))
1429 .WillOnce([&](auto, auto, auto, auto cb) {
1430 callback = std::move(cb);
1431 return ERR_IO_PENDING;
1432 });
1433
1434 ASSERT_THAT(InitConnection(), test::IsOk());
1435
1436 EXPECT_CALL(delegate_, OnConnectionError(ERR_SOCKET_NOT_CONNECTED));
1437 std::move(callback).Run(ERR_SOCKET_NOT_CONNECTED);
1438 base::RunLoop().RunUntilIdle();
1439 }
1440
1441 class MDnsConnectionSendTest : public MDnsConnectionTest {
1442 protected:
SetUp()1443 void SetUp() override {
1444 MDnsConnectionTest::SetUp();
1445 EXPECT_CALL(*socket_ipv4_ptr_, RecvFrom(_, _, _, _))
1446 .WillOnce(Return(ERR_IO_PENDING));
1447 EXPECT_CALL(*socket_ipv6_ptr_, RecvFrom(_, _, _, _))
1448 .WillOnce(Return(ERR_IO_PENDING));
1449 EXPECT_THAT(InitConnection(), test::IsOk());
1450 }
1451 };
1452
TEST_F(MDnsConnectionSendTest,Send)1453 TEST_F(MDnsConnectionSendTest, Send) {
1454 EXPECT_CALL(*socket_ipv4_ptr_,
1455 SendToInternal(sample_packet_, "224.0.0.251:5353", _));
1456 EXPECT_CALL(*socket_ipv6_ptr_,
1457 SendToInternal(sample_packet_, "[ff02::fb]:5353", _));
1458
1459 connection_.Send(sample_buffer_, sample_packet_.size());
1460 }
1461
TEST_F(MDnsConnectionSendTest,SendError)1462 TEST_F(MDnsConnectionSendTest, SendError) {
1463 EXPECT_CALL(*socket_ipv4_ptr_,
1464 SendToInternal(sample_packet_, "224.0.0.251:5353", _));
1465 EXPECT_CALL(*socket_ipv6_ptr_,
1466 SendToInternal(sample_packet_, "[ff02::fb]:5353", _))
1467 .WillOnce(Return(ERR_SOCKET_NOT_CONNECTED));
1468
1469 connection_.Send(sample_buffer_, sample_packet_.size());
1470 EXPECT_CALL(delegate_, OnConnectionError(ERR_SOCKET_NOT_CONNECTED));
1471 base::RunLoop().RunUntilIdle();
1472 }
1473
TEST_F(MDnsConnectionSendTest,SendQueued)1474 TEST_F(MDnsConnectionSendTest, SendQueued) {
1475 // Send data immediately.
1476 EXPECT_CALL(*socket_ipv4_ptr_,
1477 SendToInternal(sample_packet_, "224.0.0.251:5353", _))
1478 .Times(2)
1479 .WillRepeatedly(Return(OK));
1480
1481 CompletionOnceCallback callback;
1482 // Delay sending data. Only the first call should be made.
1483 EXPECT_CALL(*socket_ipv6_ptr_,
1484 SendToInternal(sample_packet_, "[ff02::fb]:5353", _))
1485 .WillOnce([&](auto, auto, auto cb) {
1486 callback = std::move(cb);
1487 return ERR_IO_PENDING;
1488 });
1489
1490 connection_.Send(sample_buffer_, sample_packet_.size());
1491 connection_.Send(sample_buffer_, sample_packet_.size());
1492
1493 // The second IPv6 packet is not sent yet.
1494 EXPECT_CALL(*socket_ipv4_ptr_,
1495 SendToInternal(sample_packet_, "224.0.0.251:5353", _))
1496 .Times(0);
1497 // Expect call for the second IPv6 packet.
1498 EXPECT_CALL(*socket_ipv6_ptr_,
1499 SendToInternal(sample_packet_, "[ff02::fb]:5353", _))
1500 .WillOnce(Return(OK));
1501 std::move(callback).Run(OK);
1502 }
1503
TEST(MDnsSocketTest,CreateSocket)1504 TEST(MDnsSocketTest, CreateSocket) {
1505 // Verifies that socket creation hasn't been broken.
1506 auto socket = CreateAndBindMDnsSocket(AddressFamily::ADDRESS_FAMILY_IPV4, 1,
1507 net::NetLog::Get());
1508 EXPECT_TRUE(socket);
1509 socket->Close();
1510 }
1511
1512 } // namespace net
1513