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