Home | History | Annotate | Download | only in base
      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().
     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 
     51 NetworkConfigWatcherMacThread::NetworkConfigWatcherMacThread(
     52     NetworkConfigWatcherMac::Delegate* delegate)
     53     : base::Thread("NetworkConfigWatcher"),
     54       delegate_(delegate),
     55       ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {}
     56 
     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 
     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 
     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 
     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 
    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 
    120 NetworkConfigWatcherMac::~NetworkConfigWatcherMac() {}
    121 
    122 }  // namespace net
    123