Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(126)

Side by Side Diff: net/base/address_tracker_linux.cc

Issue 739983005: Determine connection type in NetworkChangeNotifierLinux. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Re-add write to ifnames Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/base/address_tracker_linux.h ('k') | net/base/address_tracker_linux_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 <sys/ioctl.h> 9 #include <sys/ioctl.h>
10 10
11 #include "base/files/scoped_file.h"
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/net_util_linux.h"
14 16
15 namespace net { 17 namespace net {
16 namespace internal { 18 namespace internal {
17 19
18 namespace { 20 namespace {
19 21
20 // Retrieves address from NETLINK address message. 22 // Retrieves address from NETLINK address message.
21 // Sets |really_deprecated| for IPv6 addresses with preferred lifetimes of 0. 23 // Sets |really_deprecated| for IPv6 addresses with preferred lifetimes of 0.
22 bool GetAddress(const struct nlmsghdr* header, 24 bool GetAddress(const struct nlmsghdr* header,
23 IPAddressNumber* out, 25 IPAddressNumber* out,
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
69 } 71 }
70 } 72 }
71 if (local) 73 if (local)
72 address = local; 74 address = local;
73 if (!address) 75 if (!address)
74 return false; 76 return false;
75 out->assign(address, address + address_length); 77 out->assign(address, address + address_length);
76 return true; 78 return true;
77 } 79 }
78 80
79 // Returns the name for the interface with interface index |interface_index|. 81 } // namespace
80 // The return value points to a function-scoped static so it may be changed by 82
81 // subsequent calls. This function could be replaced with if_indextoname() but 83 // static
82 // net/if.h cannot be mixed with linux/if.h so we'll stick with exclusively 84 char* AddressTrackerLinux::GetInterfaceName(int interface_index, char* buf) {
83 // talking to the kernel and not the C library. 85 memset(buf, 0, IFNAMSIZ);
84 const char* GetInterfaceName(int interface_index) { 86 base::ScopedFD ioctl_socket(socket(AF_INET, SOCK_DGRAM, 0));
85 int ioctl_socket = socket(AF_INET, SOCK_DGRAM, 0); 87 if (!ioctl_socket.is_valid())
86 if (ioctl_socket < 0) 88 return buf;
87 return ""; 89
88 static struct ifreq ifr; 90 struct ifreq ifr = {.ifr_ifindex = interface_index};
derekjchow1 2015/01/30 04:46:06 I built net_watcher for Chromecast to test this ch
89 memset(&ifr, 0, sizeof(ifr)); 91
90 ifr.ifr_ifindex = interface_index; 92 if (ioctl(ioctl_socket.get(), SIOCGIFNAME, &ifr) == 0)
91 int rv = ioctl(ioctl_socket, SIOCGIFNAME, &ifr); 93 strncpy(buf, ifr.ifr_name, IFNAMSIZ - 1);
92 close(ioctl_socket); 94 return buf;
93 if (rv != 0)
94 return "";
95 return ifr.ifr_name;
96 } 95 }
97 96
98 } // namespace
99
100 AddressTrackerLinux::AddressTrackerLinux() 97 AddressTrackerLinux::AddressTrackerLinux()
101 : get_interface_name_(GetInterfaceName), 98 : get_interface_name_(GetInterfaceName),
102 address_callback_(base::Bind(&base::DoNothing)), 99 address_callback_(base::Bind(&base::DoNothing)),
103 link_callback_(base::Bind(&base::DoNothing)), 100 link_callback_(base::Bind(&base::DoNothing)),
104 tunnel_callback_(base::Bind(&base::DoNothing)), 101 tunnel_callback_(base::Bind(&base::DoNothing)),
105 netlink_fd_(-1), 102 netlink_fd_(-1),
106 is_offline_(true), 103 connection_type_initialized_(false),
107 is_offline_initialized_(false), 104 connection_type_initialized_cv_(&connection_type_lock_),
108 is_offline_initialized_cv_(&is_offline_lock_), 105 current_connection_type_(NetworkChangeNotifier::CONNECTION_NONE),
109 tracking_(false) { 106 tracking_(false) {
110 } 107 }
111 108
112 AddressTrackerLinux::AddressTrackerLinux(const base::Closure& address_callback, 109 AddressTrackerLinux::AddressTrackerLinux(const base::Closure& address_callback,
113 const base::Closure& link_callback, 110 const base::Closure& link_callback,
114 const base::Closure& tunnel_callback) 111 const base::Closure& tunnel_callback)
115 : get_interface_name_(GetInterfaceName), 112 : get_interface_name_(GetInterfaceName),
116 address_callback_(address_callback), 113 address_callback_(address_callback),
117 link_callback_(link_callback), 114 link_callback_(link_callback),
118 tunnel_callback_(tunnel_callback), 115 tunnel_callback_(tunnel_callback),
119 netlink_fd_(-1), 116 netlink_fd_(-1),
120 is_offline_(true), 117 connection_type_initialized_(false),
121 is_offline_initialized_(false), 118 connection_type_initialized_cv_(&connection_type_lock_),
122 is_offline_initialized_cv_(&is_offline_lock_), 119 current_connection_type_(NetworkChangeNotifier::CONNECTION_NONE),
123 tracking_(true) { 120 tracking_(true) {
124 DCHECK(!address_callback.is_null()); 121 DCHECK(!address_callback.is_null());
125 DCHECK(!link_callback.is_null()); 122 DCHECK(!link_callback.is_null());
126 } 123 }
127 124
128 AddressTrackerLinux::~AddressTrackerLinux() { 125 AddressTrackerLinux::~AddressTrackerLinux() {
129 CloseSocket(); 126 CloseSocket();
130 } 127 }
131 128
132 void AddressTrackerLinux::Init() { 129 void AddressTrackerLinux::Init() {
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
196 sizeof(peer))); 193 sizeof(peer)));
197 if (rv < 0) { 194 if (rv < 0) {
198 PLOG(ERROR) << "Could not send NETLINK request"; 195 PLOG(ERROR) << "Could not send NETLINK request";
199 AbortAndForceOnline(); 196 AbortAndForceOnline();
200 return; 197 return;
201 } 198 }
202 199
203 // Consume pending message to populate links_online_, but don't notify. 200 // Consume pending message to populate links_online_, but don't notify.
204 ReadMessages(&address_changed, &link_changed, &tunnel_changed); 201 ReadMessages(&address_changed, &link_changed, &tunnel_changed);
205 { 202 {
206 AddressTrackerAutoLock lock(*this, is_offline_lock_); 203 AddressTrackerAutoLock lock(*this, connection_type_lock_);
207 is_offline_initialized_ = true; 204 connection_type_initialized_ = true;
208 is_offline_initialized_cv_.Signal(); 205 connection_type_initialized_cv_.Signal();
209 } 206 }
210 207
211 if (tracking_) { 208 if (tracking_) {
212 rv = base::MessageLoopForIO::current()->WatchFileDescriptor( 209 rv = base::MessageLoopForIO::current()->WatchFileDescriptor(
213 netlink_fd_, true, base::MessageLoopForIO::WATCH_READ, &watcher_, this); 210 netlink_fd_, true, base::MessageLoopForIO::WATCH_READ, &watcher_, this);
214 if (rv < 0) { 211 if (rv < 0) {
215 PLOG(ERROR) << "Could not watch NETLINK socket"; 212 PLOG(ERROR) << "Could not watch NETLINK socket";
216 AbortAndForceOnline(); 213 AbortAndForceOnline();
217 return; 214 return;
218 } 215 }
219 } 216 }
220 } 217 }
221 218
222 void AddressTrackerLinux::AbortAndForceOnline() { 219 void AddressTrackerLinux::AbortAndForceOnline() {
223 CloseSocket(); 220 CloseSocket();
224 AddressTrackerAutoLock lock(*this, is_offline_lock_); 221 AddressTrackerAutoLock lock(*this, connection_type_lock_);
225 is_offline_ = false; 222 current_connection_type_ = NetworkChangeNotifier::CONNECTION_UNKNOWN;
226 is_offline_initialized_ = true; 223 connection_type_initialized_ = true;
227 is_offline_initialized_cv_.Signal(); 224 connection_type_initialized_cv_.Signal();
228 } 225 }
229 226
230 AddressTrackerLinux::AddressMap AddressTrackerLinux::GetAddressMap() const { 227 AddressTrackerLinux::AddressMap AddressTrackerLinux::GetAddressMap() const {
231 AddressTrackerAutoLock lock(*this, address_map_lock_); 228 AddressTrackerAutoLock lock(*this, address_map_lock_);
232 return address_map_; 229 return address_map_;
233 } 230 }
234 231
235 base::hash_set<int> AddressTrackerLinux::GetOnlineLinks() const { 232 base::hash_set<int> AddressTrackerLinux::GetOnlineLinks() const {
236 AddressTrackerAutoLock lock(*this, online_links_lock_); 233 AddressTrackerAutoLock lock(*this, online_links_lock_);
237 return online_links_; 234 return online_links_;
238 } 235 }
239 236
240 NetworkChangeNotifier::ConnectionType 237 NetworkChangeNotifier::ConnectionType
241 AddressTrackerLinux::GetCurrentConnectionType() { 238 AddressTrackerLinux::GetCurrentConnectionType() {
242 // http://crbug.com/125097 239 // http://crbug.com/125097
243 base::ThreadRestrictions::ScopedAllowWait allow_wait; 240 base::ThreadRestrictions::ScopedAllowWait allow_wait;
244 AddressTrackerAutoLock lock(*this, is_offline_lock_); 241 AddressTrackerAutoLock lock(*this, connection_type_lock_);
245 // Make sure the initial offline state is set before returning. 242 // Make sure the initial connection type is set before returning.
246 while (!is_offline_initialized_) { 243 while (!connection_type_initialized_) {
247 is_offline_initialized_cv_.Wait(); 244 connection_type_initialized_cv_.Wait();
248 } 245 }
249 // TODO(droger): Return something more detailed than CONNECTION_UNKNOWN. 246 return current_connection_type_;
250 // http://crbug.com/160537
251 return is_offline_ ? NetworkChangeNotifier::CONNECTION_NONE :
252 NetworkChangeNotifier::CONNECTION_UNKNOWN;
253 } 247 }
254 248
255 void AddressTrackerLinux::ReadMessages(bool* address_changed, 249 void AddressTrackerLinux::ReadMessages(bool* address_changed,
256 bool* link_changed, 250 bool* link_changed,
257 bool* tunnel_changed) { 251 bool* tunnel_changed) {
258 *address_changed = false; 252 *address_changed = false;
259 *link_changed = false; 253 *link_changed = false;
260 *tunnel_changed = false; 254 *tunnel_changed = false;
261 char buffer[4096]; 255 char buffer[4096];
262 bool first_loop = true; 256 bool first_loop = true;
263 for (;;) { 257 for (;;) {
264 int rv = HANDLE_EINTR(recv(netlink_fd_, 258 int rv = HANDLE_EINTR(recv(netlink_fd_,
265 buffer, 259 buffer,
266 sizeof(buffer), 260 sizeof(buffer),
267 // Block the first time through loop. 261 // Block the first time through loop.
268 first_loop ? 0 : MSG_DONTWAIT)); 262 first_loop ? 0 : MSG_DONTWAIT));
269 first_loop = false; 263 first_loop = false;
270 if (rv == 0) { 264 if (rv == 0) {
271 LOG(ERROR) << "Unexpected shutdown of NETLINK socket."; 265 LOG(ERROR) << "Unexpected shutdown of NETLINK socket.";
272 return; 266 return;
273 } 267 }
274 if (rv < 0) { 268 if (rv < 0) {
275 if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) 269 if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
276 break; 270 break;
277 PLOG(ERROR) << "Failed to recv from netlink socket"; 271 PLOG(ERROR) << "Failed to recv from netlink socket";
278 return; 272 return;
279 } 273 }
280 HandleMessage(buffer, rv, address_changed, link_changed, tunnel_changed); 274 HandleMessage(buffer, rv, address_changed, link_changed, tunnel_changed);
281 } 275 }
282 if (*link_changed) { 276 if (*link_changed || *address_changed)
283 bool is_offline; 277 UpdateCurrentConnectionType();
284 {
285 AddressTrackerAutoLock lock(*this, online_links_lock_);
286 is_offline = online_links_.empty();
287 }
288 AddressTrackerAutoLock lock(*this, is_offline_lock_);
289 is_offline_ = is_offline;
290 }
291 } 278 }
292 279
293 void AddressTrackerLinux::HandleMessage(char* buffer, 280 void AddressTrackerLinux::HandleMessage(char* buffer,
294 size_t length, 281 size_t length,
295 bool* address_changed, 282 bool* address_changed,
296 bool* link_changed, 283 bool* link_changed,
297 bool* tunnel_changed) { 284 bool* tunnel_changed) {
298 DCHECK(buffer); 285 DCHECK(buffer);
299 for (struct nlmsghdr* header = reinterpret_cast<struct nlmsghdr*>(buffer); 286 for (struct nlmsghdr* header = reinterpret_cast<struct nlmsghdr*>(buffer);
300 NLMSG_OK(header, length); 287 NLMSG_OK(header, length);
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
344 } 331 }
345 } break; 332 } break;
346 case RTM_NEWLINK: { 333 case RTM_NEWLINK: {
347 const struct ifinfomsg* msg = 334 const struct ifinfomsg* msg =
348 reinterpret_cast<struct ifinfomsg*>(NLMSG_DATA(header)); 335 reinterpret_cast<struct ifinfomsg*>(NLMSG_DATA(header));
349 if (!(msg->ifi_flags & IFF_LOOPBACK) && (msg->ifi_flags & IFF_UP) && 336 if (!(msg->ifi_flags & IFF_LOOPBACK) && (msg->ifi_flags & IFF_UP) &&
350 (msg->ifi_flags & IFF_LOWER_UP) && (msg->ifi_flags & IFF_RUNNING)) { 337 (msg->ifi_flags & IFF_LOWER_UP) && (msg->ifi_flags & IFF_RUNNING)) {
351 AddressTrackerAutoLock lock(*this, online_links_lock_); 338 AddressTrackerAutoLock lock(*this, online_links_lock_);
352 if (online_links_.insert(msg->ifi_index).second) { 339 if (online_links_.insert(msg->ifi_index).second) {
353 *link_changed = true; 340 *link_changed = true;
354 if (IsTunnelInterface(msg)) 341 if (IsTunnelInterface(msg->ifi_index))
355 *tunnel_changed = true; 342 *tunnel_changed = true;
356 } 343 }
357 } else { 344 } else {
358 AddressTrackerAutoLock lock(*this, online_links_lock_); 345 AddressTrackerAutoLock lock(*this, online_links_lock_);
359 if (online_links_.erase(msg->ifi_index)) { 346 if (online_links_.erase(msg->ifi_index)) {
360 *link_changed = true; 347 *link_changed = true;
361 if (IsTunnelInterface(msg)) 348 if (IsTunnelInterface(msg->ifi_index))
362 *tunnel_changed = true; 349 *tunnel_changed = true;
363 } 350 }
364 } 351 }
365 } break; 352 } break;
366 case RTM_DELLINK: { 353 case RTM_DELLINK: {
367 const struct ifinfomsg* msg = 354 const struct ifinfomsg* msg =
368 reinterpret_cast<struct ifinfomsg*>(NLMSG_DATA(header)); 355 reinterpret_cast<struct ifinfomsg*>(NLMSG_DATA(header));
369 AddressTrackerAutoLock lock(*this, online_links_lock_); 356 AddressTrackerAutoLock lock(*this, online_links_lock_);
370 if (online_links_.erase(msg->ifi_index)) { 357 if (online_links_.erase(msg->ifi_index)) {
371 *link_changed = true; 358 *link_changed = true;
372 if (IsTunnelInterface(msg)) 359 if (IsTunnelInterface(msg->ifi_index))
373 *tunnel_changed = true; 360 *tunnel_changed = true;
374 } 361 }
375 } break; 362 } break;
376 default: 363 default:
377 break; 364 break;
378 } 365 }
379 } 366 }
380 } 367 }
381 368
382 void AddressTrackerLinux::OnFileCanReadWithoutBlocking(int fd) { 369 void AddressTrackerLinux::OnFileCanReadWithoutBlocking(int fd) {
(...skipping 11 matching lines...) Expand all
394 } 381 }
395 382
396 void AddressTrackerLinux::OnFileCanWriteWithoutBlocking(int /* fd */) {} 383 void AddressTrackerLinux::OnFileCanWriteWithoutBlocking(int /* fd */) {}
397 384
398 void AddressTrackerLinux::CloseSocket() { 385 void AddressTrackerLinux::CloseSocket() {
399 if (netlink_fd_ >= 0 && IGNORE_EINTR(close(netlink_fd_)) < 0) 386 if (netlink_fd_ >= 0 && IGNORE_EINTR(close(netlink_fd_)) < 0)
400 PLOG(ERROR) << "Could not close NETLINK socket."; 387 PLOG(ERROR) << "Could not close NETLINK socket.";
401 netlink_fd_ = -1; 388 netlink_fd_ = -1;
402 } 389 }
403 390
404 bool AddressTrackerLinux::IsTunnelInterface(const struct ifinfomsg* msg) const { 391 bool AddressTrackerLinux::IsTunnelInterface(int interface_index) const {
405 // Linux kernel drivers/net/tun.c uses "tun" name prefix. 392 // Linux kernel drivers/net/tun.c uses "tun" name prefix.
406 return strncmp(get_interface_name_(msg->ifi_index), "tun", 3) == 0; 393 char buf[IFNAMSIZ] = {0};
394 return strncmp(get_interface_name_(interface_index, buf), "tun", 3) == 0;
395 }
396
397 void AddressTrackerLinux::UpdateCurrentConnectionType() {
398 NetworkChangeNotifier::ConnectionType type =
pauljensen 2015/01/29 19:40:12 nit: move |type| declaration down next to |network
derekjchow1 2015/01/30 04:46:06 Done.
399 NetworkChangeNotifier::CONNECTION_NONE;
400 AddressTrackerLinux::AddressMap address_map = GetAddressMap();
401 base::hash_set<int> online_links = GetOnlineLinks();
402
403 // Strip out tunnel interfaces from online_links
404 for (base::hash_set<int>::const_iterator it = online_links.begin();
405 it != online_links.end();) {
406 if (IsTunnelInterface(*it)) {
407 base::hash_set<int>::const_iterator tunnel_it = it;
408 ++it;
409 online_links.erase(tunnel_it);
410 } else {
411 ++it;
412 }
413 }
414
415 NetworkInterfaceList networks;
416 if (GetNetworkListImpl(&networks, 0, online_links, address_map,
417 get_interface_name_)) {
418 type = NetworkChangeNotifier::ConnectionTypeFromInterfaceList(networks);
419 } else {
420 type = online_links.empty() ? NetworkChangeNotifier::CONNECTION_NONE
421 : NetworkChangeNotifier::CONNECTION_UNKNOWN;
422 }
423
424 AddressTrackerAutoLock lock(*this, connection_type_lock_);
425 current_connection_type_ = type;
407 } 426 }
408 427
409 AddressTrackerLinux::AddressTrackerAutoLock::AddressTrackerAutoLock( 428 AddressTrackerLinux::AddressTrackerAutoLock::AddressTrackerAutoLock(
410 const AddressTrackerLinux& tracker, 429 const AddressTrackerLinux& tracker,
411 base::Lock& lock) 430 base::Lock& lock)
412 : tracker_(tracker), lock_(lock) { 431 : tracker_(tracker), lock_(lock) {
413 if (tracker_.tracking_) { 432 if (tracker_.tracking_) {
414 lock_.Acquire(); 433 lock_.Acquire();
415 } else { 434 } else {
416 DCHECK(tracker_.thread_checker_.CalledOnValidThread()); 435 DCHECK(tracker_.thread_checker_.CalledOnValidThread());
417 } 436 }
418 } 437 }
419 438
420 AddressTrackerLinux::AddressTrackerAutoLock::~AddressTrackerAutoLock() { 439 AddressTrackerLinux::AddressTrackerAutoLock::~AddressTrackerAutoLock() {
421 if (tracker_.tracking_) { 440 if (tracker_.tracking_) {
422 lock_.AssertAcquired(); 441 lock_.AssertAcquired();
423 lock_.Release(); 442 lock_.Release();
424 } 443 }
425 } 444 }
426 445
427 } // namespace internal 446 } // namespace internal
428 } // namespace net 447 } // namespace net
OLDNEW
« no previous file with comments | « net/base/address_tracker_linux.h ('k') | net/base/address_tracker_linux_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698