Chromium Code Reviews| Index: net/base/network_change_notifier_mac.cc |
| diff --git a/net/base/network_change_notifier_mac.cc b/net/base/network_change_notifier_mac.cc |
| index 7521c90bd649117a2d7b4400e2e29424d652564e..172d315757a497669eca8ad8228bff6992452dea 100644 |
| --- a/net/base/network_change_notifier_mac.cc |
| +++ b/net/base/network_change_notifier_mac.cc |
| @@ -4,26 +4,47 @@ |
| #include "net/base/network_change_notifier_mac.h" |
| +#include <netinet/in.h> |
| #include <SystemConfiguration/SCDynamicStoreKey.h> |
| +#include <SystemConfiguration/SCNetworkReachability.h> |
| #include <SystemConfiguration/SCSchemaDefinitions.h> |
| +#include "base/threading/platform_thread.h" |
| #include "base/mac/scoped_cftyperef.h" |
| namespace net { |
| +using base::PlatformThread; |
| + |
| NetworkChangeNotifierMac::NetworkChangeNotifierMac() |
| : forwarder_(this), |
| - config_watcher_(&forwarder_) {} |
| -NetworkChangeNotifierMac::~NetworkChangeNotifierMac() {} |
| + config_watcher_(&forwarder_), |
| + run_loop_(NULL), |
| + network_reachable_(true), |
| + notifier_thread_id_() {} |
| + |
| +NetworkChangeNotifierMac::~NetworkChangeNotifierMac() { |
| + if (reachability_.get() && run_loop_) { |
| + SCNetworkReachabilityUnscheduleFromRunLoop(reachability_.get(), |
| + run_loop_, |
| + kCFRunLoopCommonModes); |
| + } |
| + if (run_loop_) |
| + CFRelease(run_loop_); |
| +} |
| bool NetworkChangeNotifierMac::IsCurrentlyOffline() const { |
| - // TODO(eroman): http://crbug.com/53473 |
| - return false; |
| + return !network_reachable_; |
| } |
| void NetworkChangeNotifierMac::SetDynamicStoreNotificationKeys( |
| SCDynamicStoreRef store) { |
| // Called on notifier thread. |
| + notifier_thread_id_ = PlatformThread::CurrentId(); |
| + |
| + run_loop_ = CFRunLoopGetCurrent(); |
| + CFRetain(run_loop_); |
| + |
| base::mac::ScopedCFTypeRef<CFMutableArrayRef> notification_keys( |
| CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks)); |
| base::mac::ScopedCFTypeRef<CFStringRef> key( |
| @@ -42,10 +63,41 @@ void NetworkChangeNotifierMac::SetDynamicStoreNotificationKeys( |
| store, notification_keys.get(), NULL); |
| // TODO(willchan): Figure out a proper way to handle this rather than crash. |
| CHECK(ret); |
| + |
| + // Try to reach 0.0.0.0. This is the approach taken by Firefox: |
| + // |
| + // http://mxr.mozilla.org/mozilla2.0/source/netwerk/system/mac/nsNetworkLinkService.mm |
| + // |
| + // From my (adamk) testing on Snow Leopard, 0.0.0.0 |
| + // seems to be reachable if any network connection is available. |
| + struct sockaddr_in addr = {0}; |
| + addr.sin_len = sizeof(addr); |
| + addr.sin_family = AF_INET; |
| + reachability_.reset(SCNetworkReachabilityCreateWithAddress( |
| + kCFAllocatorDefault, reinterpret_cast<struct sockaddr*>(&addr))); |
| + SCNetworkReachabilityContext reachability_context = { |
| + 0, // version |
| + this, // user data |
| + NULL, // retain |
| + NULL, // release |
| + NULL // description |
| + }; |
| + if (!SCNetworkReachabilitySetCallback( |
| + reachability_.get(), |
| + &NetworkChangeNotifierMac::ReachabilityCallback, |
| + &reachability_context)) { |
| + LOG(DFATAL) << "Could not set network reachability callback"; |
| + reachability_.reset(); |
| + } else if (!SCNetworkReachabilityScheduleWithRunLoop(reachability_.get(), |
| + run_loop_, |
| + kCFRunLoopCommonModes)) { |
| + LOG(DFATAL) << "Could not schedule network reachability on run loop"; |
| + reachability_.reset(); |
| + } |
| } |
| void NetworkChangeNotifierMac::OnNetworkConfigChange(CFArrayRef changed_keys) { |
| - // Called on notifier thread. |
| + DCHECK(notifier_thread_id_ == PlatformThread::CurrentId()); |
|
Mark Mentovai
2011/06/02 19:46:36
You can use DCHECK_EQ here and on line 127.
This
|
| for (CFIndex i = 0; i < CFArrayGetCount(changed_keys); ++i) { |
| CFStringRef key = static_cast<CFStringRef>( |
| @@ -64,4 +116,22 @@ void NetworkChangeNotifierMac::OnNetworkConfigChange(CFArrayRef changed_keys) { |
| } |
| } |
| +// static |
| +void NetworkChangeNotifierMac::ReachabilityCallback( |
| + SCNetworkReachabilityRef target, |
| + SCNetworkConnectionFlags flags, |
| + void* notifier) { |
| + NetworkChangeNotifierMac* notifier_mac = |
| + static_cast<NetworkChangeNotifierMac*>(notifier); |
| + |
| + DCHECK(notifier_mac->notifier_thread_id_ == PlatformThread::CurrentId()); |
| + |
| + bool reachable = flags & kSCNetworkFlagsReachable; |
| + bool connection_required = flags & kSCNetworkFlagsConnectionRequired; |
| + bool old_reachability = notifier_mac->network_reachable_; |
| + notifier_mac->network_reachable_ = reachable && !connection_required; |
| + if (old_reachability != notifier_mac->network_reachable_) |
| + notifier_mac->NotifyObserversOfOnlineStateChange(); |
| +} |
| + |
| } // namespace net |