summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorwillchan@chromium.org <willchan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-12-21 21:08:35 +0000
committerwillchan@chromium.org <willchan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-12-21 21:08:35 +0000
commit100d5fb906712b03495b961c35f9c9b21381a74a (patch)
tree284b84c9e6baba6da57427243a8b7729f67cb132 /net
parent92683b5a068ab7c7f58251dbee9b047314977bae (diff)
downloadchromium_src-100d5fb906712b03495b961c35f9c9b21381a74a.zip
chromium_src-100d5fb906712b03495b961c35f9c9b21381a74a.tar.gz
chromium_src-100d5fb906712b03495b961c35f9c9b21381a74a.tar.bz2
Detects network changes. Only for Mac OS X so far. Hooks up TCPClientSocketPool to flush idle sockets on IP address change.
BUG=http://crbug.com/26156 TEST=Run chrome with both network cable and wireless on. Go to www.google.com, twice. Verify second time via chrome://net-internals that the second request did not need a TCP_CONNECT_JOB, since we reused idle sockets. Unplug network cable. This should flush idle sockets. Go back to www.google.com. Check chrome://net-internals. Verify that there is a TCP_CONNECT_JOB for that request, because there was no idle socket to reuse. Review URL: http://codereview.chromium.org/460149 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@35107 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r--net/base/mock_network_change_notifier.h44
-rw-r--r--net/base/network_change_notifier.cc32
-rw-r--r--net/base/network_change_notifier.h56
-rw-r--r--net/base/network_change_notifier_helper.cc42
-rw-r--r--net/base/network_change_notifier_helper.h44
-rw-r--r--net/base/network_change_notifier_linux.cc12
-rw-r--r--net/base/network_change_notifier_linux.h37
-rw-r--r--net/base/network_change_notifier_mac.cc229
-rw-r--r--net/base/network_change_notifier_mac.h51
-rw-r--r--net/base/network_change_notifier_win.cc12
-rw-r--r--net/base/network_change_notifier_win.h37
-rw-r--r--net/http/http_network_session.cc9
-rw-r--r--net/http/http_network_session.h11
-rw-r--r--net/http/http_network_transaction_unittest.cc2
-rw-r--r--net/net.gyp11
-rw-r--r--net/socket/client_socket_pool_base.cc16
-rw-r--r--net/socket/client_socket_pool_base.h38
-rw-r--r--net/socket/client_socket_pool_base_unittest.cc2
-rw-r--r--net/socket/tcp_client_socket_pool.cc6
-rw-r--r--net/socket/tcp_client_socket_pool.h10
-rw-r--r--net/socket/tcp_client_socket_pool_unittest.cc32
21 files changed, 702 insertions, 31 deletions
diff --git a/net/base/mock_network_change_notifier.h b/net/base/mock_network_change_notifier.h
new file mode 100644
index 0000000..840d2e8
--- /dev/null
+++ b/net/base/mock_network_change_notifier.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2009 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 "net/base/network_change_notifier.h"
+
+namespace net {
+
+class MockNetworkChangeNotifier : public NetworkChangeNotifier {
+ 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/network_change_notifier.cc b/net/base/network_change_notifier.cc
new file mode 100644
index 0000000..241f419
--- /dev/null
+++ b/net/base/network_change_notifier.cc
@@ -0,0 +1,32 @@
+// Copyright (c) 2009 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.
+
+#include "net/base/network_change_notifier.h"
+#include "build/build_config.h"
+#if defined(OS_WIN)
+#include "net/base/network_change_notifier_win.h"
+#elif defined(OS_LINUX)
+#include "net/base/network_change_notifier_linux.h"
+#elif defined(OS_MACOSX)
+#include "net/base/network_change_notifier_mac.h"
+#endif
+
+namespace net {
+
+// static
+scoped_refptr<NetworkChangeNotifier>
+ NetworkChangeNotifier::CreateDefaultNetworkChangeNotifier() {
+#if defined(OS_WIN)
+ return new NetworkChangeNotifierWin();
+#elif defined(OS_LINUX)
+ return new NetworkChangeNotifierLinux();
+#elif defined(OS_MACOSX)
+ return new NetworkChangeNotifierMac();
+#else
+ NOTIMPLEMENTED();
+ return NULL;
+#endif
+}
+
+} // namespace net
diff --git a/net/base/network_change_notifier.h b/net/base/network_change_notifier.h
new file mode 100644
index 0000000..d66830a
--- /dev/null
+++ b/net/base/network_change_notifier.h
@@ -0,0 +1,56 @@
+// Copyright (c) 2009 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_NETWORK_CHANGE_NOTIFIER_H_
+#define NET_BASE_NETWORK_CHANGE_NOTIFIER_H_
+
+#include "base/basictypes.h"
+#include "base/ref_counted.h"
+
+namespace net {
+
+// NetworkChangeNotifier monitors the system for network changes, and notifies
+// observers on those events.
+class NetworkChangeNotifier : public base::RefCounted<NetworkChangeNotifier> {
+ public:
+ class Observer {
+ public:
+ virtual ~Observer() {}
+
+ // Will be called when the IP address of the primary interface changes.
+ // This includes when the primary interface itself changes.
+ virtual void OnIPAddressChanged() = 0;
+
+ protected:
+ Observer() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Observer);
+ };
+
+ 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;
+
+ // This will create the platform specific default NetworkChangeNotifier.
+ static scoped_refptr<NetworkChangeNotifier>
+ CreateDefaultNetworkChangeNotifier();
+
+ protected:
+ friend class base::RefCounted<NetworkChangeNotifier>;
+ virtual ~NetworkChangeNotifier() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NetworkChangeNotifier);
+};
+
+} // namespace net
+
+#endif // NET_BASE_NETWORK_CHANGE_NOTIFIER_H_
diff --git a/net/base/network_change_notifier_helper.cc b/net/base/network_change_notifier_helper.cc
new file mode 100644
index 0000000..b18d07e
--- /dev/null
+++ b/net/base/network_change_notifier_helper.cc
@@ -0,0 +1,42 @@
+// Copyright (c) 2009 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.
+
+#include "net/base/network_change_notifier_helper.h"
+#include <algorithm>
+#include "base/logging.h"
+
+namespace net {
+
+namespace internal {
+
+NetworkChangeNotifierHelper::NetworkChangeNotifierHelper()
+ : is_notifying_observers_(false) {}
+
+NetworkChangeNotifierHelper::~NetworkChangeNotifierHelper() {
+ DCHECK(observers_.empty());
+}
+
+void NetworkChangeNotifierHelper::AddObserver(Observer* observer) {
+ DCHECK(!is_notifying_observers_);
+ observers_.push_back(observer);
+}
+
+void NetworkChangeNotifierHelper::RemoveObserver(Observer* observer) {
+ DCHECK(!is_notifying_observers_);
+ observers_.erase(std::remove(observers_.begin(), observers_.end(), observer));
+}
+
+void NetworkChangeNotifierHelper::OnIPAddressChanged() {
+ DCHECK(!is_notifying_observers_);
+ is_notifying_observers_ = true;
+ for (std::vector<Observer*>::iterator it = observers_.begin();
+ it != observers_.end(); ++it) {
+ (*it)->OnIPAddressChanged();
+ }
+ is_notifying_observers_ = false;
+}
+
+} // namespace internal
+
+} // namespace net
diff --git a/net/base/network_change_notifier_helper.h b/net/base/network_change_notifier_helper.h
new file mode 100644
index 0000000..f860c45
--- /dev/null
+++ b/net/base/network_change_notifier_helper.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2009 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.
+
+// NetworkChangeNotifierHelper is a helper class that assists in implementing
+// base functionality for a NetworkChangeNotifier implementation. In
+// particular, it manages adding/removing observers and sending them
+// notifications of event changes.
+
+#ifndef NET_BASE_NETWORK_CHANGE_NOTIFIER_HELPER_H_
+#define NET_BASE_NETWORK_CHANGE_NOTIFIER_HELPER_H_
+
+#include <vector>
+#include "base/basictypes.h"
+#include "net/base/network_change_notifier.h"
+
+namespace net {
+
+namespace internal {
+
+class NetworkChangeNotifierHelper {
+ public:
+ typedef NetworkChangeNotifier::Observer Observer;
+
+ NetworkChangeNotifierHelper();
+ ~NetworkChangeNotifierHelper();
+
+ void AddObserver(Observer* observer);
+ void RemoveObserver(Observer* observer);
+
+ void OnIPAddressChanged();
+
+ private:
+ bool is_notifying_observers_;
+ std::vector<Observer*> observers_;
+
+ DISALLOW_COPY_AND_ASSIGN(NetworkChangeNotifierHelper);
+};
+
+} // namespace internal
+
+} // namespace net
+
+#endif // NET_BASE_NETWORK_CHANGE_NOTIFIER_HELPER_H_
diff --git a/net/base/network_change_notifier_linux.cc b/net/base/network_change_notifier_linux.cc
new file mode 100644
index 0000000..e6eba24
--- /dev/null
+++ b/net/base/network_change_notifier_linux.cc
@@ -0,0 +1,12 @@
+// Copyright (c) 2009 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.
+
+#include "net/base/network_change_notifier_linux.h"
+
+namespace net {
+
+NetworkChangeNotifierLinux::NetworkChangeNotifierLinux() {}
+NetworkChangeNotifierLinux::~NetworkChangeNotifierLinux() {}
+
+} // namespace net
diff --git a/net/base/network_change_notifier_linux.h b/net/base/network_change_notifier_linux.h
new file mode 100644
index 0000000..78111c9
--- /dev/null
+++ b/net/base/network_change_notifier_linux.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2009 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_NETWORK_CHANGE_NOTIFIER_LINUX_H_
+#define NET_BASE_NETWORK_CHANGE_NOTIFIER_LINUX_H_
+
+#include "base/basictypes.h"
+#include "net/base/network_change_notifier_helper.h"
+
+namespace net {
+
+class NetworkChangeNotifierLinux : public NetworkChangeNotifier {
+ public:
+ NetworkChangeNotifierLinux();
+
+ virtual void AddObserver(Observer* observer) {
+ helper_.AddObserver(observer);
+ }
+
+ virtual void RemoveObserver(Observer* observer) {
+ helper_.RemoveObserver(observer);
+ }
+
+ private:
+ virtual ~NetworkChangeNotifierLinux();
+
+ void OnIPAddressChanged() { helper_.OnIPAddressChanged(); }
+
+ internal::NetworkChangeNotifierHelper helper_;
+
+ DISALLOW_COPY_AND_ASSIGN(NetworkChangeNotifierLinux);
+};
+
+} // namespace net
+
+#endif // NET_BASE_NETWORK_CHANGE_NOTIFIER_LINUX_H_
diff --git a/net/base/network_change_notifier_mac.cc b/net/base/network_change_notifier_mac.cc
new file mode 100644
index 0000000..81fe02d
--- /dev/null
+++ b/net/base/network_change_notifier_mac.cc
@@ -0,0 +1,229 @@
+// Copyright (c) 2009 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.
+
+// 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/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);
+
+ void Shutdown();
+
+ private:
+ friend class base::RefCountedThreadSafe<NetworkChangeNotifierImpl>;
+ ~NetworkChangeNotifierImpl();
+
+ static void DynamicStoreCallback(SCDynamicStoreRef /* store */,
+ CFArrayRef changed_keys,
+ void* config);
+
+ void OnNetworkConfigChange(CFArrayRef changed_keys);
+
+ // Runs on |notifier_loop_|.
+ void OnIPAddressChanged();
+
+ // 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_;
+
+ scoped_cftyperef<CFRunLoopSourceRef> source_;
+
+ DISALLOW_COPY_AND_ASSIGN(NetworkChangeNotifierImpl);
+};
+
+NetworkChangeNotifierImpl::NetworkChangeNotifierImpl(
+ MessageLoop* notifier_loop, NetworkChangeNotifierMac* notifier)
+ : notifier_loop_(notifier_loop),
+ notifier_(notifier) {
+ DCHECK_EQ(MessageLoop::TYPE_UI, MessageLoop::current()->type());
+ 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.
+ };
+
+ // 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(),
+ kCFRunLoopCommonModes);
+
+ // Set up the notification keys.
+ scoped_cftyperef<CFMutableArrayRef> notification_keys(
+ CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks));
+
+ // Monitor interface changes.
+ scoped_cftyperef<CFStringRef> key(
+ SCDynamicStoreKeyCreateNetworkGlobalEntity(
+ NULL /* default allocator */, kSCDynamicStoreDomainState,
+ kSCEntNetInterface));
+ CFArrayAppendValue(notification_keys.get(), key.get());
+
+ // Monitor IP address changes.
+
+ key.reset(SCDynamicStoreKeyCreateNetworkGlobalEntity(
+ NULL /* default allocator */, kSCDynamicStoreDomainState,
+ kSCEntNetIPv4));
+ CFArrayAppendValue(notification_keys.get(), key.get());
+
+ key.reset(SCDynamicStoreKeyCreateNetworkGlobalEntity(
+ NULL /* default allocator */, kSCDynamicStoreDomainState,
+ kSCEntNetIPv6));
+ CFArrayAppendValue(notification_keys.get(), key.get());
+
+ // Ok, let's ask for notifications!
+ // TODO(willchan): Figure out a proper way to handle this rather than crash.
+ CHECK(SCDynamicStoreSetNotificationKeys(
+ store.get(), notification_keys.get(), NULL));
+}
+
+NetworkChangeNotifierImpl::~NetworkChangeNotifierImpl() {
+ CFRunLoopRemoveSource(CFRunLoopGetCurrent(),
+ source_.get(),
+ kCFRunLoopCommonModes);
+}
+
+void NetworkChangeNotifierImpl::Shutdown() {
+ CHECK(notifier_);
+ notifier_ = NULL;
+}
+
+// static
+void NetworkChangeNotifierImpl::DynamicStoreCallback(
+ SCDynamicStoreRef /* store */,
+ CFArrayRef changed_keys,
+ void* config) {
+ NetworkChangeNotifierImpl* net_config =
+ static_cast<NetworkChangeNotifierImpl*>(config);
+ net_config->OnNetworkConfigChange(changed_keys);
+}
+
+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)) {
+ // TODO(willchan): Does not appear to be working. Look into this.
+ // Perhaps this isn't needed anyway.
+ } else {
+ NOTREACHED();
+ }
+ }
+}
+
+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();
+}
+
+// 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_(
+ new NetworkChangeNotifierThread(MessageLoop::current(), this)) {
+ base::Thread::Options thread_options;
+ thread_options.message_loop_type = MessageLoop::TYPE_UI;
+ notifier_thread_->StartWithOptions(thread_options);
+}
+
+NetworkChangeNotifierMac::~NetworkChangeNotifierMac() {}
+
+} // namespace net
diff --git a/net/base/network_change_notifier_mac.h b/net/base/network_change_notifier_mac.h
new file mode 100644
index 0000000..cbf0128f
--- /dev/null
+++ b/net/base/network_change_notifier_mac.h
@@ -0,0 +1,51 @@
+// Copyright (c) 2009 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_NETWORK_CHANGE_NOTIFIER_MAC_H_
+#define NET_BASE_NETWORK_CHANGE_NOTIFIER_MAC_H_
+
+#include "base/basictypes.h"
+#include "base/ref_counted.h"
+#include "base/scoped_ptr.h"
+#include "net/base/network_change_notifier.h"
+#include "net/base/network_change_notifier_helper.h"
+
+namespace base {
+class Thread;
+} // namespace base
+
+namespace net {
+
+class NetworkChangeNotifierMac : public NetworkChangeNotifier {
+ public:
+ NetworkChangeNotifierMac();
+
+ void OnIPAddressChanged() { helper_.OnIPAddressChanged(); }
+
+ // NetworkChangeNotifier methods:
+
+ virtual void AddObserver(Observer* observer) {
+ helper_.AddObserver(observer);
+ }
+
+ virtual void RemoveObserver(Observer* observer) {
+ helper_.RemoveObserver(observer);
+ }
+
+ private:
+ friend class base::RefCounted<NetworkChangeNotifierMac>;
+
+ virtual ~NetworkChangeNotifierMac();
+
+ // Receives the OS X network change notifications on this thread.
+ const scoped_ptr<base::Thread> notifier_thread_;
+
+ internal::NetworkChangeNotifierHelper helper_;
+
+ DISALLOW_COPY_AND_ASSIGN(NetworkChangeNotifierMac);
+};
+
+} // namespace net
+
+#endif // NET_BASE_NETWORK_CHANGE_NOTIFIER_MAC_H_
diff --git a/net/base/network_change_notifier_win.cc b/net/base/network_change_notifier_win.cc
new file mode 100644
index 0000000..711bd66
--- /dev/null
+++ b/net/base/network_change_notifier_win.cc
@@ -0,0 +1,12 @@
+// Copyright (c) 2009 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.
+
+#include "net/base/network_change_notifier_win.h"
+
+namespace net {
+
+NetworkChangeNotifierWin::NetworkChangeNotifierWin() {}
+NetworkChangeNotifierWin::~NetworkChangeNotifierWin() {}
+
+} // namespace net
diff --git a/net/base/network_change_notifier_win.h b/net/base/network_change_notifier_win.h
new file mode 100644
index 0000000..b208ad7
--- /dev/null
+++ b/net/base/network_change_notifier_win.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2009 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_NETWORK_CHANGE_NOTIFIER_WIN_H_
+#define NET_BASE_NETWORK_CHANGE_NOTIFIER_WIN_H_
+
+#include "base/basictypes.h"
+#include "net/base/network_change_notifier_helper.h"
+
+namespace net {
+
+class NetworkChangeNotifierWin : public NetworkChangeNotifier {
+ public:
+ NetworkChangeNotifierWin();
+
+ virtual void AddObserver(Observer* observer) {
+ helper_.AddObserver(observer);
+ }
+
+ virtual void RemoveObserver(Observer* observer) {
+ helper_.RemoveObserver(observer);
+ }
+
+ private:
+ virtual ~NetworkChangeNotifierWin();
+
+ void OnIPAddressChanged() { helper_.OnIPAddressChanged(); }
+
+ internal::NetworkChangeNotifierHelper helper_;
+
+ DISALLOW_COPY_AND_ASSIGN(NetworkChangeNotifierWin);
+};
+
+} // namespace net
+
+#endif // NET_BASE_NETWORK_CHANGE_NOTIFIER_WIN_H_
diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc
index 1c6f2fe..560c3b5 100644
--- a/net/http/http_network_session.cc
+++ b/net/http/http_network_session.cc
@@ -5,6 +5,7 @@
#include "net/http/http_network_session.h"
#include "base/logging.h"
+#include "net/base/network_change_notifier.h"
#include "net/flip/flip_session_pool.h"
namespace net {
@@ -25,9 +26,11 @@ HttpNetworkSession::HttpNetworkSession(
ClientSocketFactory* client_socket_factory,
SSLConfigService* ssl_config_service,
FlipSessionPool* flip_session_pool)
- : tcp_socket_pool_(new TCPClientSocketPool(
- max_sockets_, max_sockets_per_group_, host_resolver,
- client_socket_factory)),
+ : network_change_notifier_(
+ NetworkChangeNotifier::CreateDefaultNetworkChangeNotifier()),
+ tcp_socket_pool_(new TCPClientSocketPool(
+ max_sockets_, max_sockets_per_group_,
+ host_resolver, client_socket_factory, network_change_notifier_)),
socket_factory_(client_socket_factory),
host_resolver_(host_resolver),
proxy_service_(proxy_service),
diff --git a/net/http/http_network_session.h b/net/http/http_network_session.h
index 27267bb..6eb92db 100644
--- a/net/http/http_network_session.h
+++ b/net/http/http_network_session.h
@@ -21,10 +21,12 @@ class FlipSessionPool;
// This class holds session objects used by HttpNetworkTransaction objects.
class HttpNetworkSession : public base::RefCounted<HttpNetworkSession> {
public:
- HttpNetworkSession(HostResolver* host_resolver, ProxyService* proxy_service,
- ClientSocketFactory* client_socket_factory,
- SSLConfigService* ssl_config_service,
- FlipSessionPool* flip_session_pool);
+ HttpNetworkSession(
+ HostResolver* host_resolver,
+ ProxyService* proxy_service,
+ ClientSocketFactory* client_socket_factory,
+ SSLConfigService* ssl_config_service,
+ FlipSessionPool* flip_session_pool);
HttpAuthCache* auth_cache() { return &auth_cache_; }
SSLClientAuthCache* ssl_client_auth_cache() {
@@ -69,6 +71,7 @@ class HttpNetworkSession : public base::RefCounted<HttpNetworkSession> {
HttpAuthCache auth_cache_;
SSLClientAuthCache ssl_client_auth_cache_;
+ const scoped_refptr<NetworkChangeNotifier> network_change_notifier_;
scoped_refptr<TCPClientSocketPool> tcp_socket_pool_;
ClientSocketFactory* socket_factory_;
scoped_refptr<HostResolver> host_resolver_;
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc
index 53481ba..7e344d7 100644
--- a/net/http/http_network_transaction_unittest.cc
+++ b/net/http/http_network_transaction_unittest.cc
@@ -180,7 +180,7 @@ std::string MockGetHostName() {
class CaptureGroupNameSocketPool : public TCPClientSocketPool {
public:
- CaptureGroupNameSocketPool() : TCPClientSocketPool(0, 0, NULL, NULL) {}
+ CaptureGroupNameSocketPool() : TCPClientSocketPool(0, 0, NULL, NULL, NULL) {}
const std::string last_group_name_received() const {
return last_group_name_;
}
diff --git a/net/net.gyp b/net/net.gyp
index 2528073..60a26a8 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -108,6 +108,16 @@
'base/net_util.h',
'base/net_util_posix.cc',
'base/net_util_win.cc',
+ 'base/network_change_notifier.cc',
+ 'base/network_change_notifier.h',
+ 'base/network_change_notifier_helper.cc',
+ 'base/network_change_notifier_helper.h',
+ 'base/network_change_notifier_linux.cc',
+ 'base/network_change_notifier_linux.h',
+ 'base/network_change_notifier_mac.cc',
+ 'base/network_change_notifier_mac.h',
+ 'base/network_change_notifier_win.cc',
+ 'base/network_change_notifier_win.h',
'base/nss_memio.c',
'base/nss_memio.h',
'base/platform_mime_util.h',
@@ -593,6 +603,7 @@
'base/listen_socket_unittest.h',
'base/mime_sniffer_unittest.cc',
'base/mime_util_unittest.cc',
+ 'base/mock_network_change_notifier.h',
'base/net_test_constants.h',
'base/net_util_unittest.cc',
'base/registry_controlled_domain_unittest.cc',
diff --git a/net/socket/client_socket_pool_base.cc b/net/socket/client_socket_pool_base.cc
index 9701937..44e2187 100644
--- a/net/socket/client_socket_pool_base.cc
+++ b/net/socket/client_socket_pool_base.cc
@@ -100,7 +100,8 @@ ClientSocketPoolBaseHelper::ClientSocketPoolBaseHelper(
int max_sockets_per_group,
base::TimeDelta unused_idle_socket_timeout,
base::TimeDelta used_idle_socket_timeout,
- ConnectJobFactory* connect_job_factory)
+ ConnectJobFactory* connect_job_factory,
+ const scoped_refptr<NetworkChangeNotifier>& network_change_notifier)
: idle_socket_count_(0),
connecting_socket_count_(0),
handed_out_socket_count_(0),
@@ -109,9 +110,13 @@ ClientSocketPoolBaseHelper::ClientSocketPoolBaseHelper(
unused_idle_socket_timeout_(unused_idle_socket_timeout),
used_idle_socket_timeout_(used_idle_socket_timeout),
may_have_stalled_group_(false),
- connect_job_factory_(connect_job_factory) {
+ connect_job_factory_(connect_job_factory),
+ network_change_notifier_(network_change_notifier) {
DCHECK_LE(0, max_sockets_per_group);
DCHECK_LE(max_sockets_per_group, max_sockets);
+
+ if (network_change_notifier_)
+ network_change_notifier_->AddObserver(this);
}
ClientSocketPoolBaseHelper::~ClientSocketPoolBaseHelper() {
@@ -123,6 +128,9 @@ ClientSocketPoolBaseHelper::~ClientSocketPoolBaseHelper() {
CloseIdleSockets();
DCHECK(group_map_.empty());
DCHECK(connect_job_map_.empty());
+
+ if (network_change_notifier_)
+ network_change_notifier_->RemoveObserver(this);
}
// InsertRequestIntoQueue inserts the request into the queue based on
@@ -522,6 +530,10 @@ void ClientSocketPoolBaseHelper::OnConnectJobComplete(
}
}
+void ClientSocketPoolBaseHelper::OnIPAddressChanged() {
+ CloseIdleSockets();
+}
+
void ClientSocketPoolBaseHelper::EnableLateBindingOfSockets(bool enabled) {
g_late_binding = enabled;
}
diff --git a/net/socket/client_socket_pool_base.h b/net/socket/client_socket_pool_base.h
index 897ffec..b21bfb8 100644
--- a/net/socket/client_socket_pool_base.h
+++ b/net/socket/client_socket_pool_base.h
@@ -28,6 +28,7 @@
#include <string>
#include "base/basictypes.h"
+#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
#include "base/time.h"
#include "base/timer.h"
@@ -36,6 +37,7 @@
#include "net/base/load_log.h"
#include "net/base/load_states.h"
#include "net/base/net_errors.h"
+#include "net/base/network_change_notifier.h"
#include "net/base/request_priority.h"
#include "net/socket/client_socket.h"
#include "net/socket/client_socket_pool.h"
@@ -121,7 +123,8 @@ namespace internal {
// ClientSocketPoolBase instead.
class ClientSocketPoolBaseHelper
: public base::RefCounted<ClientSocketPoolBaseHelper>,
- public ConnectJob::Delegate {
+ public ConnectJob::Delegate,
+ public NetworkChangeNotifier::Observer {
public:
class Request {
public:
@@ -163,11 +166,13 @@ class ClientSocketPoolBaseHelper
DISALLOW_COPY_AND_ASSIGN(ConnectJobFactory);
};
- ClientSocketPoolBaseHelper(int max_sockets,
- int max_sockets_per_group,
- base::TimeDelta unused_idle_socket_timeout,
- base::TimeDelta used_idle_socket_timeout,
- ConnectJobFactory* connect_job_factory);
+ ClientSocketPoolBaseHelper(
+ int max_sockets,
+ int max_sockets_per_group,
+ base::TimeDelta unused_idle_socket_timeout,
+ base::TimeDelta used_idle_socket_timeout,
+ ConnectJobFactory* connect_job_factory,
+ const scoped_refptr<NetworkChangeNotifier>& network_change_notifier);
// See ClientSocketPool::RequestSocket for documentation on this function.
// Note that |request| must be heap allocated. If ERR_IO_PENDING is returned,
@@ -201,6 +206,9 @@ class ClientSocketPoolBaseHelper
// ConnectJob::Delegate methods:
virtual void OnConnectJobComplete(int result, ConnectJob* job);
+ // NetworkChangeNotifier::Observer methods:
+ virtual void OnIPAddressChanged();
+
// Enables late binding of sockets. In this mode, socket requests are
// decoupled from socket connection jobs. A socket request may initiate a
// socket connection job, but there is no guarantee that that socket
@@ -385,9 +393,10 @@ class ClientSocketPoolBaseHelper
const scoped_ptr<ConnectJobFactory> connect_job_factory_;
+ const scoped_refptr<NetworkChangeNotifier> network_change_notifier_;
+
// Controls whether or not we use late binding of sockets.
static bool g_late_binding;
-
};
} // namespace internal
@@ -441,15 +450,18 @@ class ClientSocketPoolBase {
// long to leave an unused idle socket open before closing it.
// |used_idle_socket_timeout| specifies how long to leave a previously used
// idle socket open before closing it.
- ClientSocketPoolBase(int max_sockets,
- int max_sockets_per_group,
- base::TimeDelta unused_idle_socket_timeout,
- base::TimeDelta used_idle_socket_timeout,
- ConnectJobFactory* connect_job_factory)
+ ClientSocketPoolBase(
+ int max_sockets,
+ int max_sockets_per_group,
+ base::TimeDelta unused_idle_socket_timeout,
+ base::TimeDelta used_idle_socket_timeout,
+ ConnectJobFactory* connect_job_factory,
+ const scoped_refptr<NetworkChangeNotifier>& network_change_notifier)
: helper_(new internal::ClientSocketPoolBaseHelper(
max_sockets, max_sockets_per_group,
unused_idle_socket_timeout, used_idle_socket_timeout,
- new ConnectJobFactoryAdaptor(connect_job_factory))) {}
+ new ConnectJobFactoryAdaptor(connect_job_factory),
+ network_change_notifier)) {}
virtual ~ClientSocketPoolBase() {}
diff --git a/net/socket/client_socket_pool_base_unittest.cc b/net/socket/client_socket_pool_base_unittest.cc
index 3c4c5cd..db61140 100644
--- a/net/socket/client_socket_pool_base_unittest.cc
+++ b/net/socket/client_socket_pool_base_unittest.cc
@@ -279,7 +279,7 @@ class TestClientSocketPool : public ClientSocketPool {
TestClientSocketPoolBase::ConnectJobFactory* connect_job_factory)
: base_(max_sockets, max_sockets_per_group,
unused_idle_socket_timeout, used_idle_socket_timeout,
- connect_job_factory) {}
+ connect_job_factory, NULL) {}
virtual int RequestSocket(
const std::string& group_name,
diff --git a/net/socket/tcp_client_socket_pool.cc b/net/socket/tcp_client_socket_pool.cc
index 84899da..1c6876a 100644
--- a/net/socket/tcp_client_socket_pool.cc
+++ b/net/socket/tcp_client_socket_pool.cc
@@ -161,11 +161,13 @@ TCPClientSocketPool::TCPClientSocketPool(
int max_sockets,
int max_sockets_per_group,
HostResolver* host_resolver,
- ClientSocketFactory* client_socket_factory)
+ ClientSocketFactory* client_socket_factory,
+ const scoped_refptr<NetworkChangeNotifier>& network_change_notifier)
: base_(max_sockets, max_sockets_per_group,
base::TimeDelta::FromSeconds(kUnusedIdleSocketTimeout),
base::TimeDelta::FromSeconds(kUsedIdleSocketTimeout),
- new TCPConnectJobFactory(client_socket_factory, host_resolver)) {}
+ new TCPConnectJobFactory(client_socket_factory, host_resolver),
+ network_change_notifier) {}
TCPClientSocketPool::~TCPClientSocketPool() {}
diff --git a/net/socket/tcp_client_socket_pool.h b/net/socket/tcp_client_socket_pool.h
index 49c0aa7..96ebe73 100644
--- a/net/socket/tcp_client_socket_pool.h
+++ b/net/socket/tcp_client_socket_pool.h
@@ -76,10 +76,12 @@ class TCPConnectJob : public ConnectJob {
class TCPClientSocketPool : public ClientSocketPool {
public:
- TCPClientSocketPool(int max_sockets,
- int max_sockets_per_group,
- HostResolver* host_resolver,
- ClientSocketFactory* client_socket_factory);
+ TCPClientSocketPool(
+ int max_sockets,
+ int max_sockets_per_group,
+ HostResolver* host_resolver,
+ ClientSocketFactory* client_socket_factory,
+ const scoped_refptr<NetworkChangeNotifier>& network_change_notifier);
// ClientSocketPool methods:
diff --git a/net/socket/tcp_client_socket_pool_unittest.cc b/net/socket/tcp_client_socket_pool_unittest.cc
index b3560be..8aa9ea0 100644
--- a/net/socket/tcp_client_socket_pool_unittest.cc
+++ b/net/socket/tcp_client_socket_pool_unittest.cc
@@ -7,6 +7,7 @@
#include "base/compiler_specific.h"
#include "base/message_loop.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/test_completion_callback.h"
#include "net/socket/client_socket.h"
@@ -197,10 +198,12 @@ class TCPClientSocketPoolTest : public ClientSocketPoolTest {
TCPClientSocketPoolTest()
: ignored_request_info_("ignored", 80),
host_resolver_(new MockHostResolver),
+ notifier_(new MockNetworkChangeNotifier),
pool_(new TCPClientSocketPool(kMaxSockets,
kMaxSocketsPerGroup,
host_resolver_,
- &client_socket_factory_)) {
+ &client_socket_factory_,
+ notifier_)) {
}
int StartRequest(const std::string& group_name, RequestPriority priority) {
@@ -211,6 +214,7 @@ class TCPClientSocketPoolTest : public ClientSocketPoolTest {
HostResolver::RequestInfo ignored_request_info_;
scoped_refptr<MockHostResolver> host_resolver_;
MockClientSocketFactory client_socket_factory_;
+ scoped_refptr<MockNetworkChangeNotifier> notifier_;
scoped_refptr<TCPClientSocketPool> pool_;
};
@@ -580,6 +584,32 @@ TEST_F(TCPClientSocketPoolTest, FailingActiveRequestWithPendingRequests) {
EXPECT_EQ(ERR_CONNECTION_FAILED, requests_[i]->WaitForResult());
}
+TEST_F(TCPClientSocketPoolTest, ResetIdleSocketsOnIPAddressChange) {
+ TestCompletionCallback callback;
+ ClientSocketHandle handle;
+ HostResolver::RequestInfo info("www.google.com", 80);
+ int rv = handle.Init("a", info, LOW, &callback, pool_.get(), NULL);
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_FALSE(handle.is_initialized());
+ EXPECT_FALSE(handle.socket());
+
+ EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_TRUE(handle.is_initialized());
+ EXPECT_TRUE(handle.socket());
+
+ handle.Reset();
+
+ // Need to run all pending to release the socket back to the pool.
+ MessageLoop::current()->RunAllPending();
+
+ // Now we should have 1 idle socket.
+ EXPECT_EQ(1, pool_->IdleSocketCount());
+
+ // After an IP address change, we should have 0 idle sockets.
+ notifier_->NotifyIPAddressChange();
+ EXPECT_EQ(0, pool_->IdleSocketCount());
+}
+
} // namespace
} // namespace net