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