diff options
-rw-r--r-- | chrome/browser/extensions/api/dial/dial_service.cc | 93 | ||||
-rw-r--r-- | chrome/browser/extensions/api/dial/dial_service.h | 5 | ||||
-rw-r--r-- | chrome/browser/extensions/api/dial/dial_service_unittest.cc | 2 |
3 files changed, 92 insertions, 8 deletions
diff --git a/chrome/browser/extensions/api/dial/dial_service.cc b/chrome/browser/extensions/api/dial/dial_service.cc index 75c6aee..2caf51c 100644 --- a/chrome/browser/extensions/api/dial/dial_service.cc +++ b/chrome/browser/extensions/api/dial/dial_service.cc @@ -91,19 +91,64 @@ std::string BuildRequest() { "MAN:\"ssdp:discover\"\r\n" "MX:%d\r\n" "ST:%s\r\n" - "USER-AGENT:%s %s\r\n" + "USER-AGENT:%s/%s %s\r\n" "\r\n", kDialRequestAddress, kDialRequestPort, kDialResponseTimeoutSecs, kDialSearchType, - version.ProductNameAndVersionForUserAgent().c_str(), + version.Name().c_str(), + version.Version().c_str(), version.OSType().c_str())); // 1500 is a good MTU value for most Ethernet LANs. DCHECK(request.size() <= 1500); return request; } +void GetNetworkListOnFileThread( + const scoped_refptr<base::MessageLoopProxy>& loop, + const base::Callback<void(const NetworkInterfaceList& networks)>& cb) { + NetworkInterfaceList list; + bool success = net::GetNetworkList(&list); + if (!success) + DVLOG(1) << "Could not retrieve network list!"; + + loop->PostTask(FROM_HERE, base::Bind(cb, list)); +} + +#if defined(OS_CHROMEOS) +IPAddressNumber GetBestBindAddressByType( + const chromeos::NetworkTypePattern& type) { + const chromeos::NetworkState* state = chromeos::NetworkHandler::Get() + ->network_state_handler()->ConnectedNetworkByType(type); + IPAddressNumber bind_ip_address; + if (!state || + !net::ParseIPLiteralToNumber(state->ip_address(), &bind_ip_address)) { + return IPAddressNumber(); + } + if (bind_ip_address.size() != net::kIPv4AddressSize) { + LOG(ERROR) << "Default network is not using IPv4."; + return IPAddressNumber(); + } + + DVLOG(1) << "Found " << state->type() << ", " << state->name() << ":" + << state->ip_address(); + return bind_ip_address; +} + +// Returns the IP address of the preferred interface to bind the socket. This +// ChromeOS version can prioritize wifi and ethernet interfaces. +IPAddressNumber GetBestBindAddressChromeOS() { + IPAddressNumber bind_ip_address = + GetBestBindAddressByType(chromeos::NetworkTypePattern::Ethernet()); + if (bind_ip_address.empty()) { + bind_ip_address = + GetBestBindAddressByType(chromeos::NetworkTypePattern::WiFi()); + } + return bind_ip_address; +} +#endif + } // namespace DialServiceImpl::DialServiceImpl(net::NetLog* net_log) @@ -163,20 +208,36 @@ void DialServiceImpl::StartDiscovery() { if (socket_.get()) return; - BindSocketAndSendRequest(); +#if defined(OS_CHROMEOS) + // The ChromeOS specific version of getting network interfaces does not + // require trampolining to another thread, and contains additional interface + // information such as interface types (i.e. wifi vs cellular). + BindSocketAndSendRequest(GetBestBindAddressChromeOS()); +#else + BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind( + &GetNetworkListOnFileThread, + base::MessageLoopProxy::current(), base::Bind( + &DialServiceImpl::SendNetworkList, AsWeakPtr()))); +#endif } -bool DialServiceImpl::BindSocketAndSendRequest() { +bool DialServiceImpl::BindSocketAndSendRequest( + const IPAddressNumber& bind_ip_address) { DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(!socket_.get()); + if (bind_ip_address.size() == 0) { + DVLOG(1) << "Could not find a valid interface to bind."; + FinishDiscovery(); + return false; + } + net::RandIntCallback rand_cb = base::Bind(&base::RandInt); socket_.reset(new UDPSocket(net::DatagramSocket::RANDOM_BIND, rand_cb, net_log_, net_log_source_)); socket_->AllowBroadcast(); - socket_->AllowAddressReuse(); // Schedule a timer to finish the discovery process (and close the socket). if (finish_delay_ > TimeDelta::FromSeconds(0)) { @@ -187,7 +248,7 @@ bool DialServiceImpl::BindSocketAndSendRequest() { } // 0 means bind a random port - IPEndPoint address(IPAddressNumber(net::kIPv4AddressSize), 0); + IPEndPoint address(bind_ip_address, 0); if (!CheckResult("Bind", socket_->Bind(address))) return false; @@ -381,6 +442,26 @@ bool DialServiceImpl::ParseResponse(const std::string& response, return true; } +void DialServiceImpl::SendNetworkList(const NetworkInterfaceList& networks) { + DCHECK(thread_checker_.CalledOnValidThread()); + IPAddressNumber bind_ip_address; + // Returns the first IPv4 address found. If there is a need for discovery + // across multiple networks, we could manage multiple sockets. + + // TODO(mfoltz): Support IPV6 multicast. http://crbug.com/165286 + for (NetworkInterfaceList::const_iterator iter = networks.begin(); + iter != networks.end(); ++iter) { + DVLOG(1) << "Found " << iter->name << ", " + << net::IPAddressToString(iter->address); + if (iter->address.size() == net::kIPv4AddressSize) { + bind_ip_address = (*iter).address; + break; + } + } + + BindSocketAndSendRequest(bind_ip_address); +} + void DialServiceImpl::FinishDiscovery() { DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(discovery_active_); diff --git a/chrome/browser/extensions/api/dial/dial_service.h b/chrome/browser/extensions/api/dial/dial_service.h index 830d3fa..5c0dc0d 100644 --- a/chrome/browser/extensions/api/dial/dial_service.h +++ b/chrome/browser/extensions/api/dial/dial_service.h @@ -116,7 +116,7 @@ class DialServiceImpl : public DialService, // Establishes the UDP socket that is used for requests and responses, // establishes a read callback on the socket, and sends the first discovery // request. Returns true if successful. - bool BindSocketAndSendRequest(); + bool BindSocketAndSendRequest(const net::IPAddressNumber& bind_ip_address); // Sends a single discovery request over the socket. void SendOneRequest(); @@ -124,6 +124,9 @@ class DialServiceImpl : public DialService, // Callback invoked for socket writes. void OnSocketWrite(int result); + // Send the network list to IO thread. + void SendNetworkList(const net::NetworkInterfaceList& list); + // Establishes the callback to read from the socket. Returns true if // successful. bool ReadSocket(); diff --git a/chrome/browser/extensions/api/dial/dial_service_unittest.cc b/chrome/browser/extensions/api/dial/dial_service_unittest.cc index 8d80753..4a23d93 100644 --- a/chrome/browser/extensions/api/dial/dial_service_unittest.cc +++ b/chrome/browser/extensions/api/dial/dial_service_unittest.cc @@ -62,7 +62,7 @@ TEST_F(DialServiceTest, TestSendMultipleRequests) { dial_service_.discovery_active_ = true; EXPECT_CALL(mock_observer_, OnDiscoveryRequest(A<DialService*>())).Times(4); EXPECT_CALL(mock_observer_, OnDiscoveryFinished(A<DialService*>())).Times(1); - dial_service_.BindSocketAndSendRequest(); + dial_service_.BindSocketAndSendRequest(mock_ip_); loop.RunUntilIdle(); dial_service_.FinishDiscovery(); } |