diff options
author | pkasting@chromium.org <pkasting@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-06-25 21:30:38 +0000 |
---|---|---|
committer | pkasting@chromium.org <pkasting@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-06-25 21:30:38 +0000 |
commit | 66761b95332549f825999e482c17c94675275f49 (patch) | |
tree | fc5307808a2c62f1eff2a9f37db3aff11c5455d9 /net/base | |
parent | e313f3b11360902a3da9b3b1cc0df2a4792d0867 (diff) | |
download | chromium_src-66761b95332549f825999e482c17c94675275f49.zip chromium_src-66761b95332549f825999e482c17c94675275f49.tar.gz chromium_src-66761b95332549f825999e482c17c94675275f49.tar.bz2 |
Massively simplify the NetworkChangeNotifier infrastructure:
* Use a process-wide object (singleton pattern)
* Create/destroy this object on the main thread, make it outlive all consumers
* Make observer-related functions threadsafe
As a result, the notifier can now be used by any thread (eliminating things like NetworkChangeObserverProxy and NetworkChangeNotifierProxy, and expanding its usefulness); its creation and inner workings are much simplified (eliminating implementation-specific classes); and it is simpler to access (eliminating things like NetworkChangeNotifierThread and a LOT of passing pointers around).
BUG=none
TEST=Unittests; network changes still trigger notifications
Review URL: http://codereview.chromium.org/2802015
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@50895 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/base')
-rw-r--r-- | net/base/host_resolver.h | 6 | ||||
-rw-r--r-- | net/base/host_resolver_impl.cc | 16 | ||||
-rw-r--r-- | net/base/host_resolver_impl.h | 7 | ||||
-rw-r--r-- | net/base/host_resolver_impl_unittest.cc | 43 | ||||
-rw-r--r-- | net/base/mock_host_resolver.cc | 2 | ||||
-rw-r--r-- | net/base/mock_network_change_notifier.h | 46 | ||||
-rw-r--r-- | net/base/net_test_suite.h | 5 | ||||
-rw-r--r-- | net/base/network_change_notifier.cc | 44 | ||||
-rw-r--r-- | net/base/network_change_notifier.h | 63 | ||||
-rw-r--r-- | net/base/network_change_notifier_linux.cc | 135 | ||||
-rw-r--r-- | net/base/network_change_notifier_linux.h | 54 | ||||
-rw-r--r-- | net/base/network_change_notifier_mac.cc | 287 | ||||
-rw-r--r-- | net/base/network_change_notifier_mac.h | 54 | ||||
-rw-r--r-- | net/base/network_change_notifier_win.cc | 73 | ||||
-rw-r--r-- | net/base/network_change_notifier_win.h | 27 |
15 files changed, 329 insertions, 533 deletions
diff --git a/net/base/host_resolver.h b/net/base/host_resolver.h index d798688..395fc65 100644 --- a/net/base/host_resolver.h +++ b/net/base/host_resolver.h @@ -21,7 +21,6 @@ class AddressList; class BoundNetLog; class HostCache; class HostResolverImpl; -class NetworkChangeNotifier; // This class represents the task of resolving hostnames (or IP address // literal) to an AddressList object. @@ -236,10 +235,7 @@ class SingleRequestHostResolver { // Creates a HostResolver implementation that queries the underlying system. // (Except if a unit-test has changed the global HostResolverProc using // ScopedHostResolverProc to intercept requests to the system). -// |network_change_notifier| must outlive HostResolver. It can optionally be -// NULL, in which case HostResolver will not respond to network changes. -HostResolver* CreateSystemHostResolver( - NetworkChangeNotifier* network_change_notifier); +HostResolver* CreateSystemHostResolver(); } // namespace net diff --git a/net/base/host_resolver_impl.cc b/net/base/host_resolver_impl.cc index c018a7a..5685fc4 100644 --- a/net/base/host_resolver_impl.cc +++ b/net/base/host_resolver_impl.cc @@ -29,7 +29,6 @@ #include "net/base/net_log.h" #include "net/base/net_errors.h" #include "net/base/net_util.h" -#include "net/base/network_change_notifier.h" #if defined(OS_WIN) #include "net/base/winsock_init.h" @@ -52,14 +51,13 @@ HostCache* CreateDefaultCache() { } // anonymous namespace -HostResolver* CreateSystemHostResolver( - NetworkChangeNotifier* network_change_notifier) { +HostResolver* CreateSystemHostResolver() { // Maximum of 50 concurrent threads. // TODO(eroman): Adjust this, do some A/B experiments. static const size_t kMaxJobs = 50u; - HostResolverImpl* resolver = new HostResolverImpl( - NULL, CreateDefaultCache(), network_change_notifier, kMaxJobs); + HostResolverImpl* resolver = + new HostResolverImpl(NULL, CreateDefaultCache(), kMaxJobs); return resolver; } @@ -704,7 +702,6 @@ class HostResolverImpl::JobPool { HostResolverImpl::HostResolverImpl( HostResolverProc* resolver_proc, HostCache* cache, - NetworkChangeNotifier* network_change_notifier, size_t max_jobs) : cache_(cache), max_jobs_(max_jobs), @@ -713,7 +710,6 @@ HostResolverImpl::HostResolverImpl( resolver_proc_(resolver_proc), default_address_family_(ADDRESS_FAMILY_UNSPECIFIED), shutdown_(false), - network_change_notifier_(network_change_notifier), ipv6_probe_monitoring_(false) { DCHECK_GT(max_jobs, 0u); @@ -724,8 +720,7 @@ HostResolverImpl::HostResolverImpl( #if defined(OS_WIN) EnsureWinsockInit(); #endif - if (network_change_notifier_) - network_change_notifier_->AddObserver(this); + NetworkChangeNotifier::AddObserver(this); } HostResolverImpl::~HostResolverImpl() { @@ -740,8 +735,7 @@ HostResolverImpl::~HostResolverImpl() { if (cur_completing_job_) cur_completing_job_->Cancel(); - if (network_change_notifier_) - network_change_notifier_->RemoveObserver(this); + NetworkChangeNotifier::RemoveObserver(this); // Delete the job pools. for (size_t i = 0u; i < arraysize(job_pools_); ++i) diff --git a/net/base/host_resolver_impl.h b/net/base/host_resolver_impl.h index a0e34ca..2a751fb 100644 --- a/net/base/host_resolver_impl.h +++ b/net/base/host_resolver_impl.h @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -73,13 +73,10 @@ class HostResolverImpl : public HostResolver, // thread-safe since it is run from multiple worker threads. If // |resolver_proc| is NULL then the default host resolver procedure is // used (which is SystemHostResolverProc except if overridden). - // |notifier| must outlive HostResolverImpl. It can optionally be NULL, in - // which case HostResolverImpl will not respond to network changes. // |max_jobs| specifies the maximum number of threads that the host resolver // will use. Use SetPoolConstraints() to specify finer-grain settings. HostResolverImpl(HostResolverProc* resolver_proc, HostCache* cache, - NetworkChangeNotifier* notifier, size_t max_jobs); // HostResolver methods: @@ -247,8 +244,6 @@ class HostResolverImpl : public HostResolver, // TODO(eroman): hack for http://crbug.com/15513 bool shutdown_; - NetworkChangeNotifier* const network_change_notifier_; - // Indicate if probing is done after each network change event to set address // family. // When false, explicit setting of address family is used. diff --git a/net/base/host_resolver_impl_unittest.cc b/net/base/host_resolver_impl_unittest.cc index 3d7e02a..6b33a56 100644 --- a/net/base/host_resolver_impl_unittest.cc +++ b/net/base/host_resolver_impl_unittest.cc @@ -13,7 +13,6 @@ #include "net/base/address_list.h" #include "net/base/completion_callback.h" #include "net/base/mock_host_resolver.h" -#include "net/base/mock_network_change_notifier.h" #include "net/base/net_errors.h" #include "net/base/net_log_unittest.h" #include "net/base/net_util.h" @@ -39,11 +38,7 @@ HostCache* CreateDefaultCache() { static const size_t kMaxJobs = 10u; HostResolverImpl* CreateHostResolverImpl(HostResolverProc* resolver_proc) { - return new HostResolverImpl( - resolver_proc, - CreateDefaultCache(), - NULL, // network_change_notifier - kMaxJobs); + return new HostResolverImpl(resolver_proc, CreateDefaultCache(), kMaxJobs); } // Helper to create a HostResolver::RequestInfo. @@ -748,7 +743,7 @@ TEST_F(HostResolverImplTest, StartWithinCallback) { // Turn off caching for this host resolver. scoped_refptr<HostResolver> host_resolver( - new HostResolverImpl(resolver_proc, NULL, NULL, kMaxJobs)); + new HostResolverImpl(resolver_proc, NULL, kMaxJobs)); // The class will receive callbacks for when each resolve completes. It // checks that the right things happened. @@ -1044,11 +1039,8 @@ TEST_F(HostResolverImplTest, CancellationObserver) { // Test that IP address changes flush the cache. TEST_F(HostResolverImplTest, FlushCacheOnIPAddressChange) { - MockNetworkChangeNotifier mock_network_change_notifier; scoped_refptr<HostResolver> host_resolver( - new HostResolverImpl(NULL, CreateDefaultCache(), - &mock_network_change_notifier, - kMaxJobs)); + new HostResolverImpl(NULL, CreateDefaultCache(), kMaxJobs)); AddressList addrlist; @@ -1066,7 +1058,8 @@ TEST_F(HostResolverImplTest, FlushCacheOnIPAddressChange) { ASSERT_EQ(OK, rv); // Should complete synchronously. // Flush cache by triggering an IP address change. - mock_network_change_notifier.NotifyIPAddressChange(); + NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests(); + MessageLoop::current()->RunAllPending(); // Notification happens async. // Resolve "host1" again -- this time it won't be served from cache, so it // will complete asynchronously. @@ -1084,8 +1077,7 @@ TEST_F(HostResolverImplTest, HigherPriorityRequestsStartedFirst) { // This HostResolverImpl will only allow 1 outstanding resolve at a time. size_t kMaxJobs = 1u; scoped_refptr<HostResolver> host_resolver( - new HostResolverImpl(resolver_proc, CreateDefaultCache(), - NULL, kMaxJobs)); + new HostResolverImpl(resolver_proc, CreateDefaultCache(), kMaxJobs)); CapturingObserver observer; host_resolver->AddObserver(&observer); @@ -1169,8 +1161,7 @@ TEST_F(HostResolverImplTest, CancelPendingRequest) { // This HostResolverImpl will only allow 1 outstanding resolve at a time. const size_t kMaxJobs = 1u; scoped_refptr<HostResolver> host_resolver( - new HostResolverImpl(resolver_proc, CreateDefaultCache(), - NULL, kMaxJobs)); + new HostResolverImpl(resolver_proc, CreateDefaultCache(), kMaxJobs)); // Note that at this point the CapturingHostResolverProc is blocked, so any // requests we make will not complete. @@ -1231,9 +1222,8 @@ TEST_F(HostResolverImplTest, QueueOverflow) { // This HostResolverImpl will only allow 1 outstanding resolve at a time. const size_t kMaxOutstandingJobs = 1u; - scoped_refptr<HostResolverImpl> host_resolver( - new HostResolverImpl(resolver_proc, CreateDefaultCache(), - NULL, kMaxOutstandingJobs)); + scoped_refptr<HostResolverImpl> host_resolver(new HostResolverImpl( + resolver_proc, CreateDefaultCache(), kMaxOutstandingJobs)); // Only allow up to 3 requests to be enqueued at a time. const size_t kMaxPendingRequests = 3u; @@ -1310,9 +1300,8 @@ TEST_F(HostResolverImplTest, SetDefaultAddressFamily_IPv4) { // This HostResolverImpl will only allow 1 outstanding resolve at a time. const size_t kMaxOutstandingJobs = 1u; - scoped_refptr<HostResolverImpl> host_resolver( - new HostResolverImpl(resolver_proc, CreateDefaultCache(), - NULL, kMaxOutstandingJobs)); + scoped_refptr<HostResolverImpl> host_resolver(new HostResolverImpl( + resolver_proc, CreateDefaultCache(), kMaxOutstandingJobs)); host_resolver->SetDefaultAddressFamily(ADDRESS_FAMILY_IPV4); @@ -1379,9 +1368,8 @@ TEST_F(HostResolverImplTest, SetDefaultAddressFamily_IPv6) { // This HostResolverImpl will only allow 1 outstanding resolve at a time. const size_t kMaxOutstandingJobs = 1u; - scoped_refptr<HostResolverImpl> host_resolver( - new HostResolverImpl(resolver_proc, CreateDefaultCache(), - NULL, kMaxOutstandingJobs)); + scoped_refptr<HostResolverImpl> host_resolver(new HostResolverImpl( + resolver_proc, CreateDefaultCache(), kMaxOutstandingJobs)); host_resolver->SetDefaultAddressFamily(ADDRESS_FAMILY_IPV6); @@ -1446,9 +1434,8 @@ TEST_F(HostResolverImplTest, SetDefaultAddressFamily_Synchronous) { new CapturingHostResolverProc(new EchoingHostResolverProc); const size_t kMaxOutstandingJobs = 10u; - scoped_refptr<HostResolverImpl> host_resolver( - new HostResolverImpl(resolver_proc, CreateDefaultCache(), - NULL, kMaxOutstandingJobs)); + scoped_refptr<HostResolverImpl> host_resolver(new HostResolverImpl( + resolver_proc, CreateDefaultCache(), kMaxOutstandingJobs)); host_resolver->SetDefaultAddressFamily(ADDRESS_FAMILY_IPV4); diff --git a/net/base/mock_host_resolver.cc b/net/base/mock_host_resolver.cc index 1ee9bb1..8d1fd89 100644 --- a/net/base/mock_host_resolver.cc +++ b/net/base/mock_host_resolver.cc @@ -98,7 +98,7 @@ void MockHostResolverBase::Reset(HostResolverProc* interceptor) { base::TimeDelta::FromSeconds(0)); } - impl_ = new HostResolverImpl(proc, cache, NULL, 50u); + impl_ = new HostResolverImpl(proc, cache, 50u); } //----------------------------------------------------------------------------- diff --git a/net/base/mock_network_change_notifier.h b/net/base/mock_network_change_notifier.h deleted file mode 100644 index 7d1b38e..0000000 --- a/net/base/mock_network_change_notifier.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_BASE_MOCK_NETWORK_CHANGE_NOTIFIER_H_ -#define NET_BASE_MOCK_NETWORK_CHANGE_NOTIFIER_H_ - -#include "base/basictypes.h" -#include "base/non_thread_safe.h" -#include "net/base/network_change_notifier.h" - -namespace net { - -class MockNetworkChangeNotifier : public NetworkChangeNotifier, - public NonThreadSafe { - public: - MockNetworkChangeNotifier() : observer_(NULL) {} - - virtual ~MockNetworkChangeNotifier() { - CHECK(!observer_); - } - - void NotifyIPAddressChange() { - if (observer_) - observer_->OnIPAddressChanged(); - } - - virtual void AddObserver(Observer* observer) { - CHECK(!observer_); - observer_ = observer; - } - - virtual void RemoveObserver(Observer* observer) { - CHECK(observer_ == observer); - observer_ = NULL; - } - - private: - Observer* observer_; - - DISALLOW_COPY_AND_ASSIGN(MockNetworkChangeNotifier); -}; - -} // namespace net - -#endif // NET_BASE_MOCK_NETWORK_CHANGE_NOTIFIER_H_ diff --git a/net/base/net_test_suite.h b/net/base/net_test_suite.h index af58ca7..cc4ed2a 100644 --- a/net/base/net_test_suite.h +++ b/net/base/net_test_suite.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -25,6 +25,8 @@ class NetTestSuite : public TestSuite { // TestSuite::Initialize(). TestSuite::Initialize() performs some global // initialization that can only be done once. void InitializeTestThread() { + network_change_notifier_.reset(net::NetworkChangeNotifier::CreateMock()); + host_resolver_proc_ = new net::RuleBasedHostResolverProc(NULL); scoped_host_resolver_proc_.Init(host_resolver_proc_.get()); // In case any attempts are made to resolve host names, force them all to @@ -44,6 +46,7 @@ class NetTestSuite : public TestSuite { } private: + scoped_ptr<net::NetworkChangeNotifier> network_change_notifier_; scoped_ptr<MessageLoop> message_loop_; scoped_refptr<net::RuleBasedHostResolverProc> host_resolver_proc_; net::ScopedDefaultHostResolverProc scoped_host_resolver_proc_; diff --git a/net/base/network_change_notifier.cc b/net/base/network_change_notifier.cc index aeca2ab..a0bc6b5 100644 --- a/net/base/network_change_notifier.cc +++ b/net/base/network_change_notifier.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -14,9 +14,22 @@ namespace net { -// static -NetworkChangeNotifier* -NetworkChangeNotifier::CreateDefaultNetworkChangeNotifier() { +namespace { + +// The actual singleton notifier. The class contract forbids usage of the API +// in ways that would require us to place locks around access to this object. +// (The prohibition on global non-POD objects makes it tricky to do such a thing +// anyway.) +NetworkChangeNotifier* g_network_change_notifier = NULL; + +} // namespace + +NetworkChangeNotifier::~NetworkChangeNotifier() { + DCHECK_EQ(this, g_network_change_notifier); + g_network_change_notifier = NULL; +} + +NetworkChangeNotifier* NetworkChangeNotifier::Create() { #if defined(OS_WIN) return new NetworkChangeNotifierWin(); #elif defined(OS_LINUX) @@ -29,4 +42,27 @@ NetworkChangeNotifier::CreateDefaultNetworkChangeNotifier() { #endif } +void NetworkChangeNotifier::AddObserver(Observer* observer) { + if (g_network_change_notifier) + g_network_change_notifier->observer_list_->AddObserver(observer); +} + +void NetworkChangeNotifier::RemoveObserver(Observer* observer) { + if (g_network_change_notifier) + g_network_change_notifier->observer_list_->RemoveObserver(observer); +} + +NetworkChangeNotifier::NetworkChangeNotifier() + : observer_list_(new ObserverListThreadSafe<Observer>()) { + DCHECK(!g_network_change_notifier); + g_network_change_notifier = this; +} + +void NetworkChangeNotifier::NotifyObserversOfIPAddressChange() { + if (g_network_change_notifier) { + g_network_change_notifier->observer_list_->Notify( + &Observer::OnIPAddressChanged); + } +} + } // namespace net diff --git a/net/base/network_change_notifier.h b/net/base/network_change_notifier.h index 70b195d..e0a8800 100644 --- a/net/base/network_change_notifier.h +++ b/net/base/network_change_notifier.h @@ -6,11 +6,13 @@ #define NET_BASE_NETWORK_CHANGE_NOTIFIER_H_ #include "base/basictypes.h" +#include "base/observer_list_threadsafe.h" namespace net { // NetworkChangeNotifier monitors the system for network changes, and notifies -// observers on those events. +// registered observers of those events. Observers may register on any thread, +// and will be called back on the thread from which they registered. class NetworkChangeNotifier { public: class Observer { @@ -28,21 +30,58 @@ class NetworkChangeNotifier { DISALLOW_COPY_AND_ASSIGN(Observer); }; - NetworkChangeNotifier() {} - virtual ~NetworkChangeNotifier() {} + virtual ~NetworkChangeNotifier(); - // These functions add and remove observers to/from the NetworkChangeNotifier. - // Each call to AddObserver() must be matched with a corresponding call to - // RemoveObserver() with the same parameter. Observers must remove themselves - // before they get deleted, otherwise the NetworkChangeNotifier may try to - // notify the wrong object. - virtual void AddObserver(Observer* observer) = 0; - virtual void RemoveObserver(Observer* observer) = 0; + // Creates the process-wide, platform-specific NetworkChangeNotifier. The + // caller owns the returned pointer. You may call this on any thread. You + // may also avoid creating this entirely (in which case nothing will be + // monitored), but if you do create it, you must do so before any other + // threads try to access the API below, and it must outlive all other threads + // which might try to use it. + static NetworkChangeNotifier* Create(); - // This will create the platform specific default NetworkChangeNotifier. - static NetworkChangeNotifier* CreateDefaultNetworkChangeNotifier(); +#ifdef UNIT_TEST + // Like Create(), but for use in tests. The mock object doesn't monitor any + // events, it merely rebroadcasts notifications when requested. + static NetworkChangeNotifier* CreateMock() { + return new NetworkChangeNotifier(); + } +#endif + + // Registers |observer| to receive notifications of network changes. The + // thread on which this is called is the thread on which |observer| will be + // called back with notifications. This is safe to call if Create() has not + // been called (as long as it doesn't race the Create() call on another + // thread), in which case it will simply do nothing. + static void AddObserver(Observer* observer); + + // Unregisters |observer| from receiving notifications. This must be called + // on the same thread on which AddObserver() was called. Like AddObserver(), + // this is safe to call if Create() has not been called (as long as it doesn't + // race the Create() call on another thread), in which case it will simply do + // nothing. Technically, it's also safe to call after the notifier object has + // been destroyed, if the call doesn't race the notifier's destruction, but + // there's no reason to use the API in this risky way, so don't do it. + static void RemoveObserver(Observer* observer); + +#ifdef UNIT_TEST + // Allow unit tests to trigger notifications. + static void NotifyObserversOfIPAddressChangeForTests() { + NotifyObserversOfIPAddressChange(); + } +#endif + + protected: + NetworkChangeNotifier(); + + // Broadcasts a notification to all registered observers. Note that this + // happens asynchronously, even for observers on the current thread, even in + // tests. + static void NotifyObserversOfIPAddressChange(); private: + const scoped_refptr<ObserverListThreadSafe<Observer> > observer_list_; + DISALLOW_COPY_AND_ASSIGN(NetworkChangeNotifier); }; diff --git a/net/base/network_change_notifier_linux.cc b/net/base/network_change_notifier_linux.cc index 9821be5..aa58c14 100644 --- a/net/base/network_change_notifier_linux.cc +++ b/net/base/network_change_notifier_linux.cc @@ -7,13 +7,15 @@ #include <errno.h> #include <sys/socket.h> -#include "base/basictypes.h" #include "base/eintr_wrapper.h" -#include "base/logging.h" -#include "base/message_loop.h" +#include "base/task.h" +#include "base/thread.h" #include "net/base/net_errors.h" #include "net/base/network_change_notifier_netlink_linux.h" +// We only post tasks to a child thread we own, so we don't need refcounting. +DISABLE_RUNNABLE_METHOD_REFCOUNT(net::NetworkChangeNotifierLinux); + namespace net { namespace { @@ -23,122 +25,115 @@ const int kInvalidSocket = -1; } // namespace NetworkChangeNotifierLinux::NetworkChangeNotifierLinux() - : netlink_fd_(kInvalidSocket), -#if defined(OS_CHROMEOS) - ALLOW_THIS_IN_INITIALIZER_LIST(factory_(this)), -#endif - loop_(MessageLoopForIO::current()) { - netlink_fd_ = InitializeNetlinkSocket(); - if (netlink_fd_ < 0) { - netlink_fd_ = kInvalidSocket; - return; - } - - ListenForNotifications(); - loop_->AddDestructionObserver(this); + : notifier_thread_(new base::Thread("NetworkChangeNotifier")), + netlink_fd_(kInvalidSocket) { + // We create this notifier thread because the notification implementation + // needs a MessageLoopForIO, and there's no guarantee that + // MessageLoop::current() meets that criterion. + base::Thread::Options thread_options(MessageLoop::TYPE_IO, 0); + notifier_thread_->StartWithOptions(thread_options); + notifier_thread_->message_loop()->PostTask(FROM_HERE, + NewRunnableMethod(this, &NetworkChangeNotifierLinux::Init)); } NetworkChangeNotifierLinux::~NetworkChangeNotifierLinux() { - DCHECK(CalledOnValidThread()); - StopWatching(); - - if (loop_) - loop_->RemoveDestructionObserver(this); + // We don't need to explicitly Stop(), but doing so allows us to sanity- + // check that the notifier thread shut down properly. + notifier_thread_->Stop(); + DCHECK_EQ(kInvalidSocket, netlink_fd_); } -void NetworkChangeNotifierLinux::AddObserver(Observer* observer) { - DCHECK(CalledOnValidThread()); - observers_.AddObserver(observer); -} +void NetworkChangeNotifierLinux::WillDestroyCurrentMessageLoop() { + DCHECK(notifier_thread_ != NULL); + // We can't check the notifier_thread_'s message_loop(), as it's now 0. + // DCHECK_EQ(notifier_thread_->message_loop(), MessageLoop::current()); -void NetworkChangeNotifierLinux::RemoveObserver(Observer* observer) { - DCHECK(CalledOnValidThread()); - observers_.RemoveObserver(observer); + if (netlink_fd_ != kInvalidSocket) { + if (HANDLE_EINTR(close(netlink_fd_)) != 0) + PLOG(ERROR) << "Failed to close socket"; + netlink_fd_ = kInvalidSocket; + netlink_watcher_.StopWatchingFileDescriptor(); + } } void NetworkChangeNotifierLinux::OnFileCanReadWithoutBlocking(int fd) { - DCHECK(CalledOnValidThread()); - DCHECK_EQ(fd, netlink_fd_); + DCHECK(notifier_thread_ != NULL); + DCHECK_EQ(notifier_thread_->message_loop(), MessageLoop::current()); + DCHECK_EQ(fd, netlink_fd_); ListenForNotifications(); } void NetworkChangeNotifierLinux::OnFileCanWriteWithoutBlocking(int /* fd */) { - DCHECK(CalledOnValidThread()); + DCHECK(notifier_thread_ != NULL); + DCHECK_EQ(notifier_thread_->message_loop(), MessageLoop::current()); + NOTREACHED(); } -void NetworkChangeNotifierLinux::WillDestroyCurrentMessageLoop() { - DCHECK(CalledOnValidThread()); - StopWatching(); - loop_ = NULL; +void NetworkChangeNotifierLinux::Init() { + DCHECK(notifier_thread_ != NULL); + DCHECK_EQ(notifier_thread_->message_loop(), MessageLoop::current()); + + netlink_fd_ = InitializeNetlinkSocket(); + if (netlink_fd_ < 0) { + netlink_fd_ = kInvalidSocket; + return; + } + MessageLoop::current()->AddDestructionObserver(this); + ListenForNotifications(); } void NetworkChangeNotifierLinux::ListenForNotifications() { - DCHECK(CalledOnValidThread()); + DCHECK(notifier_thread_ != NULL); + DCHECK_EQ(notifier_thread_->message_loop(), MessageLoop::current()); + char buf[4096]; int rv = ReadNotificationMessage(buf, arraysize(buf)); - while (rv > 0 ) { + while (rv > 0) { if (HandleNetlinkMessage(buf, rv)) { LOG(INFO) << "Detected IP address changes."; - #if defined(OS_CHROMEOS) // TODO(zelidrag): chromium-os:3996 - introduced artificial delay to // work around the issue of proxy initialization before name resolving // is functional in ChromeOS. This should be removed once this bug // is properly fixed. - MessageLoop::current()->PostDelayedTask( - FROM_HERE, - factory_.NewRunnableMethod( - &NetworkChangeNotifierLinux::NotifyObserversIPAddressChanged), - 500); + const int kObserverNotificationDelayMS = 500; + MessageLoop::current()->PostDelayedTask(FROM_HERE, NewRunnableMethod( + &NetworkChangeNotifier::NotifyObserversOfIPAddressChange), + kObserverNotificationDelayMS); #else - NotifyObserversIPAddressChanged(); + NotifyObserversOfIPAddressChange(); #endif } rv = ReadNotificationMessage(buf, arraysize(buf)); } if (rv == ERR_IO_PENDING) { - rv = loop_->WatchFileDescriptor( - netlink_fd_, false, MessageLoopForIO::WATCH_READ, &netlink_watcher_, - this); + rv = MessageLoopForIO::current()->WatchFileDescriptor(netlink_fd_, false, + MessageLoopForIO::WATCH_READ, &netlink_watcher_, this); LOG_IF(ERROR, !rv) << "Failed to watch netlink socket: " << netlink_fd_; } } -void NetworkChangeNotifierLinux::NotifyObserversIPAddressChanged() { - FOR_EACH_OBSERVER(Observer, observers_, OnIPAddressChanged()); -} - int NetworkChangeNotifierLinux::ReadNotificationMessage(char* buf, size_t len) { - DCHECK(CalledOnValidThread()); + DCHECK(notifier_thread_ != NULL); + DCHECK_EQ(notifier_thread_->message_loop(), MessageLoop::current()); + DCHECK_NE(len, 0u); DCHECK(buf); - memset(buf, 0, sizeof(buf)); int rv = recv(netlink_fd_, buf, len, 0); - if (rv > 0) { + if (rv > 0) return rv; - } else { - DCHECK_NE(rv, 0); - if (errno != EAGAIN && errno != EWOULDBLOCK) { - PLOG(DFATAL) << "recv"; - return ERR_FAILED; - } - return ERR_IO_PENDING; + DCHECK_NE(rv, 0); + if (errno != EAGAIN && errno != EWOULDBLOCK) { + PLOG(DFATAL) << "recv"; + return ERR_FAILED; } -} -void NetworkChangeNotifierLinux::StopWatching() { - DCHECK(CalledOnValidThread()); - if (netlink_fd_ != kInvalidSocket) { - if (HANDLE_EINTR(close(netlink_fd_)) != 0) - PLOG(ERROR) << "Failed to close socket"; - netlink_fd_ = kInvalidSocket; - netlink_watcher_.StopWatchingFileDescriptor(); - } + return ERR_IO_PENDING; } } // namespace net diff --git a/net/base/network_change_notifier_linux.h b/net/base/network_change_notifier_linux.h index dcedbf4..aca9377 100644 --- a/net/base/network_change_notifier_linux.h +++ b/net/base/network_change_notifier_linux.h @@ -7,37 +7,34 @@ #include "base/basictypes.h" #include "base/message_loop.h" -#include "base/non_thread_safe.h" -#include "base/observer_list.h" +#include "base/scoped_ptr.h" #include "net/base/network_change_notifier.h" -#if defined(OS_CHROMEOS) -#include "base/task.h" -#endif +namespace base { +class Thread; +} namespace net { -class NetworkChangeNotifierLinux - : public NetworkChangeNotifier, - public NonThreadSafe, - public MessageLoopForIO::Watcher, - public MessageLoop::DestructionObserver { +class NetworkChangeNotifierLinux : public MessageLoop::DestructionObserver, + public MessageLoopForIO::Watcher, + public NetworkChangeNotifier { public: NetworkChangeNotifierLinux(); - // NetworkChangeNotifier methods: - virtual void AddObserver(Observer* observer); - virtual void RemoveObserver(Observer* observer); + private: + virtual ~NetworkChangeNotifierLinux(); + + // MessageLoop::DestructionObserver: + virtual void WillDestroyCurrentMessageLoop(); - // MessageLoopForIO::Watcher methods: + // MessageLoopForIO::Watcher: virtual void OnFileCanReadWithoutBlocking(int fd); virtual void OnFileCanWriteWithoutBlocking(int /* fd */); - // MessageLoop::DestructionObserver methods: - virtual void WillDestroyCurrentMessageLoop(); - - private: - virtual ~NetworkChangeNotifierLinux(); + // Called on the notifier thread to initialize the notification + // implementation. + void Init(); // Starts listening for netlink messages. Also handles the messages if there // are any available on the netlink socket. @@ -48,21 +45,14 @@ class NetworkChangeNotifierLinux // recv() would block. Otherwise, it returns a net error code. int ReadNotificationMessage(char* buf, size_t len); - // Stops watching the netlink file descriptor. - void StopWatching(); - - void NotifyObserversIPAddressChanged(); - - // http://crbug.com/36890. - ObserverList<Observer, false> observers_; - - int netlink_fd_; // This is the netlink socket descriptor. + // The thread used to listen for notifications. This relays the notification + // to the registered observers without posting back to the thread the object + // was created on. + scoped_ptr<base::Thread> notifier_thread_; -#if defined(OS_CHROMEOS) - ScopedRunnableMethodFactory<NetworkChangeNotifierLinux> factory_; -#endif + // The netlink socket descriptor. + int netlink_fd_; - MessageLoopForIO* loop_; MessageLoopForIO::FileDescriptorWatcher netlink_watcher_; DISALLOW_COPY_AND_ASSIGN(NetworkChangeNotifierLinux); diff --git a/net/base/network_change_notifier_mac.cc b/net/base/network_change_notifier_mac.cc index ba38907..797de6d 100644 --- a/net/base/network_change_notifier_mac.cc +++ b/net/base/network_change_notifier_mac.cc @@ -2,168 +2,116 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// There are three classes involved here. There's NetworkChangeNotifierMac, -// which is the Mac specific implementation of NetworkChangeNotifier. It is the -// class with which clients can register themselves as network change -// observers. There's NetworkChangeNotifierThread, which is a base::Thread -// subclass of MessageLoop::TYPE_UI (since it needs a CFRunLoop) that contains -// the NetworkChangeNotifierImpl. NetworkChangeNotifierImpl is the object -// that receives the actual OS X notifications and posts them to the -// NetworkChangeNotifierMac's message loop, so that NetworkChangeNotifierMac -// can notify all its observers. -// -// When NetworkChangeNotifierMac is being deleted, it will delete the -// NetworkChangeNotifierThread, which will Stop() it and also delete the -// NetworkChangeNotifierImpl. Therefore, NetworkChangeNotifierImpl and -// NetworkChangeNotifierThread's lifetimes generally begin after and end before -// NetworkChangeNotifierMac. There is an edge case where a notification task -// gets posted to the IO thread, thereby maintaining a reference to -// NetworkChangeNotifierImpl beyond the lifetime of NetworkChangeNotifierThread. -// In this case, the notification is cancelled, and NetworkChangeNotifierImpl -// will be deleted once all notification tasks that reference it have been run. - #include "net/base/network_change_notifier_mac.h" -#include <SystemConfiguration/SCDynamicStore.h> + #include <SystemConfiguration/SCDynamicStoreKey.h> #include <SystemConfiguration/SCSchemaDefinitions.h> #include <algorithm> -#include "base/logging.h" -#include "base/message_loop.h" -#include "base/scoped_cftyperef.h" -#include "base/thread.h" - -namespace net { -namespace { - -// NetworkChangeNotifierImpl should be created on a thread with a CFRunLoop, -// since it requires one to pump notifications. However, it also runs some -// methods on |notifier_loop_|, because it cannot post calls to |notifier_| -// since NetworkChangeNotifier is not ref counted in a thread safe manner. -class NetworkChangeNotifierImpl - : public base::RefCountedThreadSafe<NetworkChangeNotifierImpl> { - public: - NetworkChangeNotifierImpl(MessageLoop* notifier_loop, - NetworkChangeNotifierMac* notifier); +#include "base/thread.h" - void Shutdown(); +// We only post tasks to a child thread we own, so we don't need refcounting. +DISABLE_RUNNABLE_METHOD_REFCOUNT(net::NetworkChangeNotifierMac); - private: - friend class base::RefCountedThreadSafe<NetworkChangeNotifierImpl>; - ~NetworkChangeNotifierImpl(); +namespace net { - static void DynamicStoreCallback(SCDynamicStoreRef /* store */, - CFArrayRef changed_keys, - void* config); +NetworkChangeNotifierMac::NetworkChangeNotifierMac() + : notifier_thread_(new base::Thread("NetworkChangeNotifier")) { + // We create this notifier thread because the notification implementation + // needs a thread with a CFRunLoop, and there's no guarantee that + // MessageLoop::current() meets that criterion. + base::Thread::Options thread_options(MessageLoop::TYPE_UI, 0); + notifier_thread_->StartWithOptions(thread_options); + // TODO(willchan): Look to see if there's a better signal for when it's ok to + // initialize this, rather than just delaying it by a fixed time. + const int kNotifierThreadInitializationDelayMS = 1000; + notifier_thread_->message_loop()->PostDelayedTask(FROM_HERE, + NewRunnableMethod(this, &NetworkChangeNotifierMac::Init), + kNotifierThreadInitializationDelayMS); +} - void OnNetworkConfigChange(CFArrayRef changed_keys); +NetworkChangeNotifierMac::~NetworkChangeNotifierMac() { + // We don't need to explicitly Stop(), but doing so allows us to sanity- + // check that the notifier thread shut down properly. + notifier_thread_->Stop(); + DCHECK(run_loop_source_ == NULL); +} - // Runs on |notifier_loop_|. - void OnIPAddressChanged(); +// static +void NetworkChangeNotifierMac::DynamicStoreCallback( + SCDynamicStoreRef /* store */, + CFArrayRef changed_keys, + void* config) { + NetworkChangeNotifierMac* net_config = + static_cast<NetworkChangeNotifierMac*>(config); + net_config->OnNetworkConfigChange(changed_keys); +} - // Raw pointers. Note that |notifier_| _must_ outlive the - // NetworkChangeNotifierImpl. For lifecycle management details, read the - // comment at the top of the file. - MessageLoop* const notifier_loop_; - NetworkChangeNotifierMac* notifier_; +void NetworkChangeNotifierMac::WillDestroyCurrentMessageLoop() { + DCHECK(notifier_thread_ != NULL); + // We can't check the notifier_thread_'s message_loop(), as it's now 0. + // DCHECK_EQ(notifier_thread_->message_loop(), MessageLoop::current()); - scoped_cftyperef<CFRunLoopSourceRef> source_; + DCHECK(run_loop_source_ != NULL); + CFRunLoopRemoveSource(CFRunLoopGetCurrent(), run_loop_source_.get(), + kCFRunLoopCommonModes); + run_loop_source_.reset(); +} - DISALLOW_COPY_AND_ASSIGN(NetworkChangeNotifierImpl); -}; +void NetworkChangeNotifierMac::Init() { + DCHECK(notifier_thread_ != NULL); + DCHECK_EQ(notifier_thread_->message_loop(), MessageLoop::current()); -NetworkChangeNotifierImpl::NetworkChangeNotifierImpl( - MessageLoop* notifier_loop, NetworkChangeNotifierMac* notifier) - : notifier_loop_(notifier_loop), - notifier_(notifier) { - DCHECK_EQ(MessageLoop::TYPE_UI, MessageLoop::current()->type()); + // Add a run loop source for a dynamic store to the current run loop. SCDynamicStoreContext context = { - 0, // Version 0. - this, // User data. - NULL, // This is not reference counted. No retain function. - NULL, // This is not reference counted. No release function. - NULL, // No description for this. + 0, // Version 0. + this, // User data. + NULL, // This is not reference counted. No retain function. + NULL, // This is not reference counted. No release function. + NULL, // No description for this. }; - - // Get a reference to the dynamic store. - scoped_cftyperef<SCDynamicStoreRef> store( - SCDynamicStoreCreate(NULL /* use default allocator */, - CFSTR("org.chromium"), - DynamicStoreCallback, &context)); - - // Create a run loop source for the dynamic store. - source_.reset(SCDynamicStoreCreateRunLoopSource( - NULL /* use default allocator */, - store.get(), - 0 /* 0 sounds like a fine source order to me! */)); - - // Add the run loop source to the current run loop. - CFRunLoopAddSource(CFRunLoopGetCurrent(), - source_.get(), + scoped_cftyperef<SCDynamicStoreRef> store(SCDynamicStoreCreate( + NULL, CFSTR("org.chromium"), DynamicStoreCallback, &context)); + run_loop_source_.reset(SCDynamicStoreCreateRunLoopSource( + NULL, store.get(), 0)); + CFRunLoopAddSource(CFRunLoopGetCurrent(), run_loop_source_.get(), kCFRunLoopCommonModes); - // Set up the notification keys. + // Set up notifications for interface and IP address changes. scoped_cftyperef<CFMutableArrayRef> notification_keys( CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks)); - - // Monitor interface changes. - scoped_cftyperef<CFStringRef> key( - SCDynamicStoreKeyCreateNetworkGlobalEntity( - NULL /* default allocator */, kSCDynamicStoreDomainState, - kSCEntNetInterface)); + scoped_cftyperef<CFStringRef> key(SCDynamicStoreKeyCreateNetworkGlobalEntity( + NULL, kSCDynamicStoreDomainState, kSCEntNetInterface)); CFArrayAppendValue(notification_keys.get(), key.get()); - - // Monitor IP address changes. - key.reset(SCDynamicStoreKeyCreateNetworkGlobalEntity( - NULL /* default allocator */, kSCDynamicStoreDomainState, - kSCEntNetIPv4)); + NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4)); CFArrayAppendValue(notification_keys.get(), key.get()); - key.reset(SCDynamicStoreKeyCreateNetworkGlobalEntity( - NULL /* default allocator */, kSCDynamicStoreDomainState, - kSCEntNetIPv6)); + NULL, kSCDynamicStoreDomainState, kSCEntNetIPv6)); CFArrayAppendValue(notification_keys.get(), key.get()); - // Ok, let's ask for notifications! + // Set the notification keys. This starts us receiving notifications. + bool ret = SCDynamicStoreSetNotificationKeys( + store.get(), notification_keys.get(), NULL); // TODO(willchan): Figure out a proper way to handle this rather than crash. - CHECK(SCDynamicStoreSetNotificationKeys( - store.get(), notification_keys.get(), NULL)); -} + CHECK(ret); -NetworkChangeNotifierImpl::~NetworkChangeNotifierImpl() { - CFRunLoopRemoveSource(CFRunLoopGetCurrent(), - source_.get(), - kCFRunLoopCommonModes); -} - -void NetworkChangeNotifierImpl::Shutdown() { - CHECK(notifier_); - notifier_ = NULL; + MessageLoop::current()->AddDestructionObserver(this); } -// static -void NetworkChangeNotifierImpl::DynamicStoreCallback( - SCDynamicStoreRef /* store */, - CFArrayRef changed_keys, - void* config) { - NetworkChangeNotifierImpl* net_config = - static_cast<NetworkChangeNotifierImpl*>(config); - net_config->OnNetworkConfigChange(changed_keys); -} +void NetworkChangeNotifierMac::OnNetworkConfigChange(CFArrayRef changed_keys) { + DCHECK(notifier_thread_ != NULL); + DCHECK_EQ(notifier_thread_->message_loop(), MessageLoop::current()); -void NetworkChangeNotifierImpl::OnNetworkConfigChange(CFArrayRef changed_keys) { for (CFIndex i = 0; i < CFArrayGetCount(changed_keys); ++i) { CFStringRef key = static_cast<CFStringRef>( CFArrayGetValueAtIndex(changed_keys, i)); if (CFStringHasSuffix(key, kSCEntNetIPv4) || CFStringHasSuffix(key, kSCEntNetIPv6)) { - notifier_loop_->PostTask( - FROM_HERE, - NewRunnableMethod( - this, - &NetworkChangeNotifierImpl::OnIPAddressChanged)); - } else if (CFStringHasSuffix(key, kSCEntNetInterface)) { + NotifyObserversOfIPAddressChange(); + return; + } + if (CFStringHasSuffix(key, kSCEntNetInterface)) { // TODO(willchan): Does not appear to be working. Look into this. // Perhaps this isn't needed anyway. } else { @@ -172,91 +120,4 @@ void NetworkChangeNotifierImpl::OnNetworkConfigChange(CFArrayRef changed_keys) { } } -void NetworkChangeNotifierImpl::OnIPAddressChanged() { - // If |notifier_| doesn't exist, then that means we're shutting down, so - // notifications are all cancelled. - if (notifier_) - notifier_->OnIPAddressChanged(); -} - -class NetworkChangeNotifierThread : public base::Thread { - public: - NetworkChangeNotifierThread(MessageLoop* notifier_loop, - NetworkChangeNotifierMac* notifier); - ~NetworkChangeNotifierThread(); - - protected: - virtual void Init(); - - private: - MessageLoop* const notifier_loop_; - NetworkChangeNotifierMac* const notifier_; - scoped_refptr<NetworkChangeNotifierImpl> notifier_impl_; - - DISALLOW_COPY_AND_ASSIGN(NetworkChangeNotifierThread); -}; - -NetworkChangeNotifierThread::NetworkChangeNotifierThread( - MessageLoop* notifier_loop, NetworkChangeNotifierMac* notifier) - : base::Thread("NetworkChangeNotifier"), - notifier_loop_(notifier_loop), - notifier_(notifier) {} - -NetworkChangeNotifierThread::~NetworkChangeNotifierThread() { - notifier_impl_->Shutdown(); - Stop(); -} - -// Note that |notifier_impl_| is initialized on the network change -// notifier thread, not whatever thread constructs the -// NetworkChangeNotifierThread object. This is important, because this thread -// is the one that has a CFRunLoop. -void NetworkChangeNotifierThread::Init() { - notifier_impl_ = - new NetworkChangeNotifierImpl(notifier_loop_, notifier_); -} - -} // namespace - -NetworkChangeNotifierMac::NetworkChangeNotifierMac() - : notifier_thread_(NULL), - method_factory_(this) { - // TODO(willchan): Look to see if there's a better signal for when it's ok to - // initialize this, rather than just delaying it by a fixed time. - const int kNotifierThreadInitializationDelayMS = 1000; - MessageLoop* loop = MessageLoop::current(); - loop->PostDelayedTask( - FROM_HERE, - method_factory_.NewRunnableMethod( - &NetworkChangeNotifierMac::InitializeNotifierThread, loop), - kNotifierThreadInitializationDelayMS); -} - -void NetworkChangeNotifierMac::OnIPAddressChanged() { - DCHECK(CalledOnValidThread()); - FOR_EACH_OBSERVER(Observer, observers_, OnIPAddressChanged()); -} - -void NetworkChangeNotifierMac::AddObserver(Observer* observer) { - DCHECK(CalledOnValidThread()); - observers_.AddObserver(observer); -} - -void NetworkChangeNotifierMac::RemoveObserver(Observer* observer) { - DCHECK(CalledOnValidThread()); - observers_.RemoveObserver(observer); -} - -NetworkChangeNotifierMac::~NetworkChangeNotifierMac() { - DCHECK(CalledOnValidThread()); -} - -void NetworkChangeNotifierMac::InitializeNotifierThread(MessageLoop* loop) { - DCHECK(CalledOnValidThread()); - notifier_thread_.reset(new NetworkChangeNotifierThread(loop, this)); - base::Thread::Options thread_options; - thread_options.message_loop_type = MessageLoop::TYPE_UI; - notifier_thread_->StartWithOptions(thread_options); -} - } // namespace net diff --git a/net/base/network_change_notifier_mac.h b/net/base/network_change_notifier_mac.h index 2ffaaba..c85f244 100644 --- a/net/base/network_change_notifier_mac.h +++ b/net/base/network_change_notifier_mac.h @@ -5,52 +5,52 @@ #ifndef NET_BASE_NETWORK_CHANGE_NOTIFIER_MAC_H_ #define NET_BASE_NETWORK_CHANGE_NOTIFIER_MAC_H_ +#include <SystemConfiguration/SCDynamicStore.h> + #include "base/basictypes.h" -#include "base/non_thread_safe.h" -#include "base/observer_list.h" -#include "base/ref_counted.h" +#include "base/message_loop.h" +#include "base/scoped_cftyperef.h" #include "base/scoped_ptr.h" -#include "base/task.h" #include "net/base/network_change_notifier.h" -class MessageLoop; namespace base { class Thread; -} // namespace base +} namespace net { -class NetworkChangeNotifierMac : public NetworkChangeNotifier, - public NonThreadSafe { +class NetworkChangeNotifierMac : public MessageLoop::DestructionObserver, + public NetworkChangeNotifier { public: NetworkChangeNotifierMac(); - void OnIPAddressChanged(); + private: + virtual ~NetworkChangeNotifierMac(); - // NetworkChangeNotifier methods: - virtual void AddObserver(Observer* observer); - virtual void RemoveObserver(Observer* observer); + // Called back by OS. Calls OnNetworkConfigChange(). + static void DynamicStoreCallback(SCDynamicStoreRef /* store */, + CFArrayRef changed_keys, + void* config); - private: - friend class base::RefCounted<NetworkChangeNotifierMac>; + // MessageLoop::DestructionObserver: + virtual void WillDestroyCurrentMessageLoop(); - virtual ~NetworkChangeNotifierMac(); + // Called on the notifier thread to initialize the notification + // implementation. The SystemConfiguration calls in this function can lead to + // contention early on, so we invoke this function later on in startup to keep + // it fast. + void Init(); - // Initializes the notifier thread. The SystemConfiguration calls in this - // function can lead to contention early on, so we invoke this function later - // on in startup to keep it fast. - // See http://crbug.com/34926 for details. - void InitializeNotifierThread(MessageLoop* loop); + // Called by DynamicStoreCallback() when something about the network config + // changes. + void OnNetworkConfigChange(CFArrayRef changed_keys); - // Receives the OS X network change notifications on this thread. + // The thread used to listen for notifications. This relays the notification + // to the registered observers without posting back to the thread the object + // was created on. scoped_ptr<base::Thread> notifier_thread_; - // TODO(willchan): Fix the URLRequestContextGetter leaks and flip the false to - // true so we assert that all observers have been removed. - ObserverList<Observer, false> observers_; - - // Used to initialize the notifier thread. - ScopedRunnableMethodFactory<NetworkChangeNotifierMac> method_factory_; + scoped_cftyperef<CFRunLoopSourceRef> run_loop_source_; DISALLOW_COPY_AND_ASSIGN(NetworkChangeNotifierMac); }; diff --git a/net/base/network_change_notifier_win.cc b/net/base/network_change_notifier_win.cc index bed361c..e0e0892 100644 --- a/net/base/network_change_notifier_win.cc +++ b/net/base/network_change_notifier_win.cc @@ -5,84 +5,35 @@ #include "net/base/network_change_notifier_win.h" #include <iphlpapi.h> -#include <windows.h> #include <winsock2.h> -#include "base/basictypes.h" -#include "base/compiler_specific.h" -#include "base/logging.h" -#include "base/object_watcher.h" +#pragma comment(lib, "iphlpapi.lib") namespace net { -class NetworkChangeNotifierWin::Impl - : public base::ObjectWatcher::Delegate { - public: - explicit Impl(NetworkChangeNotifierWin* notifier); - virtual ~Impl(); - - void WatchForAddressChange(); - - // ObjectWatcher::Delegate methods: - - virtual void OnObjectSignaled(HANDLE object); - - private: - NetworkChangeNotifierWin* const notifier_; - base::ObjectWatcher addr_watcher_; - OVERLAPPED addr_overlapped_; - - DISALLOW_COPY_AND_ASSIGN(Impl); -}; - -NetworkChangeNotifierWin::Impl::Impl(NetworkChangeNotifierWin* notifier) - : notifier_(notifier) { - memset(&addr_overlapped_, 0, sizeof(addr_overlapped_)); +NetworkChangeNotifierWin::NetworkChangeNotifierWin() { + memset(&addr_overlapped_, 0, sizeof addr_overlapped_); addr_overlapped_.hEvent = WSACreateEvent(); } -NetworkChangeNotifierWin::Impl::~Impl() { +NetworkChangeNotifierWin::~NetworkChangeNotifierWin() { CancelIPChangeNotify(&addr_overlapped_); addr_watcher_.StopWatching(); WSACloseEvent(addr_overlapped_.hEvent); - memset(&addr_overlapped_, 0, sizeof(addr_overlapped_)); -} - -void NetworkChangeNotifierWin::Impl::WatchForAddressChange() { - HANDLE handle = NULL; - DWORD ret = NotifyAddrChange(&handle, &addr_overlapped_); - CHECK(ret == ERROR_IO_PENDING); - addr_watcher_.StartWatching(addr_overlapped_.hEvent, this); } -void NetworkChangeNotifierWin::Impl::OnObjectSignaled(HANDLE object) { - notifier_->OnIPAddressChanged(); +void NetworkChangeNotifierWin::OnObjectSignaled(HANDLE object) { + NotifyObserversOfIPAddressChange(); - // Start watching for further address changes. + // Start watching for the next address change. WatchForAddressChange(); } -NetworkChangeNotifierWin::NetworkChangeNotifierWin() - : impl_(new Impl(ALLOW_THIS_IN_INITIALIZER_LIST(this))) { - impl_->WatchForAddressChange(); -} -void NetworkChangeNotifierWin::OnIPAddressChanged() { - DCHECK(CalledOnValidThread()); - FOR_EACH_OBSERVER(Observer, observers_, OnIPAddressChanged()); -} - -void NetworkChangeNotifierWin::AddObserver(Observer* observer) { - DCHECK(CalledOnValidThread()); - observers_.AddObserver(observer); -} - -void NetworkChangeNotifierWin::RemoveObserver(Observer* observer) { - DCHECK(CalledOnValidThread()); - observers_.RemoveObserver(observer); -} - -NetworkChangeNotifierWin::~NetworkChangeNotifierWin() { - DCHECK(CalledOnValidThread()); +void NetworkChangeNotifierWin::WatchForAddressChange() { + HANDLE handle = NULL; + DWORD ret = NotifyAddrChange(&handle, &addr_overlapped_); + CHECK(ret == ERROR_IO_PENDING); + addr_watcher_.StartWatching(addr_overlapped_.hEvent, this); } } // namespace net diff --git a/net/base/network_change_notifier_win.h b/net/base/network_change_notifier_win.h index ba2f53dc..2077ca8 100644 --- a/net/base/network_change_notifier_win.h +++ b/net/base/network_change_notifier_win.h @@ -5,35 +5,30 @@ #ifndef NET_BASE_NETWORK_CHANGE_NOTIFIER_WIN_H_ #define NET_BASE_NETWORK_CHANGE_NOTIFIER_WIN_H_ +#include <windows.h> + #include "base/basictypes.h" -#include "base/non_thread_safe.h" #include "base/object_watcher.h" -#include "base/observer_list.h" #include "net/base/network_change_notifier.h" namespace net { class NetworkChangeNotifierWin : public NetworkChangeNotifier, - public NonThreadSafe { + public base::ObjectWatcher::Delegate { public: NetworkChangeNotifierWin(); - // Called by NetworkChangeNotifierWin::Impl. - void OnIPAddressChanged(); - - // NetworkChangeNotifier methods: - virtual void AddObserver(Observer* observer); - virtual void RemoveObserver(Observer* observer); - private: - class Impl; - virtual ~NetworkChangeNotifierWin(); - // TODO(willchan): Fix the URLRequestContextGetter leaks and flip the false to - // true so we assert that all observers have been removed. - ObserverList<Observer, false> observers_; - scoped_ptr<Impl> impl_; + // ObjectWatcher::Delegate methods: + virtual void OnObjectSignaled(HANDLE object); + + // Begins listening for a single subsequent address change. + void WatchForAddressChange(); + + base::ObjectWatcher addr_watcher_; + OVERLAPPED addr_overlapped_; DISALLOW_COPY_AND_ASSIGN(NetworkChangeNotifierWin); }; |