diff options
author | willchan@chromium.org <willchan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-12-21 21:08:35 +0000 |
---|---|---|
committer | willchan@chromium.org <willchan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-12-21 21:08:35 +0000 |
commit | 100d5fb906712b03495b961c35f9c9b21381a74a (patch) | |
tree | 284b84c9e6baba6da57427243a8b7729f67cb132 /net | |
parent | 92683b5a068ab7c7f58251dbee9b047314977bae (diff) | |
download | chromium_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')
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 |