| 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> | 8 #include <resolv.h> |
| 9 | 9 |
| 10 #include "base/basictypes.h" | 10 #include "base/basictypes.h" |
| (...skipping 28 matching lines...) Expand all Loading... |
| 39 watcher_.CleanUp(); | 39 watcher_.CleanUp(); |
| 40 } | 40 } |
| 41 | 41 |
| 42 private: | 42 private: |
| 43 internal::DnsConfigWatcher watcher_; | 43 internal::DnsConfigWatcher watcher_; |
| 44 | 44 |
| 45 DISALLOW_COPY_AND_ASSIGN(DnsWatcherThread); | 45 DISALLOW_COPY_AND_ASSIGN(DnsWatcherThread); |
| 46 }; | 46 }; |
| 47 | 47 |
| 48 NetworkChangeNotifierMac::NetworkChangeNotifierMac() | 48 NetworkChangeNotifierMac::NetworkChangeNotifierMac() |
| 49 : online_state_(UNINITIALIZED), | 49 : connection_type_(CONNECTION_UNKNOWN), |
| 50 initial_state_cv_(&online_state_lock_), | 50 connection_type_initialized_(false), |
| 51 initial_connection_type_cv_(&connection_type_lock_), |
| 51 forwarder_(this), | 52 forwarder_(this), |
| 52 dns_watcher_thread_(new DnsWatcherThread()) { | 53 dns_watcher_thread_(new DnsWatcherThread()) { |
| 53 // Must be initialized after the rest of this object, as it may call back into | 54 // Must be initialized after the rest of this object, as it may call back into |
| 54 // SetInitialState(). | 55 // SetInitialConnectionType(). |
| 55 config_watcher_.reset(new NetworkConfigWatcherMac(&forwarder_)); | 56 config_watcher_.reset(new NetworkConfigWatcherMac(&forwarder_)); |
| 56 dns_watcher_thread_->StartWithOptions( | 57 dns_watcher_thread_->StartWithOptions( |
| 57 base::Thread::Options(MessageLoop::TYPE_IO, 0)); | 58 base::Thread::Options(MessageLoop::TYPE_IO, 0)); |
| 58 } | 59 } |
| 59 | 60 |
| 60 NetworkChangeNotifierMac::~NetworkChangeNotifierMac() { | 61 NetworkChangeNotifierMac::~NetworkChangeNotifierMac() { |
| 61 // Delete the ConfigWatcher to join the notifier thread, ensuring that | 62 // Delete the ConfigWatcher to join the notifier thread, ensuring that |
| 62 // StartReachabilityNotifications() has an opportunity to run to completion. | 63 // StartReachabilityNotifications() has an opportunity to run to completion. |
| 63 config_watcher_.reset(); | 64 config_watcher_.reset(); |
| 64 | 65 |
| 65 // Now that StartReachabilityNotifications() has either run to completion or | 66 // Now that StartReachabilityNotifications() has either run to completion or |
| 66 // never run at all, unschedule reachability_ if it was previously scheduled. | 67 // never run at all, unschedule reachability_ if it was previously scheduled. |
| 67 if (reachability_.get() && run_loop_.get()) { | 68 if (reachability_.get() && run_loop_.get()) { |
| 68 SCNetworkReachabilityUnscheduleFromRunLoop(reachability_.get(), | 69 SCNetworkReachabilityUnscheduleFromRunLoop(reachability_.get(), |
| 69 run_loop_.get(), | 70 run_loop_.get(), |
| 70 kCFRunLoopCommonModes); | 71 kCFRunLoopCommonModes); |
| 71 } | 72 } |
| 72 } | 73 } |
| 73 | 74 |
| 74 bool NetworkChangeNotifierMac::IsCurrentlyOffline() const { | 75 NetworkChangeNotifier::ConnectionType |
| 75 base::AutoLock lock(online_state_lock_); | 76 NetworkChangeNotifierMac::GetCurrentConnectionType() const { |
| 76 // Make sure the initial state is set before returning. | 77 base::AutoLock lock(connection_type_lock_); |
| 77 while (online_state_ == UNINITIALIZED) { | 78 // Make sure the initial connection type is set before returning. |
| 78 initial_state_cv_.Wait(); | 79 while (!connection_type_initialized_) { |
| 80 initial_connection_type_cv_.Wait(); |
| 79 } | 81 } |
| 80 return online_state_ == OFFLINE; | 82 return connection_type_; |
| 81 } | 83 } |
| 82 | 84 |
| 83 void NetworkChangeNotifierMac::SetInitialState() { | 85 void NetworkChangeNotifierMac::SetInitialConnectionType() { |
| 84 // Called on notifier thread. | 86 // Called on notifier thread. |
| 85 | 87 |
| 86 // Try to reach 0.0.0.0. This is the approach taken by Firefox: | 88 // Try to reach 0.0.0.0. This is the approach taken by Firefox: |
| 87 // | 89 // |
| 88 // http://mxr.mozilla.org/mozilla2.0/source/netwerk/system/mac/nsNetworkLinkSe
rvice.mm | 90 // http://mxr.mozilla.org/mozilla2.0/source/netwerk/system/mac/nsNetworkLinkSe
rvice.mm |
| 89 // | 91 // |
| 90 // From my (adamk) testing on Snow Leopard, 0.0.0.0 | 92 // From my (adamk) testing on Snow Leopard, 0.0.0.0 |
| 91 // seems to be reachable if any network connection is available. | 93 // seems to be reachable if any network connection is available. |
| 92 struct sockaddr_in addr = {0}; | 94 struct sockaddr_in addr = {0}; |
| 93 addr.sin_len = sizeof(addr); | 95 addr.sin_len = sizeof(addr); |
| 94 addr.sin_family = AF_INET; | 96 addr.sin_family = AF_INET; |
| 95 reachability_.reset(SCNetworkReachabilityCreateWithAddress( | 97 reachability_.reset(SCNetworkReachabilityCreateWithAddress( |
| 96 kCFAllocatorDefault, reinterpret_cast<struct sockaddr*>(&addr))); | 98 kCFAllocatorDefault, reinterpret_cast<struct sockaddr*>(&addr))); |
| 97 | 99 |
| 98 SCNetworkConnectionFlags flags; | 100 SCNetworkConnectionFlags flags; |
| 99 bool reachable = true; | 101 bool reachable = true; |
| 100 if (SCNetworkReachabilityGetFlags(reachability_, &flags)) | 102 if (SCNetworkReachabilityGetFlags(reachability_, &flags)) |
| 101 reachable = CalculateReachability(flags); | 103 reachable = CalculateReachability(flags); |
| 102 else | 104 else |
| 103 LOG(ERROR) << "Could not get initial network state, assuming online."; | 105 LOG(ERROR) << "Could not get initial network connection type," |
| 106 << "assuming online."; |
| 104 { | 107 { |
| 105 base::AutoLock lock(online_state_lock_); | 108 base::AutoLock lock(connection_type_lock_); |
| 106 online_state_ = reachable ? ONLINE : OFFLINE; | 109 // TODO(droger): Get something more detailed than CONNECTION_UNKNOWN. |
| 107 initial_state_cv_.Signal(); | 110 connection_type_ = reachable ? CONNECTION_UNKNOWN : CONNECTION_NONE; |
| 111 connection_type_initialized_ = true; |
| 112 initial_connection_type_cv_.Signal(); |
| 108 } | 113 } |
| 109 } | 114 } |
| 110 | 115 |
| 111 void NetworkChangeNotifierMac::StartReachabilityNotifications() { | 116 void NetworkChangeNotifierMac::StartReachabilityNotifications() { |
| 112 // Called on notifier thread. | 117 // Called on notifier thread. |
| 113 run_loop_.reset(CFRunLoopGetCurrent()); | 118 run_loop_.reset(CFRunLoopGetCurrent()); |
| 114 CFRetain(run_loop_.get()); | 119 CFRetain(run_loop_.get()); |
| 115 | 120 |
| 116 DCHECK(reachability_); | 121 DCHECK(reachability_); |
| 117 SCNetworkReachabilityContext reachability_context = { | 122 SCNetworkReachabilityContext reachability_context = { |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 180 // static | 185 // static |
| 181 void NetworkChangeNotifierMac::ReachabilityCallback( | 186 void NetworkChangeNotifierMac::ReachabilityCallback( |
| 182 SCNetworkReachabilityRef target, | 187 SCNetworkReachabilityRef target, |
| 183 SCNetworkConnectionFlags flags, | 188 SCNetworkConnectionFlags flags, |
| 184 void* notifier) { | 189 void* notifier) { |
| 185 NetworkChangeNotifierMac* notifier_mac = | 190 NetworkChangeNotifierMac* notifier_mac = |
| 186 static_cast<NetworkChangeNotifierMac*>(notifier); | 191 static_cast<NetworkChangeNotifierMac*>(notifier); |
| 187 | 192 |
| 188 DCHECK_EQ(notifier_mac->run_loop_.get(), CFRunLoopGetCurrent()); | 193 DCHECK_EQ(notifier_mac->run_loop_.get(), CFRunLoopGetCurrent()); |
| 189 | 194 |
| 190 OnlineState new_state = CalculateReachability(flags) ? ONLINE : OFFLINE; | 195 // TODO(droger): Get something more detailed than CONNECTION_UNKNOWN. |
| 191 OnlineState old_state; | 196 ConnectionType new_type = CalculateReachability(flags) ? CONNECTION_UNKNOWN |
| 197 : CONNECTION_NONE; |
| 198 ConnectionType old_type; |
| 192 { | 199 { |
| 193 base::AutoLock lock(notifier_mac->online_state_lock_); | 200 base::AutoLock lock(notifier_mac->connection_type_lock_); |
| 194 old_state = notifier_mac->online_state_; | 201 old_type = notifier_mac->connection_type_; |
| 195 notifier_mac->online_state_ = new_state; | 202 notifier_mac->connection_type_ = new_type; |
| 196 } | 203 } |
| 197 if (old_state != new_state) | 204 if (old_type != new_type) |
| 198 NotifyObserversOfOnlineStateChange(); | 205 NotifyObserversOfConnectionTypeChange(); |
| 199 } | 206 } |
| 200 | 207 |
| 201 } // namespace net | 208 } // namespace net |
| OLD | NEW |