OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/extensions/api/dial/dial_service.h" | 5 #include "chrome/browser/extensions/api/dial/dial_service.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <set> |
| 9 #include <utility> |
8 | 10 |
9 #include "base/basictypes.h" | 11 #include "base/basictypes.h" |
10 #include "base/callback.h" | 12 #include "base/callback.h" |
11 #include "base/logging.h" | 13 #include "base/logging.h" |
12 #include "base/rand_util.h" | 14 #include "base/rand_util.h" |
13 #include "base/strings/string_number_conversions.h" | 15 #include "base/strings/string_number_conversions.h" |
14 #include "base/strings/stringprintf.h" | 16 #include "base/strings/stringprintf.h" |
15 #include "base/time/time.h" | 17 #include "base/time/time.h" |
16 #include "chrome/browser/extensions/api/dial/dial_device_data.h" | 18 #include "chrome/browser/extensions/api/dial/dial_device_data.h" |
17 #include "chrome/common/chrome_version_info.h" | 19 #include "chrome/common/chrome_version_info.h" |
(...skipping 444 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
462 #else | 464 #else |
463 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind( | 465 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind( |
464 &GetNetworkListOnFileThread, | 466 &GetNetworkListOnFileThread, |
465 base::MessageLoopProxy::current(), base::Bind( | 467 base::MessageLoopProxy::current(), base::Bind( |
466 &DialServiceImpl::SendNetworkList, AsWeakPtr()))); | 468 &DialServiceImpl::SendNetworkList, AsWeakPtr()))); |
467 #endif | 469 #endif |
468 } | 470 } |
469 | 471 |
470 void DialServiceImpl::SendNetworkList(const NetworkInterfaceList& networks) { | 472 void DialServiceImpl::SendNetworkList(const NetworkInterfaceList& networks) { |
471 DCHECK(thread_checker_.CalledOnValidThread()); | 473 DCHECK(thread_checker_.CalledOnValidThread()); |
| 474 typedef std::pair<uint32, net::AddressFamily> InterfaceIndexAddressFamily; |
| 475 std::set<InterfaceIndexAddressFamily> interface_index_addr_family_seen; |
472 std::vector<IPAddressNumber> ip_addresses; | 476 std::vector<IPAddressNumber> ip_addresses; |
473 | 477 |
474 // Returns the first IPv4 address found. If there is a need for discovery | 478 // Binds a socket to each IPv4 network interface found. Note that |
475 // across multiple networks, we could manage multiple sockets. | 479 // there may be duplicates in |networks|, so address family + interface index |
| 480 // is used to identify unique interfaces. |
476 // TODO(mfoltz): Support IPV6 multicast. http://crbug.com/165286 | 481 // TODO(mfoltz): Support IPV6 multicast. http://crbug.com/165286 |
477 for (NetworkInterfaceList::const_iterator iter = networks.begin(); | 482 for (NetworkInterfaceList::const_iterator iter = networks.begin(); |
478 iter != networks.end(); ++iter) { | 483 iter != networks.end(); ++iter) { |
| 484 net::AddressFamily addr_family = net::GetAddressFamily(iter->address); |
479 DVLOG(1) << "Found " << iter->name << ", " | 485 DVLOG(1) << "Found " << iter->name << ", " |
480 << net::IPAddressToString(iter->address); | 486 << net::IPAddressToString(iter->address) |
481 if (iter->address.size() == net::kIPv4AddressSize) { | 487 << ", address family: " << addr_family; |
482 ip_addresses.push_back(iter->address); | 488 if (addr_family == net::ADDRESS_FAMILY_IPV4) { |
483 break; | 489 InterfaceIndexAddressFamily interface_index_addr_family = |
| 490 std::make_pair(iter->interface_index, addr_family); |
| 491 bool inserted = interface_index_addr_family_seen |
| 492 .insert(interface_index_addr_family) |
| 493 .second; |
| 494 // We have not seen this interface before, so add its IP address to the |
| 495 // discovery list. |
| 496 if (inserted) { |
| 497 VLOG(2) << "Encountered " |
| 498 << "interface index: " << iter->interface_index << ", " |
| 499 << "address family: " << addr_family << " for the first time, " |
| 500 << "adding IP address " << net::IPAddressToString(iter->address) |
| 501 << " to list."; |
| 502 ip_addresses.push_back(iter->address); |
| 503 } else { |
| 504 VLOG(2) << "Already encountered " |
| 505 << "interface index: " << iter->interface_index << ", " |
| 506 << "address family: " << addr_family << " before, not adding."; |
| 507 } |
484 } | 508 } |
485 } | 509 } |
486 | 510 |
487 DiscoverOnAddresses(ip_addresses); | 511 DiscoverOnAddresses(ip_addresses); |
488 } | 512 } |
489 | 513 |
490 void DialServiceImpl::DiscoverOnAddresses( | 514 void DialServiceImpl::DiscoverOnAddresses( |
491 const std::vector<IPAddressNumber>& ip_addresses) { | 515 const std::vector<IPAddressNumber>& ip_addresses) { |
492 if (ip_addresses.size() == 0) { | 516 if (ip_addresses.empty()) { |
493 DVLOG(1) << "Could not find a valid interface to bind. Finishing discovery"; | 517 DVLOG(1) << "Could not find a valid interface to bind. Finishing discovery"; |
494 FinishDiscovery(); | 518 FinishDiscovery(); |
495 return; | 519 return; |
496 } | 520 } |
497 | 521 |
498 // Schedule a timer to finish the discovery process (and close the sockets). | 522 // Schedule a timer to finish the discovery process (and close the sockets). |
499 if (finish_delay_ > TimeDelta::FromSeconds(0)) { | 523 if (finish_delay_ > TimeDelta::FromSeconds(0)) { |
500 VLOG(2) << "Starting timer to finish discovery."; | 524 VLOG(2) << "Starting timer to finish discovery."; |
501 finish_timer_.Start(FROM_HERE, | 525 finish_timer_.Start(FROM_HERE, |
502 finish_delay_, | 526 finish_delay_, |
503 this, | 527 this, |
504 &DialServiceImpl::FinishDiscovery); | 528 &DialServiceImpl::FinishDiscovery); |
505 } | 529 } |
506 | 530 |
507 for (std::vector<IPAddressNumber>::const_iterator iter = ip_addresses.begin(); | 531 for (std::vector<IPAddressNumber>::const_iterator iter = ip_addresses.begin(); |
508 iter != ip_addresses.end(); | 532 iter != ip_addresses.end(); |
509 ++iter) { | 533 ++iter) |
510 BindAndAddSocket(*iter); | 534 BindAndAddSocket(*iter); |
511 } | |
512 | 535 |
513 SendOneRequest(); | 536 SendOneRequest(); |
514 } | 537 } |
515 | 538 |
516 void DialServiceImpl::BindAndAddSocket(const IPAddressNumber& bind_ip_address) { | 539 void DialServiceImpl::BindAndAddSocket(const IPAddressNumber& bind_ip_address) { |
517 scoped_ptr<DialServiceImpl::DialSocket> dial_socket(CreateDialSocket()); | 540 scoped_ptr<DialServiceImpl::DialSocket> dial_socket(CreateDialSocket()); |
518 if (dial_socket->CreateAndBindSocket(bind_ip_address, net_log_, | 541 if (dial_socket->CreateAndBindSocket(bind_ip_address, net_log_, |
519 net_log_source_)) | 542 net_log_source_)) |
520 dial_sockets_.push_back(dial_socket.release()); | 543 dial_sockets_.push_back(dial_socket.release()); |
521 } | 544 } |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
554 if (!discovery_active_) { | 577 if (!discovery_active_) { |
555 VLOG(2) << "Request sent after discovery finished. Ignoring."; | 578 VLOG(2) << "Request sent after discovery finished. Ignoring."; |
556 return; | 579 return; |
557 } | 580 } |
558 | 581 |
559 VLOG(2) << "Notifying observers of discovery request"; | 582 VLOG(2) << "Notifying observers of discovery request"; |
560 FOR_EACH_OBSERVER(Observer, observer_list_, OnDiscoveryRequest(this)); | 583 FOR_EACH_OBSERVER(Observer, observer_list_, OnDiscoveryRequest(this)); |
561 // If we need to send additional requests, schedule a timer to do so. | 584 // If we need to send additional requests, schedule a timer to do so. |
562 if (num_requests_sent_ < max_requests_ && num_requests_sent_ == 1) { | 585 if (num_requests_sent_ < max_requests_ && num_requests_sent_ == 1) { |
563 VLOG(2) << "Scheduling timer to send additional requests"; | 586 VLOG(2) << "Scheduling timer to send additional requests"; |
| 587 // TODO(imcheng): Move this to SendOneRequest() once the implications are |
| 588 // understood. |
564 request_timer_.Start(FROM_HERE, | 589 request_timer_.Start(FROM_HERE, |
565 request_interval_, | 590 request_interval_, |
566 this, | 591 this, |
567 &DialServiceImpl::SendOneRequest); | 592 &DialServiceImpl::SendOneRequest); |
568 } | 593 } |
569 } | 594 } |
570 | 595 |
571 void DialServiceImpl::NotifyOnDeviceDiscovered( | 596 void DialServiceImpl::NotifyOnDeviceDiscovered( |
572 const DialDeviceData& device_data) { | 597 const DialDeviceData& device_data) { |
573 DCHECK(thread_checker_.CalledOnValidThread()); | 598 DCHECK(thread_checker_.CalledOnValidThread()); |
574 if (!discovery_active_) { | 599 if (!discovery_active_) { |
575 VLOG(2) << "Got response after discovery finished. Ignoring."; | 600 VLOG(2) << "Got response after discovery finished. Ignoring."; |
576 return; | 601 return; |
577 } | 602 } |
578 FOR_EACH_OBSERVER(Observer, observer_list_, | 603 FOR_EACH_OBSERVER(Observer, observer_list_, |
579 OnDeviceDiscovered(this, device_data)); | 604 OnDeviceDiscovered(this, device_data)); |
580 } | 605 } |
581 | 606 |
582 void DialServiceImpl::NotifyOnError() { | 607 void DialServiceImpl::NotifyOnError() { |
583 DCHECK(thread_checker_.CalledOnValidThread()); | 608 DCHECK(thread_checker_.CalledOnValidThread()); |
| 609 // TODO(imcheng): Modify upstream so that the device list is not cleared |
| 610 // when it could still potentially discover devices on other sockets. |
584 FOR_EACH_OBSERVER(Observer, observer_list_, | 611 FOR_EACH_OBSERVER(Observer, observer_list_, |
585 OnError(this, DIAL_SERVICE_SOCKET_ERROR)); | 612 OnError(this, |
| 613 HasOpenSockets() ? DIAL_SERVICE_SOCKET_ERROR |
| 614 : DIAL_SERVICE_NO_INTERFACES)); |
586 } | 615 } |
587 | 616 |
588 void DialServiceImpl::FinishDiscovery() { | 617 void DialServiceImpl::FinishDiscovery() { |
589 DCHECK(thread_checker_.CalledOnValidThread()); | 618 DCHECK(thread_checker_.CalledOnValidThread()); |
590 DCHECK(discovery_active_); | 619 DCHECK(discovery_active_); |
591 VLOG(2) << "Discovery finished."; | 620 VLOG(2) << "Discovery finished."; |
592 // Close all open sockets. | 621 // Close all open sockets. |
593 dial_sockets_.clear(); | 622 dial_sockets_.clear(); |
594 finish_timer_.Stop(); | 623 finish_timer_.Stop(); |
595 request_timer_.Stop(); | 624 request_timer_.Stop(); |
596 discovery_active_ = false; | 625 discovery_active_ = false; |
597 num_requests_sent_ = 0; | 626 num_requests_sent_ = 0; |
598 FOR_EACH_OBSERVER(Observer, observer_list_, OnDiscoveryFinished(this)); | 627 FOR_EACH_OBSERVER(Observer, observer_list_, OnDiscoveryFinished(this)); |
599 } | 628 } |
600 | 629 |
601 bool DialServiceImpl::HasOpenSockets() { | 630 bool DialServiceImpl::HasOpenSockets() { |
602 for (ScopedVector<DialSocket>::const_iterator iter = dial_sockets_.begin(); | 631 for (ScopedVector<DialSocket>::const_iterator iter = dial_sockets_.begin(); |
603 iter != dial_sockets_.end(); | 632 iter != dial_sockets_.end(); |
604 ++iter) { | 633 ++iter) { |
605 if (!((*iter)->IsClosed())) | 634 if (!((*iter)->IsClosed())) |
606 return true; | 635 return true; |
607 } | 636 } |
608 return false; | 637 return false; |
609 } | 638 } |
610 | 639 |
611 } // namespace extensions | 640 } // namespace extensions |
OLD | NEW |