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"
1372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "base/threading/thread_restrictions.h"
14731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/mac/scoped_cftyperef.h"
153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merricknamespace net {
173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merricknamespace {
193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Called back by OS.  Calls OnNetworkConfigChange().
213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid DynamicStoreCallback(SCDynamicStoreRef /* store */,
223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                          CFArrayRef changed_keys,
233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                          void* config_delegate) {
243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  NetworkConfigWatcherMac::Delegate* net_config_delegate =
253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      static_cast<NetworkConfigWatcherMac::Delegate*>(config_delegate);
263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  net_config_delegate->OnNetworkConfigChange(changed_keys);
273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
29513209b27ff55e2841eac0e4120199c23acce758Ben Murdochclass NetworkConfigWatcherMacThread : public base::Thread {
30513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch public:
31513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  NetworkConfigWatcherMacThread(NetworkConfigWatcherMac::Delegate* delegate);
32513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  virtual ~NetworkConfigWatcherMacThread();
333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
34513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch protected:
35513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // base::Thread
36513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  virtual void Init();
37513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  virtual void CleanUp();
38513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
39513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch private:
40513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // The SystemConfiguration calls in this function can lead to contention early
41513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // on, so we invoke this function later on in startup to keep it fast.
42513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  void InitNotifications();
43513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
44513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  base::mac::ScopedCFTypeRef<CFRunLoopSourceRef> run_loop_source_;
45513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  NetworkConfigWatcherMac::Delegate* const delegate_;
46513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  ScopedRunnableMethodFactory<NetworkConfigWatcherMacThread> method_factory_;
47513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
48513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DISALLOW_COPY_AND_ASSIGN(NetworkConfigWatcherMacThread);
49513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch};
50513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
51513209b27ff55e2841eac0e4120199c23acce758Ben MurdochNetworkConfigWatcherMacThread::NetworkConfigWatcherMacThread(
52513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    NetworkConfigWatcherMac::Delegate* delegate)
53513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    : base::Thread("NetworkConfigWatcher"),
54513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      delegate_(delegate),
55513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {}
56513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
57513209b27ff55e2841eac0e4120199c23acce758Ben MurdochNetworkConfigWatcherMacThread::~NetworkConfigWatcherMacThread() {
5872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // Allow IO because Stop() calls PlatformThread::Join(), which is a blocking
5972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // operation. This is expected during shutdown.
6072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  base::ThreadRestrictions::ScopedAllowIO allow_io;
6172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
62513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  Stop();
63513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
64513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
65513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid NetworkConfigWatcherMacThread::Init() {
6672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // Disallow IO to make sure NetworkConfigWatcherMacThread's helper thread does
6772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // not perform blocking operations.
6872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  base::ThreadRestrictions::SetIOAllowed(false);
6972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // TODO(willchan): Look to see if there's a better signal for when it's ok to
713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // initialize this, rather than just delaying it by a fixed time.
72513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  const int kInitializationDelayMS = 1000;
73513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  message_loop()->PostDelayedTask(
743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      FROM_HERE,
75513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      method_factory_.NewRunnableMethod(
76513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch          &NetworkConfigWatcherMacThread::InitNotifications),
77513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      kInitializationDelayMS);
783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
80513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid NetworkConfigWatcherMacThread::CleanUp() {
81513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (!run_loop_source_.get())
82513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return;
833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  CFRunLoopRemoveSource(CFRunLoopGetCurrent(), run_loop_source_.get(),
853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                        kCFRunLoopCommonModes);
863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  run_loop_source_.reset();
873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
89513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid NetworkConfigWatcherMacThread::InitNotifications() {
903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Add a run loop source for a dynamic store to the current run loop.
913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  SCDynamicStoreContext context = {
923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    0,          // Version 0.
933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    delegate_,  // User data.
943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    NULL,       // This is not reference counted.  No retain function.
953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    NULL,       // This is not reference counted.  No release function.
963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    NULL,       // No description for this.
973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  };
98731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  base::mac::ScopedCFTypeRef<SCDynamicStoreRef> store(SCDynamicStoreCreate(
993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      NULL, CFSTR("org.chromium"), DynamicStoreCallback, &context));
1003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  run_loop_source_.reset(SCDynamicStoreCreateRunLoopSource(
1013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      NULL, store.get(), 0));
1023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  CFRunLoopAddSource(CFRunLoopGetCurrent(), run_loop_source_.get(),
1033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                     kCFRunLoopCommonModes);
1043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Set up notifications for interface and IP address changes.
1063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  delegate_->SetDynamicStoreNotificationKeys(store.get());
107513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
108513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
109513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}  // namespace
1103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
111513209b27ff55e2841eac0e4120199c23acce758Ben MurdochNetworkConfigWatcherMac::NetworkConfigWatcherMac(Delegate* delegate)
112513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    : notifier_thread_(new NetworkConfigWatcherMacThread(delegate)) {
113513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // We create this notifier thread because the notification implementation
114513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // needs a thread with a CFRunLoop, and there's no guarantee that
115513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // MessageLoop::current() meets that criterion.
116513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  base::Thread::Options thread_options(MessageLoop::TYPE_UI, 0);
117513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  notifier_thread_->StartWithOptions(thread_options);
1183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
120513209b27ff55e2841eac0e4120199c23acce758Ben MurdochNetworkConfigWatcherMac::~NetworkConfigWatcherMac() {}
121513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
1223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}  // namespace net
123