network_config_watcher_mac.cc revision 3f50c38dc070f4bb515c1b64450dae14f316474e
13345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Copyright (c) 2010 The Chromium Authors. All rights reserved.
23345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Use of this source code is governed by a BSD-style license that can be
33345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// found in the LICENSE file.
43345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
53345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "net/base/network_config_watcher_mac.h"
63345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
73345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include <SystemConfiguration/SCDynamicStoreKey.h>
83345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include <SystemConfiguration/SCSchemaDefinitions.h>
93345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include <algorithm>
103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
11513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "base/compiler_specific.h"
123f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/thread.h"
13731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/mac/scoped_cftyperef.h"
143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merricknamespace net {
163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merricknamespace {
183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Called back by OS.  Calls OnNetworkConfigChange().
203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid DynamicStoreCallback(SCDynamicStoreRef /* store */,
213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                          CFArrayRef changed_keys,
223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                          void* config_delegate) {
233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  NetworkConfigWatcherMac::Delegate* net_config_delegate =
243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      static_cast<NetworkConfigWatcherMac::Delegate*>(config_delegate);
253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  net_config_delegate->OnNetworkConfigChange(changed_keys);
263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
28513209b27ff55e2841eac0e4120199c23acce758Ben Murdochclass NetworkConfigWatcherMacThread : public base::Thread {
29513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch public:
30513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  NetworkConfigWatcherMacThread(NetworkConfigWatcherMac::Delegate* delegate);
31513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  virtual ~NetworkConfigWatcherMacThread();
323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
33513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch protected:
34513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // base::Thread
35513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  virtual void Init();
36513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  virtual void CleanUp();
37513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
38513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch private:
39513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // The SystemConfiguration calls in this function can lead to contention early
40513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // on, so we invoke this function later on in startup to keep it fast.
41513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  void InitNotifications();
42513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
43513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  base::mac::ScopedCFTypeRef<CFRunLoopSourceRef> run_loop_source_;
44513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  NetworkConfigWatcherMac::Delegate* const delegate_;
45513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  ScopedRunnableMethodFactory<NetworkConfigWatcherMacThread> method_factory_;
46513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
47513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DISALLOW_COPY_AND_ASSIGN(NetworkConfigWatcherMacThread);
48513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch};
49513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
50513209b27ff55e2841eac0e4120199c23acce758Ben MurdochNetworkConfigWatcherMacThread::NetworkConfigWatcherMacThread(
51513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    NetworkConfigWatcherMac::Delegate* delegate)
52513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    : base::Thread("NetworkConfigWatcher"),
53513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      delegate_(delegate),
54513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {}
55513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
56513209b27ff55e2841eac0e4120199c23acce758Ben MurdochNetworkConfigWatcherMacThread::~NetworkConfigWatcherMacThread() {
57513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  Stop();
58513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
59513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
60513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid NetworkConfigWatcherMacThread::Init() {
613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // TODO(willchan): Look to see if there's a better signal for when it's ok to
623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // initialize this, rather than just delaying it by a fixed time.
63513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  const int kInitializationDelayMS = 1000;
64513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  message_loop()->PostDelayedTask(
653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      FROM_HERE,
66513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      method_factory_.NewRunnableMethod(
67513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch          &NetworkConfigWatcherMacThread::InitNotifications),
68513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      kInitializationDelayMS);
693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
71513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid NetworkConfigWatcherMacThread::CleanUp() {
72513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (!run_loop_source_.get())
73513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return;
743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  CFRunLoopRemoveSource(CFRunLoopGetCurrent(), run_loop_source_.get(),
763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                        kCFRunLoopCommonModes);
773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  run_loop_source_.reset();
783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
80513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid NetworkConfigWatcherMacThread::InitNotifications() {
813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Add a run loop source for a dynamic store to the current run loop.
823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  SCDynamicStoreContext context = {
833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    0,          // Version 0.
843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    delegate_,  // User data.
853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    NULL,       // This is not reference counted.  No retain function.
863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    NULL,       // This is not reference counted.  No release function.
873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    NULL,       // No description for this.
883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  };
89731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  base::mac::ScopedCFTypeRef<SCDynamicStoreRef> store(SCDynamicStoreCreate(
903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      NULL, CFSTR("org.chromium"), DynamicStoreCallback, &context));
913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  run_loop_source_.reset(SCDynamicStoreCreateRunLoopSource(
923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      NULL, store.get(), 0));
933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  CFRunLoopAddSource(CFRunLoopGetCurrent(), run_loop_source_.get(),
943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                     kCFRunLoopCommonModes);
953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Set up notifications for interface and IP address changes.
973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  delegate_->SetDynamicStoreNotificationKeys(store.get());
98513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
99513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
100513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}  // namespace
1013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
102513209b27ff55e2841eac0e4120199c23acce758Ben MurdochNetworkConfigWatcherMac::NetworkConfigWatcherMac(Delegate* delegate)
103513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    : notifier_thread_(new NetworkConfigWatcherMacThread(delegate)) {
104513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // We create this notifier thread because the notification implementation
105513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // needs a thread with a CFRunLoop, and there's no guarantee that
106513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // MessageLoop::current() meets that criterion.
107513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  base::Thread::Options thread_options(MessageLoop::TYPE_UI, 0);
108513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  notifier_thread_->StartWithOptions(thread_options);
1093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
111513209b27ff55e2841eac0e4120199c23acce758Ben MurdochNetworkConfigWatcherMac::~NetworkConfigWatcherMac() {}
112513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
1133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}  // namespace net
114