Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(21)

Side by Side Diff: net/base/network_change_notifier_mac.cc

Issue 992733002: Remove //net (except for Android test stuff) and sdch (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/base/network_change_notifier_mac.h ('k') | net/base/network_change_notifier_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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_change_notifier_mac.h"
6
7 #include <netinet/in.h>
8 #include <resolv.h>
9
10 #include "base/basictypes.h"
11 #include "base/threading/thread.h"
12 #include "net/dns/dns_config_service.h"
13
14 namespace net {
15
16 static bool CalculateReachability(SCNetworkConnectionFlags flags) {
17 bool reachable = flags & kSCNetworkFlagsReachable;
18 bool connection_required = flags & kSCNetworkFlagsConnectionRequired;
19 return reachable && !connection_required;
20 }
21
22 NetworkChangeNotifier::ConnectionType CalculateConnectionType(
23 SCNetworkConnectionFlags flags) {
24 bool reachable = CalculateReachability(flags);
25 if (reachable) {
26 #if defined(OS_IOS)
27 return (flags & kSCNetworkReachabilityFlagsIsWWAN) ?
28 NetworkChangeNotifier::CONNECTION_3G :
29 NetworkChangeNotifier::CONNECTION_WIFI;
30 #else
31 // TODO(droger): Get something more detailed than CONNECTION_UNKNOWN.
32 // http://crbug.com/112937
33 return NetworkChangeNotifier::CONNECTION_UNKNOWN;
34 #endif // defined(OS_IOS)
35 } else {
36 return NetworkChangeNotifier::CONNECTION_NONE;
37 }
38 }
39
40 // Thread on which we can run DnsConfigService, which requires a TYPE_IO
41 // message loop.
42 class NetworkChangeNotifierMac::DnsConfigServiceThread : public base::Thread {
43 public:
44 DnsConfigServiceThread() : base::Thread("DnsConfigService") {}
45
46 ~DnsConfigServiceThread() override { Stop(); }
47
48 void Init() override {
49 service_ = DnsConfigService::CreateSystemService();
50 service_->WatchConfig(base::Bind(&NetworkChangeNotifier::SetDnsConfig));
51 }
52
53 void CleanUp() override { service_.reset(); }
54
55 private:
56 scoped_ptr<DnsConfigService> service_;
57
58 DISALLOW_COPY_AND_ASSIGN(DnsConfigServiceThread);
59 };
60
61 NetworkChangeNotifierMac::NetworkChangeNotifierMac()
62 : NetworkChangeNotifier(NetworkChangeCalculatorParamsMac()),
63 connection_type_(CONNECTION_UNKNOWN),
64 connection_type_initialized_(false),
65 initial_connection_type_cv_(&connection_type_lock_),
66 forwarder_(this),
67 dns_config_service_thread_(new DnsConfigServiceThread()) {
68 // Must be initialized after the rest of this object, as it may call back into
69 // SetInitialConnectionType().
70 config_watcher_.reset(new NetworkConfigWatcherMac(&forwarder_));
71 dns_config_service_thread_->StartWithOptions(
72 base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
73 }
74
75 NetworkChangeNotifierMac::~NetworkChangeNotifierMac() {
76 // Delete the ConfigWatcher to join the notifier thread, ensuring that
77 // StartReachabilityNotifications() has an opportunity to run to completion.
78 config_watcher_.reset();
79
80 // Now that StartReachabilityNotifications() has either run to completion or
81 // never run at all, unschedule reachability_ if it was previously scheduled.
82 if (reachability_.get() && run_loop_.get()) {
83 SCNetworkReachabilityUnscheduleFromRunLoop(reachability_.get(),
84 run_loop_.get(),
85 kCFRunLoopCommonModes);
86 }
87 }
88
89 // static
90 NetworkChangeNotifier::NetworkChangeCalculatorParams
91 NetworkChangeNotifierMac::NetworkChangeCalculatorParamsMac() {
92 NetworkChangeCalculatorParams params;
93 // Delay values arrived at by simple experimentation and adjusted so as to
94 // produce a single signal when switching between network connections.
95 params.ip_address_offline_delay_ = base::TimeDelta::FromMilliseconds(500);
96 params.ip_address_online_delay_ = base::TimeDelta::FromMilliseconds(500);
97 params.connection_type_offline_delay_ =
98 base::TimeDelta::FromMilliseconds(1000);
99 params.connection_type_online_delay_ = base::TimeDelta::FromMilliseconds(500);
100 return params;
101 }
102
103 NetworkChangeNotifier::ConnectionType
104 NetworkChangeNotifierMac::GetCurrentConnectionType() const {
105 base::AutoLock lock(connection_type_lock_);
106 // Make sure the initial connection type is set before returning.
107 while (!connection_type_initialized_) {
108 initial_connection_type_cv_.Wait();
109 }
110 return connection_type_;
111 }
112
113 void NetworkChangeNotifierMac::Forwarder::Init() {
114 net_config_watcher_->SetInitialConnectionType();
115 }
116
117 void NetworkChangeNotifierMac::Forwarder::StartReachabilityNotifications() {
118 net_config_watcher_->StartReachabilityNotifications();
119 }
120
121 void NetworkChangeNotifierMac::Forwarder::SetDynamicStoreNotificationKeys(
122 SCDynamicStoreRef store) {
123 net_config_watcher_->SetDynamicStoreNotificationKeys(store);
124 }
125
126 void NetworkChangeNotifierMac::Forwarder::OnNetworkConfigChange(
127 CFArrayRef changed_keys) {
128 net_config_watcher_->OnNetworkConfigChange(changed_keys);
129 }
130
131 void NetworkChangeNotifierMac::SetInitialConnectionType() {
132 // Called on notifier thread.
133
134 // Try to reach 0.0.0.0. This is the approach taken by Firefox:
135 //
136 // http://mxr.mozilla.org/mozilla2.0/source/netwerk/system/mac/nsNetworkLinkSe rvice.mm
137 //
138 // From my (adamk) testing on Snow Leopard, 0.0.0.0
139 // seems to be reachable if any network connection is available.
140 struct sockaddr_in addr = {0};
141 addr.sin_len = sizeof(addr);
142 addr.sin_family = AF_INET;
143 reachability_.reset(SCNetworkReachabilityCreateWithAddress(
144 kCFAllocatorDefault, reinterpret_cast<struct sockaddr*>(&addr)));
145
146 SCNetworkConnectionFlags flags;
147 ConnectionType connection_type = CONNECTION_UNKNOWN;
148 if (SCNetworkReachabilityGetFlags(reachability_, &flags)) {
149 connection_type = CalculateConnectionType(flags);
150 } else {
151 LOG(ERROR) << "Could not get initial network connection type,"
152 << "assuming online.";
153 }
154 {
155 base::AutoLock lock(connection_type_lock_);
156 connection_type_ = connection_type;
157 connection_type_initialized_ = true;
158 initial_connection_type_cv_.Signal();
159 }
160 }
161
162 void NetworkChangeNotifierMac::StartReachabilityNotifications() {
163 // Called on notifier thread.
164 run_loop_.reset(CFRunLoopGetCurrent());
165 CFRetain(run_loop_.get());
166
167 DCHECK(reachability_);
168 SCNetworkReachabilityContext reachability_context = {
169 0, // version
170 this, // user data
171 NULL, // retain
172 NULL, // release
173 NULL // description
174 };
175 if (!SCNetworkReachabilitySetCallback(
176 reachability_,
177 &NetworkChangeNotifierMac::ReachabilityCallback,
178 &reachability_context)) {
179 LOG(DFATAL) << "Could not set network reachability callback";
180 reachability_.reset();
181 } else if (!SCNetworkReachabilityScheduleWithRunLoop(reachability_,
182 run_loop_,
183 kCFRunLoopCommonModes)) {
184 LOG(DFATAL) << "Could not schedule network reachability on run loop";
185 reachability_.reset();
186 }
187 }
188
189 void NetworkChangeNotifierMac::SetDynamicStoreNotificationKeys(
190 SCDynamicStoreRef store) {
191 #if defined(OS_IOS)
192 // SCDynamicStore API does not exist on iOS.
193 NOTREACHED();
194 #else
195 base::ScopedCFTypeRef<CFMutableArrayRef> notification_keys(
196 CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks));
197 base::ScopedCFTypeRef<CFStringRef> key(
198 SCDynamicStoreKeyCreateNetworkGlobalEntity(
199 NULL, kSCDynamicStoreDomainState, kSCEntNetInterface));
200 CFArrayAppendValue(notification_keys.get(), key.get());
201 key.reset(SCDynamicStoreKeyCreateNetworkGlobalEntity(
202 NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4));
203 CFArrayAppendValue(notification_keys.get(), key.get());
204 key.reset(SCDynamicStoreKeyCreateNetworkGlobalEntity(
205 NULL, kSCDynamicStoreDomainState, kSCEntNetIPv6));
206 CFArrayAppendValue(notification_keys.get(), key.get());
207
208 // Set the notification keys. This starts us receiving notifications.
209 bool ret = SCDynamicStoreSetNotificationKeys(
210 store, notification_keys.get(), NULL);
211 // TODO(willchan): Figure out a proper way to handle this rather than crash.
212 CHECK(ret);
213 #endif // defined(OS_IOS)
214 }
215
216 void NetworkChangeNotifierMac::OnNetworkConfigChange(CFArrayRef changed_keys) {
217 #if defined(OS_IOS)
218 // SCDynamicStore API does not exist on iOS.
219 NOTREACHED();
220 #else
221 DCHECK_EQ(run_loop_.get(), CFRunLoopGetCurrent());
222
223 for (CFIndex i = 0; i < CFArrayGetCount(changed_keys); ++i) {
224 CFStringRef key = static_cast<CFStringRef>(
225 CFArrayGetValueAtIndex(changed_keys, i));
226 if (CFStringHasSuffix(key, kSCEntNetIPv4) ||
227 CFStringHasSuffix(key, kSCEntNetIPv6)) {
228 NotifyObserversOfIPAddressChange();
229 return;
230 }
231 if (CFStringHasSuffix(key, kSCEntNetInterface)) {
232 // TODO(willchan): Does not appear to be working. Look into this.
233 // Perhaps this isn't needed anyway.
234 } else {
235 NOTREACHED();
236 }
237 }
238 #endif // defined(OS_IOS)
239 }
240
241 // static
242 void NetworkChangeNotifierMac::ReachabilityCallback(
243 SCNetworkReachabilityRef target,
244 SCNetworkConnectionFlags flags,
245 void* notifier) {
246 NetworkChangeNotifierMac* notifier_mac =
247 static_cast<NetworkChangeNotifierMac*>(notifier);
248
249 DCHECK_EQ(notifier_mac->run_loop_.get(), CFRunLoopGetCurrent());
250
251 ConnectionType new_type = CalculateConnectionType(flags);
252 ConnectionType old_type;
253 {
254 base::AutoLock lock(notifier_mac->connection_type_lock_);
255 old_type = notifier_mac->connection_type_;
256 notifier_mac->connection_type_ = new_type;
257 }
258 if (old_type != new_type)
259 NotifyObserversOfConnectionTypeChange();
260
261 #if defined(OS_IOS)
262 // On iOS, the SCDynamicStore API does not exist, and we use the reachability
263 // API to detect IP address changes instead.
264 NotifyObserversOfIPAddressChange();
265 #endif // defined(OS_IOS)
266 }
267
268 } // namespace net
OLDNEW
« no previous file with comments | « net/base/network_change_notifier_mac.h ('k') | net/base/network_change_notifier_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698