| 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 | 8 |
| 9 namespace net { | 9 namespace net { |
| 10 | 10 |
| 11 static bool CalculateReachability(SCNetworkConnectionFlags flags) { | 11 static bool CalculateReachability(SCNetworkConnectionFlags flags) { |
| 12 bool reachable = flags & kSCNetworkFlagsReachable; | 12 bool reachable = flags & kSCNetworkFlagsReachable; |
| 13 bool connection_required = flags & kSCNetworkFlagsConnectionRequired; | 13 bool connection_required = flags & kSCNetworkFlagsConnectionRequired; |
| 14 return reachable && !connection_required; | 14 return reachable && !connection_required; |
| 15 } | 15 } |
| 16 | 16 |
| 17 NetworkChangeNotifierMac::NetworkChangeNotifierMac() | 17 NetworkChangeNotifierMac::NetworkChangeNotifierMac() |
| 18 : online_state_(UNINITIALIZED), | 18 : connection_type_(CONNECTION_UNKNOWN), |
| 19 initial_state_cv_(&online_state_lock_), | 19 connection_type_initialized_(false), |
| 20 initial_state_cv_(&connection_type_lock_), |
| 20 forwarder_(this) { | 21 forwarder_(this) { |
| 21 // Must be initialized after the rest of this object, as it may call back into | 22 // Must be initialized after the rest of this object, as it may call back into |
| 22 // SetInitialState(). | 23 // SetInitialState(). |
| 23 config_watcher_.reset(new NetworkConfigWatcherMac(&forwarder_)); | 24 config_watcher_.reset(new NetworkConfigWatcherMac(&forwarder_)); |
| 24 } | 25 } |
| 25 | 26 |
| 26 NetworkChangeNotifierMac::~NetworkChangeNotifierMac() { | 27 NetworkChangeNotifierMac::~NetworkChangeNotifierMac() { |
| 27 // Delete the ConfigWatcher to join the notifier thread, ensuring that | 28 // Delete the ConfigWatcher to join the notifier thread, ensuring that |
| 28 // StartReachabilityNotifications() has an opportunity to run to completion. | 29 // StartReachabilityNotifications() has an opportunity to run to completion. |
| 29 config_watcher_.reset(); | 30 config_watcher_.reset(); |
| 30 | 31 |
| 31 // Now that StartReachabilityNotifications() has either run to completion or | 32 // Now that StartReachabilityNotifications() has either run to completion or |
| 32 // never run at all, unschedule reachability_ if it was previously scheduled. | 33 // never run at all, unschedule reachability_ if it was previously scheduled. |
| 33 if (reachability_.get() && run_loop_.get()) { | 34 if (reachability_.get() && run_loop_.get()) { |
| 34 SCNetworkReachabilityUnscheduleFromRunLoop(reachability_.get(), | 35 SCNetworkReachabilityUnscheduleFromRunLoop(reachability_.get(), |
| 35 run_loop_.get(), | 36 run_loop_.get(), |
| 36 kCFRunLoopCommonModes); | 37 kCFRunLoopCommonModes); |
| 37 } | 38 } |
| 38 } | 39 } |
| 39 | 40 |
| 40 bool NetworkChangeNotifierMac::IsCurrentlyOffline() const { | 41 NetworkChangeNotifier::ConnectionType |
| 41 base::AutoLock lock(online_state_lock_); | 42 NetworkChangeNotifierMac::GetCurrentConnectionType() const { |
| 43 base::AutoLock lock(connection_type_lock_); |
| 42 // Make sure the initial state is set before returning. | 44 // Make sure the initial state is set before returning. |
| 43 while (online_state_ == UNINITIALIZED) { | 45 while (!connection_type_initialized_) { |
| 44 initial_state_cv_.Wait(); | 46 initial_state_cv_.Wait(); |
| 45 } | 47 } |
| 46 return online_state_ == OFFLINE; | 48 return connection_type_; |
| 47 } | 49 } |
| 48 | 50 |
| 49 void NetworkChangeNotifierMac::SetInitialState() { | 51 void NetworkChangeNotifierMac::SetInitialState() { |
| 50 // Called on notifier thread. | 52 // Called on notifier thread. |
| 51 | 53 |
| 52 // Try to reach 0.0.0.0. This is the approach taken by Firefox: | 54 // Try to reach 0.0.0.0. This is the approach taken by Firefox: |
| 53 // | 55 // |
| 54 // http://mxr.mozilla.org/mozilla2.0/source/netwerk/system/mac/nsNetworkLinkSe
rvice.mm | 56 // http://mxr.mozilla.org/mozilla2.0/source/netwerk/system/mac/nsNetworkLinkSe
rvice.mm |
| 55 // | 57 // |
| 56 // From my (adamk) testing on Snow Leopard, 0.0.0.0 | 58 // From my (adamk) testing on Snow Leopard, 0.0.0.0 |
| 57 // seems to be reachable if any network connection is available. | 59 // seems to be reachable if any network connection is available. |
| 58 struct sockaddr_in addr = {0}; | 60 struct sockaddr_in addr = {0}; |
| 59 addr.sin_len = sizeof(addr); | 61 addr.sin_len = sizeof(addr); |
| 60 addr.sin_family = AF_INET; | 62 addr.sin_family = AF_INET; |
| 61 reachability_.reset(SCNetworkReachabilityCreateWithAddress( | 63 reachability_.reset(SCNetworkReachabilityCreateWithAddress( |
| 62 kCFAllocatorDefault, reinterpret_cast<struct sockaddr*>(&addr))); | 64 kCFAllocatorDefault, reinterpret_cast<struct sockaddr*>(&addr))); |
| 63 | 65 |
| 64 SCNetworkConnectionFlags flags; | 66 SCNetworkConnectionFlags flags; |
| 65 bool reachable = true; | 67 bool reachable = true; |
| 66 if (SCNetworkReachabilityGetFlags(reachability_, &flags)) | 68 if (SCNetworkReachabilityGetFlags(reachability_, &flags)) |
| 67 reachable = CalculateReachability(flags); | 69 reachable = CalculateReachability(flags); |
| 68 else | 70 else |
| 69 LOG(ERROR) << "Could not get initial network state, assuming online."; | 71 LOG(ERROR) << "Could not get initial network state, assuming online."; |
| 70 { | 72 { |
| 71 base::AutoLock lock(online_state_lock_); | 73 base::AutoLock lock(connection_type_lock_); |
| 72 online_state_ = reachable ? ONLINE : OFFLINE; | 74 // TODO(droger): Get something more detailed than CONNECTION_UNKNOWN. |
| 75 connection_type_ = reachable ? CONNECTION_UNKNOWN : CONNECTION_NONE; |
| 76 connection_type_initialized_ = true; |
| 73 initial_state_cv_.Signal(); | 77 initial_state_cv_.Signal(); |
| 74 } | 78 } |
| 75 } | 79 } |
| 76 | 80 |
| 77 void NetworkChangeNotifierMac::StartReachabilityNotifications() { | 81 void NetworkChangeNotifierMac::StartReachabilityNotifications() { |
| 78 // Called on notifier thread. | 82 // Called on notifier thread. |
| 79 run_loop_.reset(CFRunLoopGetCurrent()); | 83 run_loop_.reset(CFRunLoopGetCurrent()); |
| 80 CFRetain(run_loop_.get()); | 84 CFRetain(run_loop_.get()); |
| 81 | 85 |
| 82 DCHECK(reachability_); | 86 DCHECK(reachability_); |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 146 // static | 150 // static |
| 147 void NetworkChangeNotifierMac::ReachabilityCallback( | 151 void NetworkChangeNotifierMac::ReachabilityCallback( |
| 148 SCNetworkReachabilityRef target, | 152 SCNetworkReachabilityRef target, |
| 149 SCNetworkConnectionFlags flags, | 153 SCNetworkConnectionFlags flags, |
| 150 void* notifier) { | 154 void* notifier) { |
| 151 NetworkChangeNotifierMac* notifier_mac = | 155 NetworkChangeNotifierMac* notifier_mac = |
| 152 static_cast<NetworkChangeNotifierMac*>(notifier); | 156 static_cast<NetworkChangeNotifierMac*>(notifier); |
| 153 | 157 |
| 154 DCHECK_EQ(notifier_mac->run_loop_.get(), CFRunLoopGetCurrent()); | 158 DCHECK_EQ(notifier_mac->run_loop_.get(), CFRunLoopGetCurrent()); |
| 155 | 159 |
| 156 OnlineState new_state = CalculateReachability(flags) ? ONLINE : OFFLINE; | 160 // TODO(droger): Get something more detailed than CONNECTION_UNKNOWN. |
| 157 OnlineState old_state; | 161 ConnectionType new_type = CalculateReachability(flags) ? CONNECTION_UNKNOWN |
| 162 : CONNECTION_NONE; |
| 163 ConnectionType old_type; |
| 158 { | 164 { |
| 159 base::AutoLock lock(notifier_mac->online_state_lock_); | 165 base::AutoLock lock(notifier_mac->connection_type_lock_); |
| 160 old_state = notifier_mac->online_state_; | 166 old_type = notifier_mac->connection_type_; |
| 161 notifier_mac->online_state_ = new_state; | 167 notifier_mac->connection_type_ = new_type; |
| 162 } | 168 } |
| 163 if (old_state != new_state) | 169 if (old_type != new_type) |
| 164 NotifyObserversOfOnlineStateChange(); | 170 NotifyObserversOfConnectionTypeChange(); |
| 165 } | 171 } |
| 166 | 172 |
| 167 } // namespace net | 173 } // namespace net |
| OLD | NEW |