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

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

Issue 9540011: [net] Add DNS-related signals and NetLog to NetworkChangeNotifier. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Moved DNS watch to a separate IO thread on mac. Created 8 years, 9 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 | Annotate | Revision Log
« no previous file with comments | « net/base/network_change_notifier_linux.h ('k') | net/base/network_change_notifier_mac.h » ('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 // This implementation of NetworkChangeNotifier's offline state detection 5 // This implementation of NetworkChangeNotifier's offline state detection
6 // depends on D-Bus and NetworkManager, and is known to work on at least 6 // depends on D-Bus and NetworkManager, and is known to work on at least
7 // GNOME version 2.30. If D-Bus or NetworkManager are unavailable, this 7 // GNOME version 2.30. If D-Bus or NetworkManager are unavailable, this
8 // implementation will always behave as if it is online. 8 // implementation will always behave as if it is online.
9 9
10 #include "net/base/network_change_notifier_linux.h" 10 #include "net/base/network_change_notifier_linux.h"
11 11
12 #include <errno.h> 12 #include <errno.h>
13 #include <resolv.h>
13 #include <sys/socket.h> 14 #include <sys/socket.h>
14 15
15 #include "base/bind.h" 16 #include "base/bind.h"
16 #include "base/bind_helpers.h" 17 #include "base/bind_helpers.h"
17 #include "base/callback.h" 18 #include "base/callback.h"
18 #include "base/compiler_specific.h" 19 #include "base/compiler_specific.h"
19 #include "base/eintr_wrapper.h" 20 #include "base/eintr_wrapper.h"
20 #include "base/file_util.h" 21 #include "base/file_util.h"
21 #include "base/files/file_path_watcher.h" 22 #include "base/files/file_path_watcher.h"
22 #include "base/memory/weak_ptr.h" 23 #include "base/memory/weak_ptr.h"
23 #include "base/synchronization/lock.h" 24 #include "base/synchronization/lock.h"
24 #include "base/synchronization/waitable_event.h" 25 #include "base/synchronization/waitable_event.h"
25 #include "base/threading/platform_thread.h" 26 #include "base/threading/platform_thread.h"
26 #include "base/threading/thread.h" 27 #include "base/threading/thread.h"
27 #include "dbus/bus.h" 28 #include "dbus/bus.h"
28 #include "dbus/message.h" 29 #include "dbus/message.h"
29 #include "dbus/object_proxy.h" 30 #include "dbus/object_proxy.h"
31 #include "net/base/file_path_watcher_callback.h"
30 #include "net/base/net_errors.h" 32 #include "net/base/net_errors.h"
31 #include "net/base/network_change_notifier_netlink_linux.h" 33 #include "net/base/network_change_notifier_netlink_linux.h"
32 34
33 using ::base::files::FilePathWatcher; 35 using ::base::files::FilePathWatcher;
34 36
37 #ifndef _PATH_RESCONF // Normally defined in <resolv.h>
38 #define _PATH_RESCONF "/etc/resolv.conf"
39 #endif
40
35 namespace net { 41 namespace net {
36 42
37 namespace { 43 namespace {
38 44
39 const int kInvalidSocket = -1; 45 const int kInvalidSocket = -1;
40 46
41 const char kNetworkManagerServiceName[] = "org.freedesktop.NetworkManager"; 47 const char kNetworkManagerServiceName[] = "org.freedesktop.NetworkManager";
42 const char kNetworkManagerPath[] = "/org/freedesktop/NetworkManager"; 48 const char kNetworkManagerPath[] = "/org/freedesktop/NetworkManager";
43 const char kNetworkManagerInterface[] = "org.freedesktop.NetworkManager"; 49 const char kNetworkManagerInterface[] = "org.freedesktop.NetworkManager";
44 50
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after
230 return false; 236 return false;
231 } 237 }
232 } 238 }
233 239
234 bool NetworkManagerApi::IsCurrentlyOffline() { 240 bool NetworkManagerApi::IsCurrentlyOffline() {
235 offline_state_initialized_.Wait(); 241 offline_state_initialized_.Wait();
236 base::AutoLock lock(is_offline_lock_); 242 base::AutoLock lock(is_offline_lock_);
237 return is_offline_; 243 return is_offline_;
238 } 244 }
239 245
240 class DNSWatchDelegate : public FilePathWatcher::Delegate {
241 public:
242 explicit DNSWatchDelegate(const base::Closure& callback)
243 : callback_(callback) {}
244 virtual ~DNSWatchDelegate() {}
245 // FilePathWatcher::Delegate interface
246 virtual void OnFilePathChanged(const FilePath& path) OVERRIDE;
247 virtual void OnFilePathError(const FilePath& path) OVERRIDE;
248 private:
249 base::Closure callback_;
250 DISALLOW_COPY_AND_ASSIGN(DNSWatchDelegate);
251 };
252
253 void DNSWatchDelegate::OnFilePathChanged(const FilePath& path) {
254 // Calls NetworkChangeNotifier::NotifyObserversOfDNSChange().
255 callback_.Run();
256 }
257
258 void DNSWatchDelegate::OnFilePathError(const FilePath& path) {
259 LOG(ERROR) << "DNSWatchDelegate::OnFilePathError for " << path.value();
260 }
261
262 } // namespace 246 } // namespace
263 247
264 class NetworkChangeNotifierLinux::Thread 248 class NetworkChangeNotifierLinux::Thread
265 : public base::Thread, public MessageLoopForIO::Watcher { 249 : public base::Thread, public MessageLoopForIO::Watcher {
266 public: 250 public:
267 explicit Thread(dbus::Bus* bus); 251 explicit Thread(dbus::Bus* bus);
268 virtual ~Thread(); 252 virtual ~Thread();
269 253
270 // MessageLoopForIO::Watcher: 254 // MessageLoopForIO::Watcher:
271 virtual void OnFileCanReadWithoutBlocking(int fd); 255 virtual void OnFileCanReadWithoutBlocking(int fd);
272 virtual void OnFileCanWriteWithoutBlocking(int /* fd */); 256 virtual void OnFileCanWriteWithoutBlocking(int /* fd */);
273 257
274 // Plumbing for NetworkChangeNotifier::IsCurrentlyOffline. 258 // Plumbing for NetworkChangeNotifier::IsCurrentlyOffline.
275 // Safe to call from any thread. 259 // Safe to call from any thread.
276 bool IsCurrentlyOffline() { 260 bool IsCurrentlyOffline() {
277 return network_manager_api_.IsCurrentlyOffline(); 261 return network_manager_api_.IsCurrentlyOffline();
278 } 262 }
279 263
264 bool IsCurrentlyWatchingDNS() {
265 base::AutoLock lock(watching_dns_lock_);
266 return watching_dns_;
267 }
268
280 protected: 269 protected:
281 // base::Thread 270 // base::Thread
282 virtual void Init(); 271 virtual void Init();
283 virtual void CleanUp(); 272 virtual void CleanUp();
284 273
285 private: 274 private:
286 // Starts listening for netlink messages. Also handles the messages if there 275 // Starts listening for netlink messages. Also handles the messages if there
287 // are any available on the netlink socket. 276 // are any available on the netlink socket.
288 void ListenForNotifications(); 277 void ListenForNotifications();
289 278
290 // Attempts to read from the netlink socket into |buf| of length |len|. 279 // Attempts to read from the netlink socket into |buf| of length |len|.
291 // Returns the bytes read on synchronous success and ERR_IO_PENDING if the 280 // Returns the bytes read on synchronous success and ERR_IO_PENDING if the
292 // recv() would block. Otherwise, it returns a net error code. 281 // recv() would block. Otherwise, it returns a net error code.
293 int ReadNotificationMessage(char* buf, size_t len); 282 int ReadNotificationMessage(char* buf, size_t len);
294 283
284 // Called from FilePathWatcherCallback.
285 void OnDNSFileChanged(unsigned detail, bool watch_success);
286
295 // The netlink socket descriptor. 287 // The netlink socket descriptor.
296 int netlink_fd_; 288 int netlink_fd_;
297 MessageLoopForIO::FileDescriptorWatcher netlink_watcher_; 289 MessageLoopForIO::FileDescriptorWatcher netlink_watcher_;
298 290
299 // Technically only needed for ChromeOS, but it's ugly to #ifdef out. 291 // Used to watch for changes to /etc/resolv.conf and /etc/hosts.
300 base::WeakPtrFactory<Thread> ptr_factory_; 292 FilePathWatcherCallback resolv_watcher_;
293 FilePathWatcherCallback hosts_watcher_;
301 294
302 // Used to watch for changes to /etc/resolv.conf and /etc/hosts. 295 base::Lock watching_dns_lock_;
303 scoped_ptr<base::files::FilePathWatcher> resolv_file_watcher_; 296 bool watching_dns_;
304 scoped_ptr<base::files::FilePathWatcher> hosts_file_watcher_;
305 scoped_refptr<DNSWatchDelegate> resolv_watcher_delegate_;
306 scoped_refptr<DNSWatchDelegate> hosts_watcher_delegate_;
307 297
308 // Used to detect online/offline state changes. 298 // Used to detect online/offline state changes.
309 NetworkManagerApi network_manager_api_; 299 NetworkManagerApi network_manager_api_;
310 300
311 DISALLOW_COPY_AND_ASSIGN(Thread); 301 DISALLOW_COPY_AND_ASSIGN(Thread);
312 }; 302 };
313 303
314 NetworkChangeNotifierLinux::Thread::Thread(dbus::Bus* bus) 304 NetworkChangeNotifierLinux::Thread::Thread(dbus::Bus* bus)
315 : base::Thread("NetworkChangeNotifier"), 305 : base::Thread("NetworkChangeNotifier"),
316 netlink_fd_(kInvalidSocket), 306 netlink_fd_(kInvalidSocket),
317 ALLOW_THIS_IN_INITIALIZER_LIST(ptr_factory_(this)), 307 watching_dns_(false),
318 network_manager_api_( 308 network_manager_api_(
319 base::Bind(&NetworkChangeNotifier 309 base::Bind(&NetworkChangeNotifier
320 ::NotifyObserversOfOnlineStateChange), 310 ::NotifyObserversOfOnlineStateChange),
321 bus) { 311 bus) {
322 } 312 }
323 313
324 NetworkChangeNotifierLinux::Thread::~Thread() { 314 NetworkChangeNotifierLinux::Thread::~Thread() {
325 DCHECK(!Thread::IsRunning()); 315 DCHECK(!Thread::IsRunning());
326 } 316 }
327 317
328 void NetworkChangeNotifierLinux::Thread::Init() { 318 void NetworkChangeNotifierLinux::Thread::Init() {
329 resolv_file_watcher_.reset(new FilePathWatcher); 319 base::AutoLock lock(watching_dns_lock_);
330 hosts_file_watcher_.reset(new FilePathWatcher); 320 watching_dns_ = true;
331 resolv_watcher_delegate_ = new DNSWatchDelegate(base::Bind( 321 if (!resolv_watcher_.Watch(
332 &NetworkChangeNotifier::NotifyObserversOfDNSChange, 322 FilePath(FILE_PATH_LITERAL(_PATH_RESCONF)),
333 static_cast<unsigned>(CHANGE_DNS_SETTINGS))); 323 base::Bind(&Thread::OnDNSFileChanged,
334 hosts_watcher_delegate_ = new DNSWatchDelegate(base::Bind( 324 base::Unretained(this),
335 &NetworkChangeNotifier::NotifyObserversOfDNSChange, 325 static_cast<unsigned>(CHANGE_DNS_SETTINGS)))) {
336 static_cast<unsigned>(CHANGE_DNS_HOSTS)));
337 if (!resolv_file_watcher_->Watch(
338 FilePath(FILE_PATH_LITERAL("/etc/resolv.conf")),
339 resolv_watcher_delegate_.get())) {
340 LOG(ERROR) << "Failed to setup watch for /etc/resolv.conf"; 326 LOG(ERROR) << "Failed to setup watch for /etc/resolv.conf";
327 watching_dns_ = false;
341 } 328 }
342 if (!hosts_file_watcher_->Watch(FilePath(FILE_PATH_LITERAL("/etc/hosts")), 329 if (!hosts_watcher_.Watch(
343 hosts_watcher_delegate_.get())) { 330 FilePath(FILE_PATH_LITERAL("/etc/hosts")),
331 base::Bind(&Thread::OnDNSFileChanged,
332 base::Unretained(this),
333 static_cast<unsigned>(CHANGE_DNS_HOSTS)))) {
344 LOG(ERROR) << "Failed to setup watch for /etc/hosts"; 334 LOG(ERROR) << "Failed to setup watch for /etc/hosts";
335 watching_dns_ = false;
345 } 336 }
346 netlink_fd_ = InitializeNetlinkSocket(); 337 netlink_fd_ = InitializeNetlinkSocket();
347 if (netlink_fd_ < 0) { 338 if (netlink_fd_ < 0) {
348 netlink_fd_ = kInvalidSocket; 339 netlink_fd_ = kInvalidSocket;
349 return; 340 return;
350 } 341 }
351 ListenForNotifications(); 342 ListenForNotifications();
352 343
353 network_manager_api_.Init(); 344 network_manager_api_.Init();
354 } 345 }
355 346
356 void NetworkChangeNotifierLinux::Thread::CleanUp() { 347 void NetworkChangeNotifierLinux::Thread::CleanUp() {
357 if (netlink_fd_ != kInvalidSocket) { 348 if (netlink_fd_ != kInvalidSocket) {
358 if (HANDLE_EINTR(close(netlink_fd_)) != 0) 349 if (HANDLE_EINTR(close(netlink_fd_)) != 0)
359 PLOG(ERROR) << "Failed to close socket"; 350 PLOG(ERROR) << "Failed to close socket";
360 netlink_fd_ = kInvalidSocket; 351 netlink_fd_ = kInvalidSocket;
361 netlink_watcher_.StopWatchingFileDescriptor(); 352 netlink_watcher_.StopWatchingFileDescriptor();
362 } 353 }
363 // Kill watchers early to make sure they won't try to call 354 // Kill watchers early to make sure they won't try to call
364 // into us via the delegate during destruction. 355 // into us via the delegate during destruction.
365 resolv_file_watcher_.reset(); 356 resolv_watcher_.Cancel();
366 hosts_file_watcher_.reset(); 357 hosts_watcher_.Cancel();
367 358
368 network_manager_api_.CleanUp(); 359 network_manager_api_.CleanUp();
369 } 360 }
370 361
371 void NetworkChangeNotifierLinux::Thread::OnFileCanReadWithoutBlocking(int fd) { 362 void NetworkChangeNotifierLinux::Thread::OnFileCanReadWithoutBlocking(int fd) {
372 DCHECK_EQ(fd, netlink_fd_); 363 DCHECK_EQ(fd, netlink_fd_);
373 ListenForNotifications(); 364 ListenForNotifications();
374 } 365 }
375 366
376 void NetworkChangeNotifierLinux::Thread::OnFileCanWriteWithoutBlocking( 367 void NetworkChangeNotifierLinux::Thread::OnFileCanWriteWithoutBlocking(
377 int /* fd */) { 368 int /* fd */) {
378 NOTREACHED(); 369 NOTREACHED();
379 } 370 }
380 371
381 void NetworkChangeNotifierLinux::Thread::ListenForNotifications() { 372 void NetworkChangeNotifierLinux::Thread::ListenForNotifications() {
382 char buf[4096]; 373 char buf[4096];
383 int rv = ReadNotificationMessage(buf, arraysize(buf)); 374 int rv = ReadNotificationMessage(buf, arraysize(buf));
384 while (rv > 0) { 375 while (rv > 0) {
385 if (HandleNetlinkMessage(buf, rv)) { 376 if (HandleNetlinkMessage(buf, rv)) {
386 VLOG(1) << "Detected IP address changes."; 377 VLOG(1) << "Detected IP address changes.";
387 #if defined(OS_CHROMEOS)
388 // TODO(oshima): chromium-os:8285 - introduced artificial delay to
389 // work around the issue of network load issue after connection
390 // restored. See the bug for more details.
391 // This should be removed once this bug is properly fixed.
392 const int kObserverNotificationDelayMS = 200;
393 message_loop()->PostDelayedTask(
394 FROM_HERE,
395 base::Bind(&NetworkChangeNotifier::NotifyObserversOfIPAddressChange),
396 kObserverNotificationDelayMS);
397 #else
398 NotifyObserversOfIPAddressChange(); 378 NotifyObserversOfIPAddressChange();
399 #endif
400 } 379 }
401 rv = ReadNotificationMessage(buf, arraysize(buf)); 380 rv = ReadNotificationMessage(buf, arraysize(buf));
402 } 381 }
403 382
404 if (rv == ERR_IO_PENDING) { 383 if (rv == ERR_IO_PENDING) {
405 rv = MessageLoopForIO::current()->WatchFileDescriptor(netlink_fd_, false, 384 rv = MessageLoopForIO::current()->WatchFileDescriptor(netlink_fd_, false,
406 MessageLoopForIO::WATCH_READ, &netlink_watcher_, this); 385 MessageLoopForIO::WATCH_READ, &netlink_watcher_, this);
407 LOG_IF(ERROR, !rv) << "Failed to watch netlink socket: " << netlink_fd_; 386 LOG_IF(ERROR, !rv) << "Failed to watch netlink socket: " << netlink_fd_;
408 } 387 }
409 } 388 }
(...skipping 10 matching lines...) Expand all
420 399
421 DCHECK_NE(rv, 0); 400 DCHECK_NE(rv, 0);
422 if (errno != EAGAIN && errno != EWOULDBLOCK) { 401 if (errno != EAGAIN && errno != EWOULDBLOCK) {
423 PLOG(DFATAL) << "recv"; 402 PLOG(DFATAL) << "recv";
424 return ERR_FAILED; 403 return ERR_FAILED;
425 } 404 }
426 405
427 return ERR_IO_PENDING; 406 return ERR_IO_PENDING;
428 } 407 }
429 408
409 void NetworkChangeNotifierLinux::Thread::OnDNSFileChanged(unsigned detail,
410 bool watch_success) {
411 if (!watch_success) {
412 LOG(ERROR) << "DNS watch failed.";
413 base::AutoLock lock(watching_dns_lock_);
414 watching_dns_ = false;
415 }
416 // Always notify observers so that they can check IsWatchingDNS().
417 NetworkChangeNotifier::NotifyObserversOfDNSChange(detail);
418 }
419
430 NetworkChangeNotifierLinux* NetworkChangeNotifierLinux::Create() { 420 NetworkChangeNotifierLinux* NetworkChangeNotifierLinux::Create() {
431 return new NetworkChangeNotifierLinux(NULL); 421 return new NetworkChangeNotifierLinux(NULL);
432 } 422 }
433 423
434 NetworkChangeNotifierLinux* NetworkChangeNotifierLinux::CreateForTest( 424 NetworkChangeNotifierLinux* NetworkChangeNotifierLinux::CreateForTest(
435 dbus::Bus* bus) { 425 dbus::Bus* bus) {
436 return new NetworkChangeNotifierLinux(bus); 426 return new NetworkChangeNotifierLinux(bus);
437 } 427 }
438 428
439 NetworkChangeNotifierLinux::NetworkChangeNotifierLinux(dbus::Bus* bus) 429 NetworkChangeNotifierLinux::NetworkChangeNotifierLinux(dbus::Bus* bus)
440 : notifier_thread_(new Thread(bus)) { 430 : notifier_thread_(new Thread(bus)) {
441 // We create this notifier thread because the notification implementation 431 // We create this notifier thread because the notification implementation
442 // needs a MessageLoopForIO, and there's no guarantee that 432 // needs a MessageLoopForIO, and there's no guarantee that
443 // MessageLoop::current() meets that criterion. 433 // MessageLoop::current() meets that criterion.
444 base::Thread::Options thread_options(MessageLoop::TYPE_IO, 0); 434 base::Thread::Options thread_options(MessageLoop::TYPE_IO, 0);
445 notifier_thread_->StartWithOptions(thread_options); 435 notifier_thread_->StartWithOptions(thread_options);
446 } 436 }
447 437
448 NetworkChangeNotifierLinux::~NetworkChangeNotifierLinux() { 438 NetworkChangeNotifierLinux::~NetworkChangeNotifierLinux() {
449 // Stopping from here allows us to sanity- check that the notifier 439 // Stopping from here allows us to sanity- check that the notifier
450 // thread shut down properly. 440 // thread shut down properly.
451 notifier_thread_->Stop(); 441 notifier_thread_->Stop();
452 } 442 }
453 443
454 bool NetworkChangeNotifierLinux::IsCurrentlyOffline() const { 444 bool NetworkChangeNotifierLinux::IsCurrentlyOffline() const {
455 return notifier_thread_->IsCurrentlyOffline(); 445 return notifier_thread_->IsCurrentlyOffline();
456 } 446 }
457 447
448 bool NetworkChangeNotifierLinux::IsCurrentlyWatchingDNS() const {
449 return notifier_thread_->IsCurrentlyWatchingDNS();
450 }
451
458 } // namespace net 452 } // namespace net
OLDNEW
« no previous file with comments | « net/base/network_change_notifier_linux.h ('k') | net/base/network_change_notifier_mac.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698