Index: net/base/address_tracker_linux.cc |
diff --git a/net/base/address_tracker_linux.cc b/net/base/address_tracker_linux.cc |
index 27dd2019ab0dffd6392dee105b7ae11ba7b6e138..731bf4f97785ebf45837c35a4fe4033bd4ffffff 100644 |
--- a/net/base/address_tracker_linux.cc |
+++ b/net/base/address_tracker_linux.cc |
@@ -8,9 +8,11 @@ |
#include <linux/if.h> |
#include <sys/ioctl.h> |
+#include "base/files/scoped_file.h" |
#include "base/logging.h" |
#include "base/posix/eintr_wrapper.h" |
#include "base/threading/thread_restrictions.h" |
+#include "net/base/net_util_linux.h" |
namespace net { |
namespace internal { |
@@ -76,26 +78,22 @@ bool GetAddress(const struct nlmsghdr* header, |
return true; |
} |
-// Returns the name for the interface with interface index |interface_index|. |
-// The return value points to a function-scoped static so it may be changed by |
-// subsequent calls. This function could be replaced with if_indextoname() but |
-// net/if.h cannot be mixed with linux/if.h so we'll stick with exclusively |
-// talking to the kernel and not the C library. |
-const char* GetInterfaceName(int interface_index) { |
- int ioctl_socket = socket(AF_INET, SOCK_DGRAM, 0); |
- if (ioctl_socket < 0) |
- return ""; |
- static struct ifreq ifr; |
- memset(&ifr, 0, sizeof(ifr)); |
+} // namespace |
+ |
+// static |
+char* AddressTrackerLinux::GetInterfaceName(int interface_index, char* buf) { |
+ memset(buf, 0, IFNAMSIZ); |
+ base::ScopedFD ioctl_socket(socket(AF_INET, SOCK_DGRAM, 0)); |
+ if (!ioctl_socket.is_valid()) |
+ return buf; |
+ |
+ struct ifreq ifr = {}; |
ifr.ifr_ifindex = interface_index; |
- int rv = ioctl(ioctl_socket, SIOCGIFNAME, &ifr); |
- close(ioctl_socket); |
- if (rv != 0) |
- return ""; |
- return ifr.ifr_name; |
-} |
-} // namespace |
+ if (ioctl(ioctl_socket.get(), SIOCGIFNAME, &ifr) == 0) |
+ strncpy(buf, ifr.ifr_name, IFNAMSIZ - 1); |
+ return buf; |
+} |
AddressTrackerLinux::AddressTrackerLinux() |
: get_interface_name_(GetInterfaceName), |
@@ -103,9 +101,9 @@ AddressTrackerLinux::AddressTrackerLinux() |
link_callback_(base::Bind(&base::DoNothing)), |
tunnel_callback_(base::Bind(&base::DoNothing)), |
netlink_fd_(-1), |
- is_offline_(true), |
- is_offline_initialized_(false), |
- is_offline_initialized_cv_(&is_offline_lock_), |
+ connection_type_initialized_(false), |
+ connection_type_initialized_cv_(&connection_type_lock_), |
+ current_connection_type_(NetworkChangeNotifier::CONNECTION_NONE), |
tracking_(false) { |
} |
@@ -117,9 +115,9 @@ AddressTrackerLinux::AddressTrackerLinux(const base::Closure& address_callback, |
link_callback_(link_callback), |
tunnel_callback_(tunnel_callback), |
netlink_fd_(-1), |
- is_offline_(true), |
- is_offline_initialized_(false), |
- is_offline_initialized_cv_(&is_offline_lock_), |
+ connection_type_initialized_(false), |
+ connection_type_initialized_cv_(&connection_type_lock_), |
+ current_connection_type_(NetworkChangeNotifier::CONNECTION_NONE), |
tracking_(true) { |
DCHECK(!address_callback.is_null()); |
DCHECK(!link_callback.is_null()); |
@@ -203,9 +201,9 @@ void AddressTrackerLinux::Init() { |
// Consume pending message to populate links_online_, but don't notify. |
ReadMessages(&address_changed, &link_changed, &tunnel_changed); |
{ |
- AddressTrackerAutoLock lock(*this, is_offline_lock_); |
- is_offline_initialized_ = true; |
- is_offline_initialized_cv_.Signal(); |
+ AddressTrackerAutoLock lock(*this, connection_type_lock_); |
+ connection_type_initialized_ = true; |
+ connection_type_initialized_cv_.Signal(); |
} |
if (tracking_) { |
@@ -221,10 +219,10 @@ void AddressTrackerLinux::Init() { |
void AddressTrackerLinux::AbortAndForceOnline() { |
CloseSocket(); |
- AddressTrackerAutoLock lock(*this, is_offline_lock_); |
- is_offline_ = false; |
- is_offline_initialized_ = true; |
- is_offline_initialized_cv_.Signal(); |
+ AddressTrackerAutoLock lock(*this, connection_type_lock_); |
+ current_connection_type_ = NetworkChangeNotifier::CONNECTION_UNKNOWN; |
+ connection_type_initialized_ = true; |
+ connection_type_initialized_cv_.Signal(); |
} |
AddressTrackerLinux::AddressMap AddressTrackerLinux::GetAddressMap() const { |
@@ -241,15 +239,12 @@ NetworkChangeNotifier::ConnectionType |
AddressTrackerLinux::GetCurrentConnectionType() { |
// http://crbug.com/125097 |
base::ThreadRestrictions::ScopedAllowWait allow_wait; |
- AddressTrackerAutoLock lock(*this, is_offline_lock_); |
- // Make sure the initial offline state is set before returning. |
- while (!is_offline_initialized_) { |
- is_offline_initialized_cv_.Wait(); |
+ AddressTrackerAutoLock lock(*this, connection_type_lock_); |
+ // Make sure the initial connection type is set before returning. |
+ while (!connection_type_initialized_) { |
+ connection_type_initialized_cv_.Wait(); |
} |
- // TODO(droger): Return something more detailed than CONNECTION_UNKNOWN. |
- // http://crbug.com/160537 |
- return is_offline_ ? NetworkChangeNotifier::CONNECTION_NONE : |
- NetworkChangeNotifier::CONNECTION_UNKNOWN; |
+ return current_connection_type_; |
} |
void AddressTrackerLinux::ReadMessages(bool* address_changed, |
@@ -279,15 +274,8 @@ void AddressTrackerLinux::ReadMessages(bool* address_changed, |
} |
HandleMessage(buffer, rv, address_changed, link_changed, tunnel_changed); |
} |
- if (*link_changed) { |
- bool is_offline; |
- { |
- AddressTrackerAutoLock lock(*this, online_links_lock_); |
- is_offline = online_links_.empty(); |
- } |
- AddressTrackerAutoLock lock(*this, is_offline_lock_); |
- is_offline_ = is_offline; |
- } |
+ if (*link_changed || *address_changed) |
+ UpdateCurrentConnectionType(); |
} |
void AddressTrackerLinux::HandleMessage(char* buffer, |
@@ -351,14 +339,14 @@ void AddressTrackerLinux::HandleMessage(char* buffer, |
AddressTrackerAutoLock lock(*this, online_links_lock_); |
if (online_links_.insert(msg->ifi_index).second) { |
*link_changed = true; |
- if (IsTunnelInterface(msg)) |
+ if (IsTunnelInterface(msg->ifi_index)) |
*tunnel_changed = true; |
} |
} else { |
AddressTrackerAutoLock lock(*this, online_links_lock_); |
if (online_links_.erase(msg->ifi_index)) { |
*link_changed = true; |
- if (IsTunnelInterface(msg)) |
+ if (IsTunnelInterface(msg->ifi_index)) |
*tunnel_changed = true; |
} |
} |
@@ -369,7 +357,7 @@ void AddressTrackerLinux::HandleMessage(char* buffer, |
AddressTrackerAutoLock lock(*this, online_links_lock_); |
if (online_links_.erase(msg->ifi_index)) { |
*link_changed = true; |
- if (IsTunnelInterface(msg)) |
+ if (IsTunnelInterface(msg->ifi_index)) |
*tunnel_changed = true; |
} |
} break; |
@@ -401,9 +389,41 @@ void AddressTrackerLinux::CloseSocket() { |
netlink_fd_ = -1; |
} |
-bool AddressTrackerLinux::IsTunnelInterface(const struct ifinfomsg* msg) const { |
+bool AddressTrackerLinux::IsTunnelInterface(int interface_index) const { |
// Linux kernel drivers/net/tun.c uses "tun" name prefix. |
- return strncmp(get_interface_name_(msg->ifi_index), "tun", 3) == 0; |
+ char buf[IFNAMSIZ] = {0}; |
+ return strncmp(get_interface_name_(interface_index, buf), "tun", 3) == 0; |
+} |
+ |
+void AddressTrackerLinux::UpdateCurrentConnectionType() { |
+ AddressTrackerLinux::AddressMap address_map = GetAddressMap(); |
+ base::hash_set<int> online_links = GetOnlineLinks(); |
+ |
+ // Strip out tunnel interfaces from online_links |
+ for (base::hash_set<int>::const_iterator it = online_links.begin(); |
+ it != online_links.end();) { |
+ if (IsTunnelInterface(*it)) { |
+ base::hash_set<int>::const_iterator tunnel_it = it; |
+ ++it; |
+ online_links.erase(*tunnel_it); |
+ } else { |
+ ++it; |
+ } |
+ } |
+ |
+ NetworkInterfaceList networks; |
+ NetworkChangeNotifier::ConnectionType type = |
+ NetworkChangeNotifier::CONNECTION_NONE; |
+ if (GetNetworkListImpl(&networks, 0, online_links, address_map, |
+ get_interface_name_)) { |
+ type = NetworkChangeNotifier::ConnectionTypeFromInterfaceList(networks); |
+ } else { |
+ type = online_links.empty() ? NetworkChangeNotifier::CONNECTION_NONE |
+ : NetworkChangeNotifier::CONNECTION_UNKNOWN; |
+ } |
+ |
+ AddressTrackerAutoLock lock(*this, connection_type_lock_); |
+ current_connection_type_ = type; |
} |
AddressTrackerLinux::AddressTrackerAutoLock::AddressTrackerAutoLock( |