| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "content/renderer/p2p/ipc_network_manager.h" |
| |
| #include <string> |
| #include "base/bind.h" |
| #include "base/command_line.h" |
| #include "base/location.h" |
| #include "base/metrics/histogram_macros.h" |
| #include "base/single_thread_task_runner.h" |
| #include "base/sys_byteorder.h" |
| #include "base/threading/thread_task_runner_handle.h" |
| #include "content/public/common/content_switches.h" |
| #include "jingle/glue/utils.h" |
| #include "net/base/ip_address.h" |
| #include "net/base/network_change_notifier.h" |
| #include "net/base/network_interfaces.h" |
| #include "third_party/webrtc/base/socketaddress.h" |
| |
| namespace content { |
| |
| namespace { |
| |
| rtc::AdapterType ConvertConnectionTypeToAdapterType( |
| net::NetworkChangeNotifier::ConnectionType type) { |
| switch (type) { |
| case net::NetworkChangeNotifier::CONNECTION_UNKNOWN: |
| return rtc::ADAPTER_TYPE_UNKNOWN; |
| case net::NetworkChangeNotifier::CONNECTION_ETHERNET: |
| return rtc::ADAPTER_TYPE_ETHERNET; |
| case net::NetworkChangeNotifier::CONNECTION_WIFI: |
| return rtc::ADAPTER_TYPE_WIFI; |
| case net::NetworkChangeNotifier::CONNECTION_2G: |
| case net::NetworkChangeNotifier::CONNECTION_3G: |
| case net::NetworkChangeNotifier::CONNECTION_4G: |
| return rtc::ADAPTER_TYPE_CELLULAR; |
| default: |
| return rtc::ADAPTER_TYPE_UNKNOWN; |
| } |
| } |
| |
| } // namespace |
| |
| IpcNetworkManager::IpcNetworkManager(NetworkListManager* network_list_manager) |
| : network_list_manager_(network_list_manager), |
| start_count_(0), |
| network_list_received_(false), |
| weak_factory_(this) { |
| network_list_manager_->AddNetworkListObserver(this); |
| } |
| |
| IpcNetworkManager::~IpcNetworkManager() { |
| DCHECK(!start_count_); |
| network_list_manager_->RemoveNetworkListObserver(this); |
| } |
| |
| void IpcNetworkManager::StartUpdating() { |
| if (network_list_received_) { |
| // Post a task to avoid reentrancy. |
| base::ThreadTaskRunnerHandle::Get()->PostTask( |
| FROM_HERE, base::Bind(&IpcNetworkManager::SendNetworksChangedSignal, |
| weak_factory_.GetWeakPtr())); |
| } |
| ++start_count_; |
| } |
| |
| void IpcNetworkManager::StopUpdating() { |
| DCHECK_GT(start_count_, 0); |
| --start_count_; |
| } |
| |
| void IpcNetworkManager::OnNetworkListChanged( |
| const net::NetworkInterfaceList& list, |
| const net::IPAddress& default_ipv4_local_address, |
| const net::IPAddress& default_ipv6_local_address) { |
| // Update flag if network list received for the first time. |
| if (!network_list_received_) |
| network_list_received_ = true; |
| |
| // Default addresses should be set only when they are in the filtered list of |
| // network addresses. |
| bool use_default_ipv4_address = false; |
| bool use_default_ipv6_address = false; |
| |
| // rtc::Network uses these prefix_length to compare network |
| // interfaces discovered. |
| std::vector<rtc::Network*> networks; |
| for (net::NetworkInterfaceList::const_iterator it = list.begin(); |
| it != list.end(); it++) { |
| rtc::IPAddress ip_address = |
| jingle_glue::NetIPAddressToRtcIPAddress(it->address); |
| DCHECK(!ip_address.IsNil()); |
| |
| rtc::IPAddress prefix = rtc::TruncateIP(ip_address, it->prefix_length); |
| std::unique_ptr<rtc::Network> network( |
| new rtc::Network(it->name, it->name, prefix, it->prefix_length, |
| ConvertConnectionTypeToAdapterType(it->type))); |
| network->set_default_local_address_provider(this); |
| |
| rtc::InterfaceAddress iface_addr; |
| if (it->address.IsIPv4()) { |
| use_default_ipv4_address |= (default_ipv4_local_address == it->address); |
| iface_addr = rtc::InterfaceAddress(ip_address); |
| } else { |
| DCHECK(it->address.IsIPv6()); |
| iface_addr = rtc::InterfaceAddress(ip_address, it->ip_address_attributes); |
| |
| // Only allow non-private, non-deprecated IPv6 addresses which don't |
| // contain MAC. |
| if (rtc::IPIsMacBased(iface_addr) || |
| (it->ip_address_attributes & net::IP_ADDRESS_ATTRIBUTE_DEPRECATED) || |
| rtc::IPIsPrivate(iface_addr)) { |
| continue; |
| } |
| |
| use_default_ipv6_address |= (default_ipv6_local_address == it->address); |
| } |
| network->AddIP(iface_addr); |
| networks.push_back(network.release()); |
| } |
| |
| // Update the default local addresses. |
| rtc::IPAddress ipv4_default; |
| rtc::IPAddress ipv6_default; |
| if (use_default_ipv4_address) { |
| ipv4_default = |
| jingle_glue::NetIPAddressToRtcIPAddress(default_ipv4_local_address); |
| } |
| if (use_default_ipv6_address) { |
| ipv6_default = |
| jingle_glue::NetIPAddressToRtcIPAddress(default_ipv6_local_address); |
| } |
| set_default_local_addresses(ipv4_default, ipv6_default); |
| |
| if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
| switches::kAllowLoopbackInPeerConnection)) { |
| std::string name_v4("loopback_ipv4"); |
| rtc::IPAddress ip_address_v4(INADDR_LOOPBACK); |
| rtc::Network* network_v4 = new rtc::Network( |
| name_v4, name_v4, ip_address_v4, 32, rtc::ADAPTER_TYPE_UNKNOWN); |
| network_v4->set_default_local_address_provider(this); |
| network_v4->AddIP(ip_address_v4); |
| networks.push_back(network_v4); |
| |
| rtc::IPAddress ipv6_default_address; |
| // Only add IPv6 loopback if we can get default local address for IPv6. If |
| // we can't, it means that we don't have IPv6 enabled on this machine and |
| // bind() to the IPv6 loopback address will fail. |
| if (GetDefaultLocalAddress(AF_INET6, &ipv6_default_address)) { |
| DCHECK(!ipv6_default_address.IsNil()); |
| std::string name_v6("loopback_ipv6"); |
| rtc::IPAddress ip_address_v6(in6addr_loopback); |
| rtc::Network* network_v6 = new rtc::Network( |
| name_v6, name_v6, ip_address_v6, 64, rtc::ADAPTER_TYPE_UNKNOWN); |
| network_v6->set_default_local_address_provider(this); |
| network_v6->AddIP(ip_address_v6); |
| networks.push_back(network_v6); |
| } |
| } |
| |
| bool changed = false; |
| NetworkManager::Stats stats; |
| MergeNetworkList(networks, &changed, &stats); |
| if (changed) |
| SignalNetworksChanged(); |
| |
| // Send interface counts to UMA. |
| UMA_HISTOGRAM_COUNTS_100("WebRTC.PeerConnection.IPv4Interfaces", |
| stats.ipv4_network_count); |
| UMA_HISTOGRAM_COUNTS_100("WebRTC.PeerConnection.IPv6Interfaces", |
| stats.ipv6_network_count); |
| } |
| |
| void IpcNetworkManager::SendNetworksChangedSignal() { |
| SignalNetworksChanged(); |
| } |
| |
| } // namespace content |