15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/network_config_watcher_mac.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/compiler_specific.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/weak_ptr.h" 129ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread_restrictions.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net { 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(OS_IOS) 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Called back by OS. Calls OnNetworkConfigChange(). 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DynamicStoreCallback(SCDynamicStoreRef /* store */, 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CFArrayRef changed_keys, 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void* config_delegate) { 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NetworkConfigWatcherMac::Delegate* net_config_delegate = 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<NetworkConfigWatcherMac::Delegate*>(config_delegate); 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net_config_delegate->OnNetworkConfigChange(changed_keys); 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // !defined(OS_IOS) 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class NetworkConfigWatcherMacThread : public base::Thread { 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NetworkConfigWatcherMacThread(NetworkConfigWatcherMac::Delegate* delegate); 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual ~NetworkConfigWatcherMacThread(); 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected: 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // base::Thread 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void Init() OVERRIDE; 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void CleanUp() OVERRIDE; 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The SystemConfiguration calls in this function can lead to contention early 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // on, so we invoke this function later on in startup to keep it fast. 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void InitNotifications(); 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 46eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::ScopedCFTypeRef<CFRunLoopSourceRef> run_loop_source_; 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NetworkConfigWatcherMac::Delegate* const delegate_; 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::WeakPtrFactory<NetworkConfigWatcherMacThread> weak_factory_; 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(NetworkConfigWatcherMacThread); 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NetworkConfigWatcherMacThread::NetworkConfigWatcherMacThread( 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NetworkConfigWatcherMac::Delegate* delegate) 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : base::Thread("NetworkConfigWatcher"), 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delegate_(delegate), 57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) weak_factory_(this) {} 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NetworkConfigWatcherMacThread::~NetworkConfigWatcherMacThread() { 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Allow IO because Stop() calls PlatformThread::Join(), which is a blocking 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // operation. This is expected during shutdown. 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::ThreadRestrictions::ScopedAllowIO allow_io; 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Stop(); 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NetworkConfigWatcherMacThread::Init() { 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Disallow IO to make sure NetworkConfigWatcherMacThread's helper thread does 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // not perform blocking operations. 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::ThreadRestrictions::SetIOAllowed(false); 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delegate_->Init(); 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(willchan): Look to see if there's a better signal for when it's ok to 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // initialize this, rather than just delaying it by a fixed time. 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const base::TimeDelta kInitializationDelay = base::TimeDelta::FromSeconds(1); 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) message_loop()->PostDelayedTask( 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FROM_HERE, 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&NetworkConfigWatcherMacThread::InitNotifications, 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) weak_factory_.GetWeakPtr()), 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kInitializationDelay); 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NetworkConfigWatcherMacThread::CleanUp() { 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!run_loop_source_.get()) 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CFRunLoopRemoveSource(CFRunLoopGetCurrent(), run_loop_source_.get(), 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kCFRunLoopCommonModes); 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) run_loop_source_.reset(); 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NetworkConfigWatcherMacThread::InitNotifications() { 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(OS_IOS) 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // SCDynamicStore API does not exist on iOS. 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Add a run loop source for a dynamic store to the current run loop. 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SCDynamicStoreContext context = { 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, // Version 0. 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delegate_, // User data. 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL, // This is not reference counted. No retain function. 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL, // This is not reference counted. No release function. 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL, // No description for this. 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 104eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::ScopedCFTypeRef<SCDynamicStoreRef> store(SCDynamicStoreCreate( 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL, CFSTR("org.chromium"), DynamicStoreCallback, &context)); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) run_loop_source_.reset(SCDynamicStoreCreateRunLoopSource( 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL, store.get(), 0)); 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CFRunLoopAddSource(CFRunLoopGetCurrent(), run_loop_source_.get(), 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kCFRunLoopCommonModes); 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // !defined(OS_IOS) 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Set up notifications for interface and IP address changes. 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delegate_->StartReachabilityNotifications(); 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(OS_IOS) 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delegate_->SetDynamicStoreNotificationKeys(store.get()); 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // !defined(OS_IOS) 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NetworkConfigWatcherMac::NetworkConfigWatcherMac(Delegate* delegate) 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : notifier_thread_(new NetworkConfigWatcherMacThread(delegate)) { 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We create this notifier thread because the notification implementation 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // needs a thread with a CFRunLoop, and there's no guarantee that 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // MessageLoop::current() meets that criterion. 12690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) base::Thread::Options thread_options(base::MessageLoop::TYPE_UI, 0); 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) notifier_thread_->StartWithOptions(thread_options); 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NetworkConfigWatcherMac::~NetworkConfigWatcherMac() {} 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace net 133