diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/base/network_change_notifier_mac.cc | 78 | ||||
-rw-r--r-- | net/base/network_change_notifier_mac.h | 42 | ||||
-rw-r--r-- | net/base/network_config_watcher_mac.cc | 86 | ||||
-rw-r--r-- | net/base/network_config_watcher_mac.h | 65 | ||||
-rw-r--r-- | net/net.gyp | 2 | ||||
-rw-r--r-- | net/proxy/proxy_config_service_mac.cc | 101 | ||||
-rw-r--r-- | net/proxy/proxy_config_service_mac.h | 48 | ||||
-rw-r--r-- | net/proxy/proxy_service.cc | 2 |
8 files changed, 307 insertions, 117 deletions
diff --git a/net/base/network_change_notifier_mac.cc b/net/base/network_change_notifier_mac.cc index 797de6d..4c46a99 100644 --- a/net/base/network_change_notifier_mac.cc +++ b/net/base/network_change_notifier_mac.cc @@ -6,78 +6,13 @@ #include <SystemConfiguration/SCDynamicStoreKey.h> #include <SystemConfiguration/SCSchemaDefinitions.h> -#include <algorithm> - -#include "base/thread.h" - -// We only post tasks to a child thread we own, so we don't need refcounting. -DISABLE_RUNNABLE_METHOD_REFCOUNT(net::NetworkChangeNotifierMac); namespace net { -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); -} - -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); -} - -// static -void NetworkChangeNotifierMac::DynamicStoreCallback( - SCDynamicStoreRef /* store */, - CFArrayRef changed_keys, - void* config) { - NetworkChangeNotifierMac* net_config = - static_cast<NetworkChangeNotifierMac*>(config); - net_config->OnNetworkConfigChange(changed_keys); -} +NetworkChangeNotifierMac::NetworkChangeNotifierMac() {} -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()); - - DCHECK(run_loop_source_ != NULL); - CFRunLoopRemoveSource(CFRunLoopGetCurrent(), run_loop_source_.get(), - kCFRunLoopCommonModes); - run_loop_source_.reset(); -} - -void NetworkChangeNotifierMac::Init() { - DCHECK(notifier_thread_ != NULL); - DCHECK_EQ(notifier_thread_->message_loop(), MessageLoop::current()); - - // 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. - }; - 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 notifications for interface and IP address changes. +void NetworkChangeNotifierMac::SetDynamicStoreNotificationKeys( + SCDynamicStoreRef store) { scoped_cftyperef<CFMutableArrayRef> notification_keys( CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks)); scoped_cftyperef<CFStringRef> key(SCDynamicStoreKeyCreateNetworkGlobalEntity( @@ -92,16 +27,13 @@ void NetworkChangeNotifierMac::Init() { // Set the notification keys. This starts us receiving notifications. bool ret = SCDynamicStoreSetNotificationKeys( - store.get(), notification_keys.get(), NULL); + store, notification_keys.get(), NULL); // TODO(willchan): Figure out a proper way to handle this rather than crash. CHECK(ret); - - MessageLoop::current()->AddDestructionObserver(this); } void NetworkChangeNotifierMac::OnNetworkConfigChange(CFArrayRef changed_keys) { - DCHECK(notifier_thread_ != NULL); - DCHECK_EQ(notifier_thread_->message_loop(), MessageLoop::current()); + // Called on notifier thread. for (CFIndex i = 0; i < CFArrayGetCount(changed_keys); ++i) { CFStringRef key = static_cast<CFStringRef>( diff --git a/net/base/network_change_notifier_mac.h b/net/base/network_change_notifier_mac.h index 86792e0..1d23524 100644 --- a/net/base/network_change_notifier_mac.h +++ b/net/base/network_change_notifier_mac.h @@ -9,50 +9,22 @@ #include <SystemConfiguration/SCDynamicStore.h> #include "base/basictypes.h" -#include "base/message_loop.h" -#include "base/scoped_cftyperef.h" -#include "base/scoped_ptr.h" #include "net/base/network_change_notifier.h" - -namespace base { -class Thread; -} +#include "net/base/network_config_watcher_mac.h" namespace net { -class NetworkChangeNotifierMac : public MessageLoop::DestructionObserver, +class NetworkChangeNotifierMac : public NetworkConfigWatcherMac, public NetworkChangeNotifier { public: NetworkChangeNotifierMac(); - private: - virtual ~NetworkChangeNotifierMac(); - - // Called back by OS. Calls OnNetworkConfigChange(). - static void DynamicStoreCallback(SCDynamicStoreRef /* store */, - CFArrayRef changed_keys, - void* config); - - // MessageLoop::DestructionObserver: - virtual void WillDestroyCurrentMessageLoop(); - - // 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(); - - // Called by DynamicStoreCallback() when something about the network config - // changes. - void OnNetworkConfigChange(CFArrayRef changed_keys); - - // 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_; - - scoped_cftyperef<CFRunLoopSourceRef> run_loop_source_; + protected: + // NetworkConfigWatcherMac implementation: + virtual void SetDynamicStoreNotificationKeys(SCDynamicStoreRef store); + virtual void OnNetworkConfigChange(CFArrayRef changed_keys); + private: DISALLOW_COPY_AND_ASSIGN(NetworkChangeNotifierMac); }; diff --git a/net/base/network_config_watcher_mac.cc b/net/base/network_config_watcher_mac.cc new file mode 100644 index 0000000..8767dff --- /dev/null +++ b/net/base/network_config_watcher_mac.cc @@ -0,0 +1,86 @@ +// 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. + +#include "net/base/network_config_watcher_mac.h" + +#include <SystemConfiguration/SCDynamicStoreKey.h> +#include <SystemConfiguration/SCSchemaDefinitions.h> +#include <algorithm> + +#include "base/thread.h" + +// We only post tasks to a child thread we own, so we don't need refcounting. +DISABLE_RUNNABLE_METHOD_REFCOUNT(net::NetworkConfigWatcherMac); + +namespace net { + +NetworkConfigWatcherMac::NetworkConfigWatcherMac() + : notifier_thread_(new base::Thread("NetworkConfigWatcher")) { + // 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, &NetworkConfigWatcherMac::Init), + kNotifierThreadInitializationDelayMS); +} + +NetworkConfigWatcherMac::~NetworkConfigWatcherMac() { + // 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); +} + +// static +void NetworkConfigWatcherMac::DynamicStoreCallback( + SCDynamicStoreRef /* store */, + CFArrayRef changed_keys, + void* config) { + NetworkConfigWatcherMac* net_config = + static_cast<NetworkConfigWatcherMac*>(config); + net_config->OnNetworkConfigChange(changed_keys); +} + +void NetworkConfigWatcherMac::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()); + + DCHECK(run_loop_source_ != NULL); + CFRunLoopRemoveSource(CFRunLoopGetCurrent(), run_loop_source_.get(), + kCFRunLoopCommonModes); + run_loop_source_.reset(); +} + +void NetworkConfigWatcherMac::Init() { + DCHECK(notifier_thread_ != NULL); + DCHECK_EQ(notifier_thread_->message_loop(), MessageLoop::current()); + + // 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. + }; + 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 notifications for interface and IP address changes. + SetDynamicStoreNotificationKeys(store.get()); + + MessageLoop::current()->AddDestructionObserver(this); +} + +} // namespace net diff --git a/net/base/network_config_watcher_mac.h b/net/base/network_config_watcher_mac.h new file mode 100644 index 0000000..71fb825 --- /dev/null +++ b/net/base/network_config_watcher_mac.h @@ -0,0 +1,65 @@ +// 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_NETWORK_CONFIG_WATCHER_MAC_H_ +#define NET_BASE_NETWORK_CONFIG_WATCHER_MAC_H_ + +#include <SystemConfiguration/SCDynamicStore.h> + +#include "base/basictypes.h" +#include "base/message_loop.h" +#include "base/scoped_cftyperef.h" +#include "base/scoped_ptr.h" + +namespace base { +class Thread; +} + +namespace net { + +// Base class for watching the Mac OS system network settings. +class NetworkConfigWatcherMac : public MessageLoop::DestructionObserver { + public: + NetworkConfigWatcherMac(); + + protected: + virtual ~NetworkConfigWatcherMac(); + + // Called to register the notification keys on |store|. + // Implementors are expected to call SCDynamicStoreSetNotificationKeys(). + // Will be called on the notifier thread. + virtual void SetDynamicStoreNotificationKeys(SCDynamicStoreRef store) = 0; + + // Called when one of the notification keys has changed. + // Will be called on the notifier thread. + virtual void OnNetworkConfigChange(CFArrayRef changed_keys) = 0; + + private: + // Called back by OS. Calls OnNetworkConfigChange(). + static void DynamicStoreCallback(SCDynamicStoreRef /* store */, + CFArrayRef changed_keys, + void* config); + + // MessageLoop::DestructionObserver: + virtual void WillDestroyCurrentMessageLoop(); + + // 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(); + + // 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_; + + scoped_cftyperef<CFRunLoopSourceRef> run_loop_source_; + + DISALLOW_COPY_AND_ASSIGN(NetworkConfigWatcherMac); +}; + +} // namespace net + +#endif // NET_BASE_NETWORK_CONFIG_WATCHER_MAC_H_ diff --git a/net/net.gyp b/net/net.gyp index b580e0f..56edd4c 100644 --- a/net/net.gyp +++ b/net/net.gyp @@ -125,6 +125,8 @@ 'base/network_change_notifier_netlink_linux.h', 'base/network_change_notifier_win.cc', 'base/network_change_notifier_win.h', + 'base/network_config_watcher_mac.cc', + 'base/network_config_watcher_mac.h', 'base/nss_memio.c', 'base/nss_memio.h', 'base/pem_tokenizer.cc', diff --git a/net/proxy/proxy_config_service_mac.cc b/net/proxy/proxy_config_service_mac.cc index 27a0426..38237a56 100644 --- a/net/proxy/proxy_config_service_mac.cc +++ b/net/proxy/proxy_config_service_mac.cc @@ -161,9 +161,104 @@ void GetCurrentProxyConfig(ProxyConfig* config) { } // namespace -ProxyConfigServiceMac::ProxyConfigServiceMac() - : PollingProxyConfigService(base::TimeDelta::FromSeconds(kPollIntervalSec), - &GetCurrentProxyConfig) { +// Reference-counted helper for posting a task to +// ProxyConfigServiceMac::OnProxyConfigChanged between the notifier and IO +// thread. This helper object may outlive the ProxyConfigServiceMac. +class ProxyConfigServiceMac::Helper + : public base::RefCountedThreadSafe<ProxyConfigServiceMac::Helper> { + public: + explicit Helper(ProxyConfigServiceMac* parent) : parent_(parent) { + DCHECK(parent); + } + + // Called when the parent is destroyed. + void Orphan() { + parent_ = NULL; + } + + void OnProxyConfigChanged(const ProxyConfig& new_config) { + if (parent_) + parent_->OnProxyConfigChanged(new_config); + } + + private: + ProxyConfigServiceMac* parent_; +}; + +ProxyConfigServiceMac::ProxyConfigServiceMac(MessageLoop* io_loop) + : has_fetched_config_(false), + helper_(new Helper(this)), + io_loop_(io_loop) { + DCHECK(io_loop); +} + +ProxyConfigServiceMac::~ProxyConfigServiceMac() { + DCHECK_EQ(io_loop_, MessageLoop::current()); + helper_->Orphan(); + io_loop_ = NULL; +} + +void ProxyConfigServiceMac::AddObserver(Observer* observer) { + DCHECK_EQ(io_loop_, MessageLoop::current()); + observers_.AddObserver(observer); +} + +void ProxyConfigServiceMac::RemoveObserver(Observer* observer) { + DCHECK_EQ(io_loop_, MessageLoop::current()); + observers_.RemoveObserver(observer); +} + +bool ProxyConfigServiceMac::GetLatestProxyConfig(ProxyConfig* config) { + DCHECK_EQ(io_loop_, MessageLoop::current()); + + // Lazy-initialize by fetching the proxy setting from this thread. + if (!has_fetched_config_) { + GetCurrentProxyConfig(&last_config_fetched_); + has_fetched_config_ = true; + } + + *config = last_config_fetched_; + return has_fetched_config_; +} + +void ProxyConfigServiceMac::SetDynamicStoreNotificationKeys( + SCDynamicStoreRef store) { + CFStringRef proxies_key = SCDynamicStoreKeyCreateProxies(NULL); + CFArrayRef key_array = CFArrayCreate( + NULL, (const void **)(&proxies_key), 1, &kCFTypeArrayCallBacks); + + bool ret = SCDynamicStoreSetNotificationKeys(store, key_array, NULL); + // TODO(willchan): Figure out a proper way to handle this rather than crash. + CHECK(ret); + + CFRelease(key_array); + CFRelease(proxies_key); +} + +void ProxyConfigServiceMac::OnNetworkConfigChange(CFArrayRef changed_keys) { + // Called on notifier thread. + + // Fetch the new system proxy configuration. + ProxyConfig new_config; + GetCurrentProxyConfig(&new_config); + + // Call OnProxyConfigChanged() on the IO thread to notify our observers. + io_loop_->PostTask( + FROM_HERE, + NewRunnableMethod( + helper_.get(), &Helper::OnProxyConfigChanged, new_config)); +} + +void ProxyConfigServiceMac::OnProxyConfigChanged( + const ProxyConfig& new_config) { + DCHECK_EQ(io_loop_, MessageLoop::current()); + + // Keep track of the last value we have seen. + has_fetched_config_ = true; + last_config_fetched_ = new_config; + + // Notify all the observers. + FOR_EACH_OBSERVER(Observer, observers_, OnProxyConfigChanged(new_config)); } } // namespace net diff --git a/net/proxy/proxy_config_service_mac.h b/net/proxy/proxy_config_service_mac.h index 3602313..fd2d524 100644 --- a/net/proxy/proxy_config_service_mac.h +++ b/net/proxy/proxy_config_service_mac.h @@ -6,15 +6,53 @@ #define NET_PROXY_PROXY_CONFIG_SERVICE_MAC_H_ #pragma once -#include "net/proxy/polling_proxy_config_service.h" +#include "base/basictypes.h" +#include "base/observer_list.h" +#include "base/ref_counted.h" +#include "net/base/network_config_watcher_mac.h" +#include "net/proxy/proxy_config.h" +#include "net/proxy/proxy_config_service.h" namespace net { -// TODO(eroman): Use notification-based system APIs instead of polling for -// changes. -class ProxyConfigServiceMac : public PollingProxyConfigService { +class ProxyConfigServiceMac : public ProxyConfigService, + public NetworkConfigWatcherMac { public: - ProxyConfigServiceMac(); + // Constructs a ProxyConfigService that watches the Mac OS system settings. + // This instance is expected to be operated and deleted on |io_loop| + // (however it may be constructed from a different thread). + explicit ProxyConfigServiceMac(MessageLoop* io_loop); + virtual ~ProxyConfigServiceMac(); + + public: + // ProxyConfigService implementation: + virtual void AddObserver(Observer* observer); + virtual void RemoveObserver(Observer* observer); + virtual bool GetLatestProxyConfig(ProxyConfig* config); + + protected: + // NetworkConfigWatcherMac implementation: + virtual void SetDynamicStoreNotificationKeys(SCDynamicStoreRef store); + virtual void OnNetworkConfigChange(CFArrayRef changed_keys); + + private: + class Helper; + + // Called when the proxy configuration has changed, to notify the observers. + void OnProxyConfigChanged(const ProxyConfig& new_config); + + ObserverList<Observer> observers_; + + // Holds the last system proxy settings that we fetched. + bool has_fetched_config_; + ProxyConfig last_config_fetched_; + + scoped_refptr<Helper> helper_; + + // The thread that we expect to be operated on. + MessageLoop* io_loop_; + + DISALLOW_COPY_AND_ASSIGN(ProxyConfigServiceMac); }; } // namespace net diff --git a/net/proxy/proxy_service.cc b/net/proxy/proxy_service.cc index d13b1f1..7358f1c 100644 --- a/net/proxy/proxy_service.cc +++ b/net/proxy/proxy_service.cc @@ -614,7 +614,7 @@ ProxyConfigService* ProxyService::CreateSystemProxyConfigService( #if defined(OS_WIN) return new ProxyConfigServiceWin(); #elif defined(OS_MACOSX) - return new ProxyConfigServiceMac(); + return new ProxyConfigServiceMac(io_loop); #elif defined(OS_LINUX) ProxyConfigServiceLinux* linux_config_service = new ProxyConfigServiceLinux(); |