summaryrefslogtreecommitdiffstats
path: root/net/base
diff options
context:
space:
mode:
authorpkasting@chromium.org <pkasting@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-06-25 21:30:38 +0000
committerpkasting@chromium.org <pkasting@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-06-25 21:30:38 +0000
commit66761b95332549f825999e482c17c94675275f49 (patch)
treefc5307808a2c62f1eff2a9f37db3aff11c5455d9 /net/base
parente313f3b11360902a3da9b3b1cc0df2a4792d0867 (diff)
downloadchromium_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.h6
-rw-r--r--net/base/host_resolver_impl.cc16
-rw-r--r--net/base/host_resolver_impl.h7
-rw-r--r--net/base/host_resolver_impl_unittest.cc43
-rw-r--r--net/base/mock_host_resolver.cc2
-rw-r--r--net/base/mock_network_change_notifier.h46
-rw-r--r--net/base/net_test_suite.h5
-rw-r--r--net/base/network_change_notifier.cc44
-rw-r--r--net/base/network_change_notifier.h63
-rw-r--r--net/base/network_change_notifier_linux.cc135
-rw-r--r--net/base/network_change_notifier_linux.h54
-rw-r--r--net/base/network_change_notifier_mac.cc287
-rw-r--r--net/base/network_change_notifier_mac.h54
-rw-r--r--net/base/network_change_notifier_win.cc73
-rw-r--r--net/base/network_change_notifier_win.h27
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);
};