Chromium Code Reviews| 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 "net/base/address_tracker_linux.h" | 5 #include "net/base/address_tracker_linux.h" |
| 6 | 6 |
| 7 #include <errno.h> | 7 #include <errno.h> |
| 8 #include <linux/if.h> | 8 #include <linux/if.h> |
| 9 #include <linux/wireless.h> | |
| 9 #include <sys/ioctl.h> | 10 #include <sys/ioctl.h> |
| 10 | 11 |
| 11 #include "base/logging.h" | 12 #include "base/logging.h" |
| 12 #include "base/posix/eintr_wrapper.h" | 13 #include "base/posix/eintr_wrapper.h" |
| 13 #include "base/threading/thread_restrictions.h" | 14 #include "base/threading/thread_restrictions.h" |
| 15 #include "net/base/ip_endpoint.h" | |
| 16 #include "net/base/net_util_linux.h" | |
| 17 #include "net/base/net_util_posix.h" | |
| 14 | 18 |
| 15 namespace net { | 19 namespace net { |
| 16 namespace internal { | 20 namespace internal { |
| 17 | 21 |
| 18 namespace { | 22 namespace { |
| 19 | 23 |
| 24 // Gets the connection type for interface |ifname| by checking for wireless | |
| 25 // extensions. It is assumed for linux that if there are no extensions that | |
| 26 // the device is ethernet. | |
| 27 NetworkChangeNotifier::ConnectionType | |
| 28 GetInterfaceConnectionType(std::string ifname) { | |
| 29 NetworkChangeNotifier::ConnectionType type = | |
| 30 NetworkChangeNotifier::CONNECTION_UNKNOWN; | |
| 31 | |
| 32 int s = socket(AF_INET, SOCK_STREAM, 0); | |
| 33 if (s == -1) { | |
| 34 return type; | |
| 35 } | |
| 36 | |
| 37 struct iwreq pwrq; | |
| 38 memset(&pwrq, 0, sizeof(pwrq)); | |
| 39 strncpy(pwrq.ifr_name, ifname.c_str(), IFNAMSIZ); | |
| 40 | |
| 41 if (ioctl(s, SIOCGIWNAME, &pwrq) != -1) { | |
| 42 type = NetworkChangeNotifier::CONNECTION_WIFI; | |
| 43 } | |
|
pauljensen
2014/11/21 18:55:36
extra line break
derekjchow1
2014/11/21 23:13:58
Done.
| |
| 44 else { | |
| 45 type = NetworkChangeNotifier::CONNECTION_ETHERNET; | |
|
pauljensen
2014/11/21 18:55:36
We should be defaulting to UNKNOWN not ETHERNET.
derekjchow1
2014/11/21 23:13:58
I'm looking to use NetworkChangeNotifierLinux in a
pauljensen
2014/11/24 12:33:18
I don't think this works. I believe on Chromebook
| |
| 46 } | |
| 47 close(s); | |
| 48 return type; | |
| 49 } | |
| 50 | |
| 20 // Retrieves address from NETLINK address message. | 51 // Retrieves address from NETLINK address message. |
| 21 // Sets |really_deprecated| for IPv6 addresses with preferred lifetimes of 0. | 52 // Sets |really_deprecated| for IPv6 addresses with preferred lifetimes of 0. |
| 22 bool GetAddress(const struct nlmsghdr* header, | 53 bool GetAddress(const struct nlmsghdr* header, |
| 23 IPAddressNumber* out, | 54 IPAddressNumber* out, |
| 24 bool* really_deprecated) { | 55 bool* really_deprecated) { |
| 25 if (really_deprecated) | 56 if (really_deprecated) |
| 26 *really_deprecated = false; | 57 *really_deprecated = false; |
| 27 const struct ifaddrmsg* msg = | 58 const struct ifaddrmsg* msg = |
| 28 reinterpret_cast<struct ifaddrmsg*>(NLMSG_DATA(header)); | 59 reinterpret_cast<struct ifaddrmsg*>(NLMSG_DATA(header)); |
| 29 size_t address_length = 0; | 60 size_t address_length = 0; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 70 } | 101 } |
| 71 if (local) | 102 if (local) |
| 72 address = local; | 103 address = local; |
| 73 if (!address) | 104 if (!address) |
| 74 return false; | 105 return false; |
| 75 out->assign(address, address + address_length); | 106 out->assign(address, address + address_length); |
| 76 return true; | 107 return true; |
| 77 } | 108 } |
| 78 | 109 |
| 79 // Returns the name for the interface with interface index |interface_index|. | 110 // Returns the name for the interface with interface index |interface_index|. |
| 80 // The return value points to a function-scoped static so it may be changed by | 111 // |buf| should be a pointer to an array of size IFNAMSIZ. This function acts |
| 81 // subsequent calls. This function could be replaced with if_indextoname() but | 112 // behaves as if_indextoname which cannot be used as net/if.h cannot be mixed |
| 82 // net/if.h cannot be mixed with linux/if.h so we'll stick with exclusively | 113 // with linux/if.h. We'll stick with exclusively talking to the kernel and |
| 83 // talking to the kernel and not the C library. | 114 // not the C library. |
| 84 const char* GetInterfaceName(int interface_index) { | 115 char* GetInterfaceName(unsigned int interface_index, char* buf) { |
| 85 int ioctl_socket = socket(AF_INET, SOCK_DGRAM, 0); | 116 int ioctl_socket = socket(AF_INET, SOCK_DGRAM, 0); |
| 86 if (ioctl_socket < 0) | 117 if (ioctl_socket < 0) { |
| 87 return ""; | 118 strncpy(buf, "", IFNAMSIZ); |
| 119 return buf; | |
| 120 } | |
| 88 static struct ifreq ifr; | 121 static struct ifreq ifr; |
| 89 memset(&ifr, 0, sizeof(ifr)); | 122 memset(&ifr, 0, sizeof(ifr)); |
| 90 ifr.ifr_ifindex = interface_index; | 123 ifr.ifr_ifindex = interface_index; |
| 91 int rv = ioctl(ioctl_socket, SIOCGIFNAME, &ifr); | 124 int rv = ioctl(ioctl_socket, SIOCGIFNAME, &ifr); |
| 92 close(ioctl_socket); | 125 close(ioctl_socket); |
| 93 if (rv != 0) | 126 if (rv != 0) { |
| 94 return ""; | 127 strncpy(buf, "", IFNAMSIZ); |
| 95 return ifr.ifr_name; | 128 return buf; |
| 129 } | |
| 130 strncpy(buf, ifr.ifr_name, IFNAMSIZ); | |
| 131 return buf; | |
| 96 } | 132 } |
| 97 | 133 |
| 98 } // namespace | 134 } // namespace |
| 99 | 135 |
| 100 AddressTrackerLinux::AddressTrackerLinux() | 136 AddressTrackerLinux::AddressTrackerLinux() |
| 101 : get_interface_name_(GetInterfaceName), | 137 : get_interface_name_(GetInterfaceName), |
| 102 address_callback_(base::Bind(&base::DoNothing)), | 138 address_callback_(base::Bind(&base::DoNothing)), |
| 103 link_callback_(base::Bind(&base::DoNothing)), | 139 link_callback_(base::Bind(&base::DoNothing)), |
| 104 tunnel_callback_(base::Bind(&base::DoNothing)), | 140 tunnel_callback_(base::Bind(&base::DoNothing)), |
| 105 netlink_fd_(-1), | 141 netlink_fd_(-1), |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 241 AddressTrackerLinux::GetCurrentConnectionType() { | 277 AddressTrackerLinux::GetCurrentConnectionType() { |
| 242 // http://crbug.com/125097 | 278 // http://crbug.com/125097 |
| 243 base::ThreadRestrictions::ScopedAllowWait allow_wait; | 279 base::ThreadRestrictions::ScopedAllowWait allow_wait; |
| 244 AddressTrackerAutoLock lock(*this, is_offline_lock_); | 280 AddressTrackerAutoLock lock(*this, is_offline_lock_); |
| 245 // Make sure the initial offline state is set before returning. | 281 // Make sure the initial offline state is set before returning. |
| 246 while (!is_offline_initialized_) { | 282 while (!is_offline_initialized_) { |
| 247 is_offline_initialized_cv_.Wait(); | 283 is_offline_initialized_cv_.Wait(); |
| 248 } | 284 } |
| 249 // TODO(droger): Return something more detailed than CONNECTION_UNKNOWN. | 285 // TODO(droger): Return something more detailed than CONNECTION_UNKNOWN. |
| 250 // http://crbug.com/160537 | 286 // http://crbug.com/160537 |
| 251 return is_offline_ ? NetworkChangeNotifier::CONNECTION_NONE : | 287 if (is_offline_) |
| 252 NetworkChangeNotifier::CONNECTION_UNKNOWN; | 288 return NetworkChangeNotifier::CONNECTION_NONE; |
| 289 | |
| 290 std::string primary_if = GetPrimaryNetif(); | |
| 291 if (primary_if.empty()) | |
| 292 return NetworkChangeNotifier::CONNECTION_NONE; | |
| 293 | |
| 294 return GetInterfaceConnectionType(primary_if); | |
|
pauljensen
2014/11/21 18:55:36
You've added lots of code executed while the lock
derekjchow1
2014/11/21 23:13:58
Done.
| |
| 253 } | 295 } |
| 254 | 296 |
| 255 void AddressTrackerLinux::ReadMessages(bool* address_changed, | 297 void AddressTrackerLinux::ReadMessages(bool* address_changed, |
| 256 bool* link_changed, | 298 bool* link_changed, |
| 257 bool* tunnel_changed) { | 299 bool* tunnel_changed) { |
| 258 *address_changed = false; | 300 *address_changed = false; |
| 259 *link_changed = false; | 301 *link_changed = false; |
| 260 *tunnel_changed = false; | 302 *tunnel_changed = false; |
| 261 char buffer[4096]; | 303 char buffer[4096]; |
| 262 bool first_loop = true; | 304 bool first_loop = true; |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 396 void AddressTrackerLinux::OnFileCanWriteWithoutBlocking(int /* fd */) {} | 438 void AddressTrackerLinux::OnFileCanWriteWithoutBlocking(int /* fd */) {} |
| 397 | 439 |
| 398 void AddressTrackerLinux::CloseSocket() { | 440 void AddressTrackerLinux::CloseSocket() { |
| 399 if (netlink_fd_ >= 0 && IGNORE_EINTR(close(netlink_fd_)) < 0) | 441 if (netlink_fd_ >= 0 && IGNORE_EINTR(close(netlink_fd_)) < 0) |
| 400 PLOG(ERROR) << "Could not close NETLINK socket."; | 442 PLOG(ERROR) << "Could not close NETLINK socket."; |
| 401 netlink_fd_ = -1; | 443 netlink_fd_ = -1; |
| 402 } | 444 } |
| 403 | 445 |
| 404 bool AddressTrackerLinux::IsTunnelInterface(const struct ifinfomsg* msg) const { | 446 bool AddressTrackerLinux::IsTunnelInterface(const struct ifinfomsg* msg) const { |
| 405 // Linux kernel drivers/net/tun.c uses "tun" name prefix. | 447 // Linux kernel drivers/net/tun.c uses "tun" name prefix. |
| 406 return strncmp(get_interface_name_(msg->ifi_index), "tun", 3) == 0; | 448 char buf[IFNAMSIZ] = {0}; |
| 449 return strncmp(get_interface_name_(msg->ifi_index, buf), "tun", 3) == 0; | |
| 450 } | |
| 451 | |
| 452 bool AddressTrackerLinux::GetNetworkList(NetworkInterfaceList* networks, | |
| 453 int policy) const { | |
| 454 const base::hash_set<int> online_links = GetOnlineLinks(); | |
| 455 const internal::AddressTrackerLinux::AddressMap address_map | |
| 456 = GetAddressMap(); | |
| 457 | |
| 458 bool success = GetNetworkListImpl(networks, policy, online_links, address_map, | |
| 459 get_interface_name_); | |
| 460 if (success) { | |
| 461 for (size_t i = 0; i < (*networks).size(); ++i) | |
| 462 (*networks)[i].type = GetInterfaceConnectionType((*networks)[i].name); | |
| 463 } | |
| 464 | |
| 465 return success; | |
| 466 } | |
| 467 | |
| 468 std::string AddressTrackerLinux::GetPrimaryNetif() const { | |
| 469 NetworkInterfaceList networks; | |
| 470 if (!GetNetworkList(&networks, 0)) { | |
| 471 LOG(ERROR) << "GetNetworkList failed"; | |
| 472 return ""; | |
| 473 } | |
| 474 | |
| 475 for (size_t i = 0; i < networks.size(); ++i) { | |
| 476 net::AddressFamily family = net::GetAddressFamily(networks[i].address); | |
| 477 | |
| 478 // Skip ignored interfaces. | |
| 479 if (netifs_to_ignore_.find(networks[i].name) != netifs_to_ignore_.end()) | |
| 480 continue; | |
| 481 | |
| 482 // IPv4 address means interface is configured. | |
|
pauljensen
2014/11/21 18:55:36
I don't think an IPv4 address means an interface i
derekjchow1
2014/11/21 23:13:58
Done.
| |
| 483 // IP address is cleared by DHCP when Ethernet cable is unplugged. It may | |
|
pauljensen
2014/11/21 18:55:36
I don't think DHCP clears IP addresses on local in
derekjchow1
2014/11/21 23:13:58
Done.
| |
| 484 // not be true if static IP is used. | |
| 485 if (family != net::ADDRESS_FAMILY_IPV4) | |
| 486 continue; | |
| 487 | |
| 488 return networks[i].name; | |
| 489 } | |
| 490 | |
| 491 return ""; | |
| 492 } | |
| 493 | |
| 494 bool AddressTrackerLinux::AddNetifToIgnore(const std::string& netif_name) { | |
| 495 return netifs_to_ignore_.insert(netif_name).second; | |
| 496 } | |
| 497 | |
| 498 bool AddressTrackerLinux::RemoveNetifToIgnore(const std::string& netif_name) { | |
| 499 return netifs_to_ignore_.erase(netif_name) > 0; | |
| 407 } | 500 } |
| 408 | 501 |
| 409 AddressTrackerLinux::AddressTrackerAutoLock::AddressTrackerAutoLock( | 502 AddressTrackerLinux::AddressTrackerAutoLock::AddressTrackerAutoLock( |
| 410 const AddressTrackerLinux& tracker, | 503 const AddressTrackerLinux& tracker, |
| 411 base::Lock& lock) | 504 base::Lock& lock) |
| 412 : tracker_(tracker), lock_(lock) { | 505 : tracker_(tracker), lock_(lock) { |
| 413 if (tracker_.tracking_) { | 506 if (tracker_.tracking_) { |
| 414 lock_.Acquire(); | 507 lock_.Acquire(); |
| 415 } else { | 508 } else { |
| 416 DCHECK(tracker_.thread_checker_.CalledOnValidThread()); | 509 DCHECK(tracker_.thread_checker_.CalledOnValidThread()); |
| 417 } | 510 } |
| 418 } | 511 } |
| 419 | 512 |
| 420 AddressTrackerLinux::AddressTrackerAutoLock::~AddressTrackerAutoLock() { | 513 AddressTrackerLinux::AddressTrackerAutoLock::~AddressTrackerAutoLock() { |
| 421 if (tracker_.tracking_) { | 514 if (tracker_.tracking_) { |
| 422 lock_.AssertAcquired(); | 515 lock_.AssertAcquired(); |
| 423 lock_.Release(); | 516 lock_.Release(); |
| 424 } | 517 } |
| 425 } | 518 } |
| 426 | 519 |
| 427 } // namespace internal | 520 } // namespace internal |
| 428 } // namespace net | 521 } // namespace net |
| OLD | NEW |