• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "net/base/network_config_watcher_mac.h"
6 
7 #include <SystemConfiguration/SCDynamicStoreKey.h>
8 #include <SystemConfiguration/SCSchemaDefinitions.h>
9 #include <algorithm>
10 
11 #include "base/compiler_specific.h"
12 #include "base/threading/thread.h"
13 #include "base/threading/thread_restrictions.h"
14 #include "base/mac/scoped_cftyperef.h"
15 
16 namespace net {
17 
18 namespace {
19 
20 // Called back by OS.  Calls OnNetworkConfigChange().
DynamicStoreCallback(SCDynamicStoreRef,CFArrayRef changed_keys,void * config_delegate)21 void DynamicStoreCallback(SCDynamicStoreRef /* store */,
22                           CFArrayRef changed_keys,
23                           void* config_delegate) {
24   NetworkConfigWatcherMac::Delegate* net_config_delegate =
25       static_cast<NetworkConfigWatcherMac::Delegate*>(config_delegate);
26   net_config_delegate->OnNetworkConfigChange(changed_keys);
27 }
28 
29 class NetworkConfigWatcherMacThread : public base::Thread {
30  public:
31   NetworkConfigWatcherMacThread(NetworkConfigWatcherMac::Delegate* delegate);
32   virtual ~NetworkConfigWatcherMacThread();
33 
34  protected:
35   // base::Thread
36   virtual void Init();
37   virtual void CleanUp();
38 
39  private:
40   // The SystemConfiguration calls in this function can lead to contention early
41   // on, so we invoke this function later on in startup to keep it fast.
42   void InitNotifications();
43 
44   base::mac::ScopedCFTypeRef<CFRunLoopSourceRef> run_loop_source_;
45   NetworkConfigWatcherMac::Delegate* const delegate_;
46   ScopedRunnableMethodFactory<NetworkConfigWatcherMacThread> method_factory_;
47 
48   DISALLOW_COPY_AND_ASSIGN(NetworkConfigWatcherMacThread);
49 };
50 
NetworkConfigWatcherMacThread(NetworkConfigWatcherMac::Delegate * delegate)51 NetworkConfigWatcherMacThread::NetworkConfigWatcherMacThread(
52     NetworkConfigWatcherMac::Delegate* delegate)
53     : base::Thread("NetworkConfigWatcher"),
54       delegate_(delegate),
55       ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {}
56 
~NetworkConfigWatcherMacThread()57 NetworkConfigWatcherMacThread::~NetworkConfigWatcherMacThread() {
58   // Allow IO because Stop() calls PlatformThread::Join(), which is a blocking
59   // operation. This is expected during shutdown.
60   base::ThreadRestrictions::ScopedAllowIO allow_io;
61 
62   Stop();
63 }
64 
Init()65 void NetworkConfigWatcherMacThread::Init() {
66   // Disallow IO to make sure NetworkConfigWatcherMacThread's helper thread does
67   // not perform blocking operations.
68   base::ThreadRestrictions::SetIOAllowed(false);
69 
70   // TODO(willchan): Look to see if there's a better signal for when it's ok to
71   // initialize this, rather than just delaying it by a fixed time.
72   const int kInitializationDelayMS = 1000;
73   message_loop()->PostDelayedTask(
74       FROM_HERE,
75       method_factory_.NewRunnableMethod(
76           &NetworkConfigWatcherMacThread::InitNotifications),
77       kInitializationDelayMS);
78 }
79 
CleanUp()80 void NetworkConfigWatcherMacThread::CleanUp() {
81   if (!run_loop_source_.get())
82     return;
83 
84   CFRunLoopRemoveSource(CFRunLoopGetCurrent(), run_loop_source_.get(),
85                         kCFRunLoopCommonModes);
86   run_loop_source_.reset();
87 }
88 
InitNotifications()89 void NetworkConfigWatcherMacThread::InitNotifications() {
90   // Add a run loop source for a dynamic store to the current run loop.
91   SCDynamicStoreContext context = {
92     0,          // Version 0.
93     delegate_,  // User data.
94     NULL,       // This is not reference counted.  No retain function.
95     NULL,       // This is not reference counted.  No release function.
96     NULL,       // No description for this.
97   };
98   base::mac::ScopedCFTypeRef<SCDynamicStoreRef> store(SCDynamicStoreCreate(
99       NULL, CFSTR("org.chromium"), DynamicStoreCallback, &context));
100   run_loop_source_.reset(SCDynamicStoreCreateRunLoopSource(
101       NULL, store.get(), 0));
102   CFRunLoopAddSource(CFRunLoopGetCurrent(), run_loop_source_.get(),
103                      kCFRunLoopCommonModes);
104 
105   // Set up notifications for interface and IP address changes.
106   delegate_->SetDynamicStoreNotificationKeys(store.get());
107 }
108 
109 }  // namespace
110 
NetworkConfigWatcherMac(Delegate * delegate)111 NetworkConfigWatcherMac::NetworkConfigWatcherMac(Delegate* delegate)
112     : notifier_thread_(new NetworkConfigWatcherMacThread(delegate)) {
113   // We create this notifier thread because the notification implementation
114   // needs a thread with a CFRunLoop, and there's no guarantee that
115   // MessageLoop::current() meets that criterion.
116   base::Thread::Options thread_options(MessageLoop::TYPE_UI, 0);
117   notifier_thread_->StartWithOptions(thread_options);
118 }
119 
~NetworkConfigWatcherMac()120 NetworkConfigWatcherMac::~NetworkConfigWatcherMac() {}
121 
122 }  // namespace net
123