summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/base/network_change_notifier_mac.cc78
-rw-r--r--net/base/network_change_notifier_mac.h42
-rw-r--r--net/base/network_config_watcher_mac.cc86
-rw-r--r--net/base/network_config_watcher_mac.h65
-rw-r--r--net/net.gyp2
-rw-r--r--net/proxy/proxy_config_service_mac.cc101
-rw-r--r--net/proxy/proxy_config_service_mac.h48
-rw-r--r--net/proxy/proxy_service.cc2
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();