- add sources.
[platform/framework/web/crosswalk.git] / src / net / base / network_config_watcher_mac.cc
1 // Copyright (c) 2012 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 <algorithm>
8
9 #include "base/bind.h"
10 #include "base/compiler_specific.h"
11 #include "base/memory/weak_ptr.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/threading/thread.h"
14 #include "base/threading/thread_restrictions.h"
15
16 namespace net {
17
18 namespace {
19
20 #if !defined(OS_IOS)
21 // Called back by OS.  Calls OnNetworkConfigChange().
22 void DynamicStoreCallback(SCDynamicStoreRef /* store */,
23                           CFArrayRef changed_keys,
24                           void* config_delegate) {
25   NetworkConfigWatcherMac::Delegate* net_config_delegate =
26       static_cast<NetworkConfigWatcherMac::Delegate*>(config_delegate);
27   net_config_delegate->OnNetworkConfigChange(changed_keys);
28 }
29 #endif  // !defined(OS_IOS)
30
31 class NetworkConfigWatcherMacThread : public base::Thread {
32  public:
33   NetworkConfigWatcherMacThread(NetworkConfigWatcherMac::Delegate* delegate);
34   virtual ~NetworkConfigWatcherMacThread();
35
36  protected:
37   // base::Thread
38   virtual void Init() OVERRIDE;
39   virtual void CleanUp() OVERRIDE;
40
41  private:
42   // The SystemConfiguration calls in this function can lead to contention early
43   // on, so we invoke this function later on in startup to keep it fast.
44   void InitNotifications();
45
46   base::ScopedCFTypeRef<CFRunLoopSourceRef> run_loop_source_;
47   NetworkConfigWatcherMac::Delegate* const delegate_;
48   base::WeakPtrFactory<NetworkConfigWatcherMacThread> weak_factory_;
49
50   DISALLOW_COPY_AND_ASSIGN(NetworkConfigWatcherMacThread);
51 };
52
53 NetworkConfigWatcherMacThread::NetworkConfigWatcherMacThread(
54     NetworkConfigWatcherMac::Delegate* delegate)
55     : base::Thread("NetworkConfigWatcher"),
56       delegate_(delegate),
57       weak_factory_(this) {}
58
59 NetworkConfigWatcherMacThread::~NetworkConfigWatcherMacThread() {
60   // Allow IO because Stop() calls PlatformThread::Join(), which is a blocking
61   // operation. This is expected during shutdown.
62   base::ThreadRestrictions::ScopedAllowIO allow_io;
63
64   Stop();
65 }
66
67 void NetworkConfigWatcherMacThread::Init() {
68   // Disallow IO to make sure NetworkConfigWatcherMacThread's helper thread does
69   // not perform blocking operations.
70   base::ThreadRestrictions::SetIOAllowed(false);
71
72   delegate_->Init();
73
74   // TODO(willchan): Look to see if there's a better signal for when it's ok to
75   // initialize this, rather than just delaying it by a fixed time.
76   const base::TimeDelta kInitializationDelay = base::TimeDelta::FromSeconds(1);
77   message_loop()->PostDelayedTask(
78       FROM_HERE,
79       base::Bind(&NetworkConfigWatcherMacThread::InitNotifications,
80                  weak_factory_.GetWeakPtr()),
81       kInitializationDelay);
82 }
83
84 void NetworkConfigWatcherMacThread::CleanUp() {
85   if (!run_loop_source_.get())
86     return;
87
88   CFRunLoopRemoveSource(CFRunLoopGetCurrent(), run_loop_source_.get(),
89                         kCFRunLoopCommonModes);
90   run_loop_source_.reset();
91 }
92
93 void NetworkConfigWatcherMacThread::InitNotifications() {
94 #if !defined(OS_IOS)
95   // SCDynamicStore API does not exist on iOS.
96   // Add a run loop source for a dynamic store to the current run loop.
97   SCDynamicStoreContext context = {
98     0,          // Version 0.
99     delegate_,  // User data.
100     NULL,       // This is not reference counted.  No retain function.
101     NULL,       // This is not reference counted.  No release function.
102     NULL,       // No description for this.
103   };
104   base::ScopedCFTypeRef<SCDynamicStoreRef> store(SCDynamicStoreCreate(
105       NULL, CFSTR("org.chromium"), DynamicStoreCallback, &context));
106   run_loop_source_.reset(SCDynamicStoreCreateRunLoopSource(
107       NULL, store.get(), 0));
108   CFRunLoopAddSource(CFRunLoopGetCurrent(), run_loop_source_.get(),
109                      kCFRunLoopCommonModes);
110 #endif  // !defined(OS_IOS)
111
112   // Set up notifications for interface and IP address changes.
113   delegate_->StartReachabilityNotifications();
114 #if !defined(OS_IOS)
115   delegate_->SetDynamicStoreNotificationKeys(store.get());
116 #endif  // !defined(OS_IOS)
117 }
118
119 }  // namespace
120
121 NetworkConfigWatcherMac::NetworkConfigWatcherMac(Delegate* delegate)
122     : notifier_thread_(new NetworkConfigWatcherMacThread(delegate)) {
123   // We create this notifier thread because the notification implementation
124   // needs a thread with a CFRunLoop, and there's no guarantee that
125   // MessageLoop::current() meets that criterion.
126   base::Thread::Options thread_options(base::MessageLoop::TYPE_UI, 0);
127   notifier_thread_->StartWithOptions(thread_options);
128 }
129
130 NetworkConfigWatcherMac::~NetworkConfigWatcherMac() {}
131
132 }  // namespace net