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/files/scoped_file.h" | 12 #include "base/files/scoped_file.h" |
12 #include "base/logging.h" | 13 #include "base/logging.h" |
13 #include "base/posix/eintr_wrapper.h" | 14 #include "base/posix/eintr_wrapper.h" |
14 #include "base/threading/thread_restrictions.h" | 15 #include "base/threading/thread_restrictions.h" |
15 #include "net/base/net_util_linux.h" | 16 #include "net/base/net_util_linux.h" |
16 | 17 |
17 namespace net { | 18 namespace net { |
18 namespace internal { | 19 namespace internal { |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
71 } | 72 } |
72 } | 73 } |
73 if (local) | 74 if (local) |
74 address = local; | 75 address = local; |
75 if (!address) | 76 if (!address) |
76 return false; | 77 return false; |
77 out->assign(address, address + address_length); | 78 out->assign(address, address + address_length); |
78 return true; | 79 return true; |
79 } | 80 } |
80 | 81 |
| 82 std::string GetInterfaceSSID(const std::string& ifname) { |
| 83 int ioctl_socket = socket(AF_INET, SOCK_DGRAM, 0); |
| 84 if (ioctl_socket < 0) |
| 85 return ""; |
| 86 struct iwreq wreq; |
| 87 memset(&wreq, 0, sizeof(wreq)); |
| 88 strncpy(wreq.ifr_name, ifname.c_str(), IFNAMSIZ - 1); |
| 89 |
| 90 char ssid[IW_ESSID_MAX_SIZE + 1] = {0}; |
| 91 wreq.u.essid.pointer = ssid; |
| 92 wreq.u.essid.length = IW_ESSID_MAX_SIZE; |
| 93 int rv = ioctl(ioctl_socket, SIOCGIWESSID, &wreq); |
| 94 close(ioctl_socket); |
| 95 return (rv == 0) ? ssid : ""; |
| 96 } |
| 97 |
81 } // namespace | 98 } // namespace |
82 | 99 |
83 // static | 100 // static |
84 char* AddressTrackerLinux::GetInterfaceName(int interface_index, char* buf) { | 101 char* AddressTrackerLinux::GetInterfaceName(int interface_index, char* buf) { |
85 memset(buf, 0, IFNAMSIZ); | 102 memset(buf, 0, IFNAMSIZ); |
86 base::ScopedFD ioctl_socket(socket(AF_INET, SOCK_DGRAM, 0)); | 103 base::ScopedFD ioctl_socket(socket(AF_INET, SOCK_DGRAM, 0)); |
87 if (!ioctl_socket.is_valid()) | 104 if (!ioctl_socket.is_valid()) |
88 return buf; | 105 return buf; |
89 | 106 |
90 struct ifreq ifr = {}; | 107 struct ifreq ifr = {}; |
91 ifr.ifr_ifindex = interface_index; | 108 ifr.ifr_ifindex = interface_index; |
92 | 109 |
93 if (ioctl(ioctl_socket.get(), SIOCGIFNAME, &ifr) == 0) | 110 if (ioctl(ioctl_socket.get(), SIOCGIFNAME, &ifr) == 0) |
94 strncpy(buf, ifr.ifr_name, IFNAMSIZ - 1); | 111 strncpy(buf, ifr.ifr_name, IFNAMSIZ - 1); |
95 return buf; | 112 return buf; |
96 } | 113 } |
97 | 114 |
| 115 // static |
| 116 std::string AddressTrackerLinux::ConnectionSSIDFromInterfaceList( |
| 117 const NetworkInterfaceList& interfaces, |
| 118 GetInterfaceSSIDFunction get_interface_ssid) { |
| 119 std::string connected_ssid; |
| 120 bool first = true; |
| 121 for (size_t i = 0; i < interfaces.size(); ++i) { |
| 122 if (interfaces[i].type != NetworkChangeNotifier::CONNECTION_WIFI) |
| 123 return ""; |
| 124 std::string ssid = get_interface_ssid(interfaces[i].name); |
| 125 if (first) { |
| 126 first = false; |
| 127 connected_ssid = ssid; |
| 128 } else if (ssid != connected_ssid) { |
| 129 return ""; |
| 130 } |
| 131 } |
| 132 return connected_ssid; |
| 133 } |
| 134 |
98 AddressTrackerLinux::AddressTrackerLinux() | 135 AddressTrackerLinux::AddressTrackerLinux() |
99 : get_interface_name_(GetInterfaceName), | 136 : get_interface_name_(GetInterfaceName), |
100 address_callback_(base::Bind(&base::DoNothing)), | 137 address_callback_(base::Bind(&base::DoNothing)), |
101 link_callback_(base::Bind(&base::DoNothing)), | 138 link_callback_(base::Bind(&base::DoNothing)), |
102 tunnel_callback_(base::Bind(&base::DoNothing)), | 139 tunnel_callback_(base::Bind(&base::DoNothing)), |
103 netlink_fd_(-1), | 140 netlink_fd_(-1), |
104 connection_type_initialized_(false), | 141 connection_type_initialized_(false), |
105 connection_type_initialized_cv_(&connection_type_lock_), | 142 connection_type_initialized_cv_(&connection_type_lock_), |
106 current_connection_type_(NetworkChangeNotifier::CONNECTION_NONE), | 143 current_connection_type_(NetworkChangeNotifier::CONNECTION_NONE), |
107 tracking_(false) { | 144 tracking_(false) { |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
216 } | 253 } |
217 } | 254 } |
218 } | 255 } |
219 | 256 |
220 void AddressTrackerLinux::AbortAndForceOnline() { | 257 void AddressTrackerLinux::AbortAndForceOnline() { |
221 CloseSocket(); | 258 CloseSocket(); |
222 AddressTrackerAutoLock lock(*this, connection_type_lock_); | 259 AddressTrackerAutoLock lock(*this, connection_type_lock_); |
223 current_connection_type_ = NetworkChangeNotifier::CONNECTION_UNKNOWN; | 260 current_connection_type_ = NetworkChangeNotifier::CONNECTION_UNKNOWN; |
224 connection_type_initialized_ = true; | 261 connection_type_initialized_ = true; |
225 connection_type_initialized_cv_.Signal(); | 262 connection_type_initialized_cv_.Signal(); |
| 263 current_wifi_ssid_ = ""; |
226 } | 264 } |
227 | 265 |
228 AddressTrackerLinux::AddressMap AddressTrackerLinux::GetAddressMap() const { | 266 AddressTrackerLinux::AddressMap AddressTrackerLinux::GetAddressMap() const { |
229 AddressTrackerAutoLock lock(*this, address_map_lock_); | 267 AddressTrackerAutoLock lock(*this, address_map_lock_); |
230 return address_map_; | 268 return address_map_; |
231 } | 269 } |
232 | 270 |
233 base::hash_set<int> AddressTrackerLinux::GetOnlineLinks() const { | 271 base::hash_set<int> AddressTrackerLinux::GetOnlineLinks() const { |
234 AddressTrackerAutoLock lock(*this, online_links_lock_); | 272 AddressTrackerAutoLock lock(*this, online_links_lock_); |
235 return online_links_; | 273 return online_links_; |
236 } | 274 } |
237 | 275 |
238 NetworkChangeNotifier::ConnectionType | 276 NetworkChangeNotifier::ConnectionType |
239 AddressTrackerLinux::GetCurrentConnectionType() { | 277 AddressTrackerLinux::GetCurrentConnectionType() { |
240 // http://crbug.com/125097 | 278 // http://crbug.com/125097 |
241 base::ThreadRestrictions::ScopedAllowWait allow_wait; | 279 base::ThreadRestrictions::ScopedAllowWait allow_wait; |
242 AddressTrackerAutoLock lock(*this, connection_type_lock_); | 280 AddressTrackerAutoLock lock(*this, connection_type_lock_); |
243 // Make sure the initial connection type is set before returning. | 281 // Make sure the initial connection type is set before returning. |
244 while (!connection_type_initialized_) { | 282 while (!connection_type_initialized_) { |
245 connection_type_initialized_cv_.Wait(); | 283 connection_type_initialized_cv_.Wait(); |
246 } | 284 } |
247 return current_connection_type_; | 285 return current_connection_type_; |
248 } | 286 } |
249 | 287 |
| 288 std::string AddressTrackerLinux::GetCurrentWiFiSSID() { |
| 289 // Don't wait for initialization, return an empty SSID if not initialized. |
| 290 AddressTrackerAutoLock lock(*this, wifi_ssid_lock_); |
| 291 return current_wifi_ssid_; |
| 292 } |
| 293 |
250 void AddressTrackerLinux::ReadMessages(bool* address_changed, | 294 void AddressTrackerLinux::ReadMessages(bool* address_changed, |
251 bool* link_changed, | 295 bool* link_changed, |
252 bool* tunnel_changed) { | 296 bool* tunnel_changed) { |
253 *address_changed = false; | 297 *address_changed = false; |
254 *link_changed = false; | 298 *link_changed = false; |
255 *tunnel_changed = false; | 299 *tunnel_changed = false; |
256 char buffer[4096]; | 300 char buffer[4096]; |
257 bool first_loop = true; | 301 bool first_loop = true; |
258 for (;;) { | 302 for (;;) { |
259 int rv = HANDLE_EINTR(recv(netlink_fd_, | 303 int rv = HANDLE_EINTR(recv(netlink_fd_, |
260 buffer, | 304 buffer, |
261 sizeof(buffer), | 305 sizeof(buffer), |
262 // Block the first time through loop. | 306 // Block the first time through loop. |
263 first_loop ? 0 : MSG_DONTWAIT)); | 307 first_loop ? 0 : MSG_DONTWAIT)); |
264 first_loop = false; | 308 first_loop = false; |
265 if (rv == 0) { | 309 if (rv == 0) { |
266 LOG(ERROR) << "Unexpected shutdown of NETLINK socket."; | 310 LOG(ERROR) << "Unexpected shutdown of NETLINK socket."; |
267 return; | 311 return; |
268 } | 312 } |
269 if (rv < 0) { | 313 if (rv < 0) { |
270 if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) | 314 if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) |
271 break; | 315 break; |
272 PLOG(ERROR) << "Failed to recv from netlink socket"; | 316 PLOG(ERROR) << "Failed to recv from netlink socket"; |
273 return; | 317 return; |
274 } | 318 } |
275 HandleMessage(buffer, rv, address_changed, link_changed, tunnel_changed); | 319 HandleMessage(buffer, rv, address_changed, link_changed, tunnel_changed); |
276 } | 320 } |
277 if (*link_changed || *address_changed) | 321 if (*link_changed || *address_changed) |
278 UpdateCurrentConnectionType(); | 322 UpdateCurrentConnectionTypeAndSSID(); |
279 } | 323 } |
280 | 324 |
281 void AddressTrackerLinux::HandleMessage(char* buffer, | 325 void AddressTrackerLinux::HandleMessage(char* buffer, |
282 size_t length, | 326 size_t length, |
283 bool* address_changed, | 327 bool* address_changed, |
284 bool* link_changed, | 328 bool* link_changed, |
285 bool* tunnel_changed) { | 329 bool* tunnel_changed) { |
286 DCHECK(buffer); | 330 DCHECK(buffer); |
287 for (struct nlmsghdr* header = reinterpret_cast<struct nlmsghdr*>(buffer); | 331 for (struct nlmsghdr* header = reinterpret_cast<struct nlmsghdr*>(buffer); |
288 NLMSG_OK(header, length); | 332 NLMSG_OK(header, length); |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
388 PLOG(ERROR) << "Could not close NETLINK socket."; | 432 PLOG(ERROR) << "Could not close NETLINK socket."; |
389 netlink_fd_ = -1; | 433 netlink_fd_ = -1; |
390 } | 434 } |
391 | 435 |
392 bool AddressTrackerLinux::IsTunnelInterface(int interface_index) const { | 436 bool AddressTrackerLinux::IsTunnelInterface(int interface_index) const { |
393 // Linux kernel drivers/net/tun.c uses "tun" name prefix. | 437 // Linux kernel drivers/net/tun.c uses "tun" name prefix. |
394 char buf[IFNAMSIZ] = {0}; | 438 char buf[IFNAMSIZ] = {0}; |
395 return strncmp(get_interface_name_(interface_index, buf), "tun", 3) == 0; | 439 return strncmp(get_interface_name_(interface_index, buf), "tun", 3) == 0; |
396 } | 440 } |
397 | 441 |
398 void AddressTrackerLinux::UpdateCurrentConnectionType() { | 442 void AddressTrackerLinux::UpdateCurrentConnectionTypeAndSSID() { |
399 AddressTrackerLinux::AddressMap address_map = GetAddressMap(); | 443 AddressTrackerLinux::AddressMap address_map = GetAddressMap(); |
400 base::hash_set<int> online_links = GetOnlineLinks(); | 444 base::hash_set<int> online_links = GetOnlineLinks(); |
401 | 445 |
402 // Strip out tunnel interfaces from online_links | 446 // Strip out tunnel interfaces from online_links |
403 for (base::hash_set<int>::const_iterator it = online_links.begin(); | 447 for (base::hash_set<int>::const_iterator it = online_links.begin(); |
404 it != online_links.end();) { | 448 it != online_links.end();) { |
405 if (IsTunnelInterface(*it)) { | 449 if (IsTunnelInterface(*it)) { |
406 base::hash_set<int>::const_iterator tunnel_it = it; | 450 base::hash_set<int>::const_iterator tunnel_it = it; |
407 ++it; | 451 ++it; |
408 online_links.erase(*tunnel_it); | 452 online_links.erase(*tunnel_it); |
409 } else { | 453 } else { |
410 ++it; | 454 ++it; |
411 } | 455 } |
412 } | 456 } |
413 | 457 |
414 NetworkInterfaceList networks; | 458 NetworkInterfaceList networks; |
415 NetworkChangeNotifier::ConnectionType type = | 459 NetworkChangeNotifier::ConnectionType type = |
416 NetworkChangeNotifier::CONNECTION_NONE; | 460 NetworkChangeNotifier::CONNECTION_NONE; |
| 461 std::string ssid; |
417 if (GetNetworkListImpl(&networks, 0, online_links, address_map, | 462 if (GetNetworkListImpl(&networks, 0, online_links, address_map, |
418 get_interface_name_)) { | 463 get_interface_name_)) { |
419 type = NetworkChangeNotifier::ConnectionTypeFromInterfaceList(networks); | 464 type = NetworkChangeNotifier::ConnectionTypeFromInterfaceList(networks); |
| 465 ssid = ConnectionSSIDFromInterfaceList(networks, GetInterfaceSSID); |
420 } else { | 466 } else { |
421 type = online_links.empty() ? NetworkChangeNotifier::CONNECTION_NONE | 467 type = online_links.empty() ? NetworkChangeNotifier::CONNECTION_NONE |
422 : NetworkChangeNotifier::CONNECTION_UNKNOWN; | 468 : NetworkChangeNotifier::CONNECTION_UNKNOWN; |
423 } | 469 } |
424 | 470 |
425 AddressTrackerAutoLock lock(*this, connection_type_lock_); | 471 { |
426 current_connection_type_ = type; | 472 AddressTrackerAutoLock lock(*this, connection_type_lock_); |
| 473 current_connection_type_ = type; |
| 474 } |
| 475 { |
| 476 AddressTrackerAutoLock lock(*this, wifi_ssid_lock_); |
| 477 current_wifi_ssid_ = ssid; |
| 478 } |
427 } | 479 } |
428 | 480 |
429 AddressTrackerLinux::AddressTrackerAutoLock::AddressTrackerAutoLock( | 481 AddressTrackerLinux::AddressTrackerAutoLock::AddressTrackerAutoLock( |
430 const AddressTrackerLinux& tracker, | 482 const AddressTrackerLinux& tracker, |
431 base::Lock& lock) | 483 base::Lock& lock) |
432 : tracker_(tracker), lock_(lock) { | 484 : tracker_(tracker), lock_(lock) { |
433 if (tracker_.tracking_) { | 485 if (tracker_.tracking_) { |
434 lock_.Acquire(); | 486 lock_.Acquire(); |
435 } else { | 487 } else { |
436 DCHECK(tracker_.thread_checker_.CalledOnValidThread()); | 488 DCHECK(tracker_.thread_checker_.CalledOnValidThread()); |
437 } | 489 } |
438 } | 490 } |
439 | 491 |
440 AddressTrackerLinux::AddressTrackerAutoLock::~AddressTrackerAutoLock() { | 492 AddressTrackerLinux::AddressTrackerAutoLock::~AddressTrackerAutoLock() { |
441 if (tracker_.tracking_) { | 493 if (tracker_.tracking_) { |
442 lock_.AssertAcquired(); | 494 lock_.AssertAcquired(); |
443 lock_.Release(); | 495 lock_.Release(); |
444 } | 496 } |
445 } | 497 } |
446 | 498 |
447 } // namespace internal | 499 } // namespace internal |
448 } // namespace net | 500 } // namespace net |
OLD | NEW |