| 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..a4c4d2d4c95859237f1a9455ef77469b1f35f170 100644
|
| --- a/net/base/network_change_notifier_mac.cc
|
| +++ b/net/base/network_change_notifier_mac.cc
|
| @@ -1,10 +1,12 @@
|
| -// Copyright (c) 2010 The Chromium Authors. All rights reserved.
|
| +// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| #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/mac/scoped_cftyperef.h"
|
| @@ -13,17 +15,27 @@ namespace net {
|
|
|
| NetworkChangeNotifierMac::NetworkChangeNotifierMac()
|
| : forwarder_(this),
|
| - config_watcher_(&forwarder_) {}
|
| -NetworkChangeNotifierMac::~NetworkChangeNotifierMac() {}
|
| + config_watcher_(&forwarder_),
|
| + network_reachable_(true) {}
|
| +
|
| +NetworkChangeNotifierMac::~NetworkChangeNotifierMac() {
|
| + if (reachability_.get() && run_loop_.get()) {
|
| + SCNetworkReachabilityUnscheduleFromRunLoop(reachability_.get(),
|
| + run_loop_.get(),
|
| + kCFRunLoopCommonModes);
|
| + }
|
| +}
|
|
|
| bool NetworkChangeNotifierMac::IsCurrentlyOffline() const {
|
| - // TODO(eroman): http://crbug.com/53473
|
| - return false;
|
| + return !network_reachable_;
|
| }
|
|
|
| void NetworkChangeNotifierMac::SetDynamicStoreNotificationKeys(
|
| SCDynamicStoreRef store) {
|
| // Called on notifier thread.
|
| + run_loop_.reset(CFRunLoopGetCurrent());
|
| + CFRetain(run_loop_.get());
|
| +
|
| base::mac::ScopedCFTypeRef<CFMutableArrayRef> notification_keys(
|
| CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks));
|
| base::mac::ScopedCFTypeRef<CFStringRef> key(
|
| @@ -42,10 +54,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_EQ(run_loop_.get(), CFRunLoopGetCurrent());
|
|
|
| for (CFIndex i = 0; i < CFArrayGetCount(changed_keys); ++i) {
|
| CFStringRef key = static_cast<CFStringRef>(
|
| @@ -64,4 +107,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_EQ(notifier_mac->run_loop_.get(), CFRunLoopGetCurrent());
|
| +
|
| + 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
|
|
|