| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/base/network_change_notifier_mac.h" | 5 #include "net/base/network_change_notifier_mac.h" |
| 6 | 6 |
| 7 #include <netinet/in.h> | 7 #include <netinet/in.h> |
| 8 #include <resolv.h> |
| 9 |
| 10 #ifndef _PATH_RESCONF // Normally defined in <resolv.h> |
| 11 #define _PATH_RESCONF "/etc/resolv.conf" |
| 12 #endif |
| 8 | 13 |
| 9 namespace net { | 14 namespace net { |
| 10 | 15 |
| 11 static bool CalculateReachability(SCNetworkConnectionFlags flags) { | 16 static bool CalculateReachability(SCNetworkConnectionFlags flags) { |
| 12 bool reachable = flags & kSCNetworkFlagsReachable; | 17 bool reachable = flags & kSCNetworkFlagsReachable; |
| 13 bool connection_required = flags & kSCNetworkFlagsConnectionRequired; | 18 bool connection_required = flags & kSCNetworkFlagsConnectionRequired; |
| 14 return reachable && !connection_required; | 19 return reachable && !connection_required; |
| 15 } | 20 } |
| 16 | 21 |
| 17 NetworkChangeNotifierMac::NetworkChangeNotifierMac() | 22 NetworkChangeNotifierMac::NetworkChangeNotifierMac() |
| 18 : online_state_(UNINITIALIZED), | 23 : online_state_(UNINITIALIZED), |
| 19 initial_state_cv_(&online_state_lock_), | 24 initial_state_cv_(&online_state_lock_), |
| 20 forwarder_(this) { | 25 forwarder_(this), |
| 26 watching_dns_(false) { |
| 21 // Must be initialized after the rest of this object, as it may call back into | 27 // Must be initialized after the rest of this object, as it may call back into |
| 22 // SetInitialState(). | 28 // SetInitialState(). |
| 23 config_watcher_.reset(new NetworkConfigWatcherMac(&forwarder_)); | 29 config_watcher_.reset(new NetworkConfigWatcherMac(&forwarder_)); |
| 30 |
| 31 base::AutoLock lock(watching_dns_lock_); |
| 32 watching_dns_ = true; |
| 33 if (!resolv_watcher_.Watch( |
| 34 FilePath(FILE_PATH_LITERAL(_PATH_RESCONF)), |
| 35 base::Bind(&NetworkChangeNotifierMac::OnDNSFileChanged, |
| 36 base::Unretained(this), |
| 37 static_cast<unsigned>(CHANGE_DNS_SETTINGS)))) { |
| 38 LOG(ERROR) << "Failed to setup watch for /etc/resolv.conf"; |
| 39 watching_dns_ = false; |
| 40 } |
| 41 if (!hosts_watcher_.Watch( |
| 42 FilePath(FILE_PATH_LITERAL("/etc/hosts")), |
| 43 base::Bind(&NetworkChangeNotifierMac::OnDNSFileChanged, |
| 44 base::Unretained(this), |
| 45 static_cast<unsigned>(CHANGE_DNS_HOSTS)))) { |
| 46 LOG(ERROR) << "Failed to setup watch for /etc/hosts"; |
| 47 watching_dns_ = false; |
| 48 } |
| 24 } | 49 } |
| 25 | 50 |
| 26 NetworkChangeNotifierMac::~NetworkChangeNotifierMac() { | 51 NetworkChangeNotifierMac::~NetworkChangeNotifierMac() { |
| 27 // Delete the ConfigWatcher to join the notifier thread, ensuring that | 52 // Delete the ConfigWatcher to join the notifier thread, ensuring that |
| 28 // StartReachabilityNotifications() has an opportunity to run to completion. | 53 // StartReachabilityNotifications() has an opportunity to run to completion. |
| 29 config_watcher_.reset(); | 54 config_watcher_.reset(); |
| 30 | 55 |
| 31 // Now that StartReachabilityNotifications() has either run to completion or | 56 // Now that StartReachabilityNotifications() has either run to completion or |
| 32 // never run at all, unschedule reachability_ if it was previously scheduled. | 57 // never run at all, unschedule reachability_ if it was previously scheduled. |
| 33 if (reachability_.get() && run_loop_.get()) { | 58 if (reachability_.get() && run_loop_.get()) { |
| 34 SCNetworkReachabilityUnscheduleFromRunLoop(reachability_.get(), | 59 SCNetworkReachabilityUnscheduleFromRunLoop(reachability_.get(), |
| 35 run_loop_.get(), | 60 run_loop_.get(), |
| 36 kCFRunLoopCommonModes); | 61 kCFRunLoopCommonModes); |
| 37 } | 62 } |
| 38 } | 63 } |
| 39 | 64 |
| 40 bool NetworkChangeNotifierMac::IsCurrentlyOffline() const { | 65 bool NetworkChangeNotifierMac::IsCurrentlyOffline() const { |
| 41 base::AutoLock lock(online_state_lock_); | 66 base::AutoLock lock(online_state_lock_); |
| 42 // Make sure the initial state is set before returning. | 67 // Make sure the initial state is set before returning. |
| 43 while (online_state_ == UNINITIALIZED) { | 68 while (online_state_ == UNINITIALIZED) { |
| 44 initial_state_cv_.Wait(); | 69 initial_state_cv_.Wait(); |
| 45 } | 70 } |
| 46 return online_state_ == OFFLINE; | 71 return online_state_ == OFFLINE; |
| 47 } | 72 } |
| 48 | 73 |
| 74 bool NetworkChangeNotifierMac::IsCurrentlyWatchingDNS() const { |
| 75 base::AutoLock lock(watching_dns_lock_); |
| 76 return watching_dns_ == OFFLINE; |
| 77 } |
| 78 |
| 49 void NetworkChangeNotifierMac::SetInitialState() { | 79 void NetworkChangeNotifierMac::SetInitialState() { |
| 50 // Called on notifier thread. | 80 // Called on notifier thread. |
| 51 | 81 |
| 52 // Try to reach 0.0.0.0. This is the approach taken by Firefox: | 82 // Try to reach 0.0.0.0. This is the approach taken by Firefox: |
| 53 // | 83 // |
| 54 // http://mxr.mozilla.org/mozilla2.0/source/netwerk/system/mac/nsNetworkLinkSe
rvice.mm | 84 // http://mxr.mozilla.org/mozilla2.0/source/netwerk/system/mac/nsNetworkLinkSe
rvice.mm |
| 55 // | 85 // |
| 56 // From my (adamk) testing on Snow Leopard, 0.0.0.0 | 86 // From my (adamk) testing on Snow Leopard, 0.0.0.0 |
| 57 // seems to be reachable if any network connection is available. | 87 // seems to be reachable if any network connection is available. |
| 58 struct sockaddr_in addr = {0}; | 88 struct sockaddr_in addr = {0}; |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 136 } | 166 } |
| 137 if (CFStringHasSuffix(key, kSCEntNetInterface)) { | 167 if (CFStringHasSuffix(key, kSCEntNetInterface)) { |
| 138 // TODO(willchan): Does not appear to be working. Look into this. | 168 // TODO(willchan): Does not appear to be working. Look into this. |
| 139 // Perhaps this isn't needed anyway. | 169 // Perhaps this isn't needed anyway. |
| 140 } else { | 170 } else { |
| 141 NOTREACHED(); | 171 NOTREACHED(); |
| 142 } | 172 } |
| 143 } | 173 } |
| 144 } | 174 } |
| 145 | 175 |
| 176 void NetworkChangeNotifierMac::OnDNSFileChanged(unsigned detail, |
| 177 bool watch_success) { |
| 178 if (!watch_success) { |
| 179 LOG(ERROR) << "DNS watch failed."; |
| 180 base::AutoLock lock(watching_dns_lock_); |
| 181 watching_dns_ = false; |
| 182 } |
| 183 // Always notify observers so that they can check IsWatchingDNS(). |
| 184 NetworkChangeNotifier::NotifyObserversOfDNSChange(detail); |
| 185 } |
| 186 |
| 146 // static | 187 // static |
| 147 void NetworkChangeNotifierMac::ReachabilityCallback( | 188 void NetworkChangeNotifierMac::ReachabilityCallback( |
| 148 SCNetworkReachabilityRef target, | 189 SCNetworkReachabilityRef target, |
| 149 SCNetworkConnectionFlags flags, | 190 SCNetworkConnectionFlags flags, |
| 150 void* notifier) { | 191 void* notifier) { |
| 151 NetworkChangeNotifierMac* notifier_mac = | 192 NetworkChangeNotifierMac* notifier_mac = |
| 152 static_cast<NetworkChangeNotifierMac*>(notifier); | 193 static_cast<NetworkChangeNotifierMac*>(notifier); |
| 153 | 194 |
| 154 DCHECK_EQ(notifier_mac->run_loop_.get(), CFRunLoopGetCurrent()); | 195 DCHECK_EQ(notifier_mac->run_loop_.get(), CFRunLoopGetCurrent()); |
| 155 | 196 |
| 156 OnlineState new_state = CalculateReachability(flags) ? ONLINE : OFFLINE; | 197 OnlineState new_state = CalculateReachability(flags) ? ONLINE : OFFLINE; |
| 157 OnlineState old_state; | 198 OnlineState old_state; |
| 158 { | 199 { |
| 159 base::AutoLock lock(notifier_mac->online_state_lock_); | 200 base::AutoLock lock(notifier_mac->online_state_lock_); |
| 160 old_state = notifier_mac->online_state_; | 201 old_state = notifier_mac->online_state_; |
| 161 notifier_mac->online_state_ = new_state; | 202 notifier_mac->online_state_ = new_state; |
| 162 } | 203 } |
| 163 if (old_state != new_state) | 204 if (old_state != new_state) |
| 164 NotifyObserversOfOnlineStateChange(); | 205 NotifyObserversOfOnlineStateChange(); |
| 165 } | 206 } |
| 166 | 207 |
| 167 } // namespace net | 208 } // namespace net |
| OLD | NEW |