diff options
author | sergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-02-16 00:13:56 +0000 |
---|---|---|
committer | sergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-02-16 00:13:56 +0000 |
commit | ddaf98a89a9e9f6ea353ca2ef4b89e8c89f53005 (patch) | |
tree | 3be1c37731fc9fe91a27efbb58949ad9bda31cb9 /remoting/host/policy_hack | |
parent | ff8b0e30c9665cd6d22516a2944d33d0a63bec81 (diff) | |
download | chromium_src-ddaf98a89a9e9f6ea353ca2ef4b89e8c89f53005.zip chromium_src-ddaf98a89a9e9f6ea353ca2ef4b89e8c89f53005.tar.gz chromium_src-ddaf98a89a9e9f6ea353ca2ef4b89e8c89f53005.tar.bz2 |
Respect NAT traversal policy in the Me2Me host.
Now the Me2Me host uses the same policy value that It2Me checks to determine if NAT traversal should be enabled. policy_hack has been moved to remoting/host because now it is used not only by the plugin. Also fixed a bug in the policy loader that would cause 5 seconds delay when starting (affects It2Me too).
BUG=114254
Review URL: http://codereview.chromium.org/9401022
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@122195 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting/host/policy_hack')
-rw-r--r-- | remoting/host/policy_hack/nat_policy.cc | 112 | ||||
-rw-r--r-- | remoting/host/policy_hack/nat_policy.h | 78 | ||||
-rw-r--r-- | remoting/host/policy_hack/nat_policy_linux.cc | 273 | ||||
-rw-r--r-- | remoting/host/policy_hack/nat_policy_mac.mm | 71 | ||||
-rw-r--r-- | remoting/host/policy_hack/nat_policy_win.cc | 185 |
5 files changed, 719 insertions, 0 deletions
diff --git a/remoting/host/policy_hack/nat_policy.cc b/remoting/host/policy_hack/nat_policy.cc new file mode 100644 index 0000000..631550b --- /dev/null +++ b/remoting/host/policy_hack/nat_policy.cc @@ -0,0 +1,112 @@ +// Copyright (c) 2012 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. + +// Most of this code is copied from: +// src/chrome/browser/policy/asynchronous_policy_loader.{h,cc} + +#include "remoting/host/policy_hack/nat_policy.h" + +#include "base/bind.h" +#include "base/compiler_specific.h" +#include "base/location.h" +#include "base/memory/weak_ptr.h" +#include "base/message_loop_proxy.h" +#include "base/synchronization/waitable_event.h" +#include "base/time.h" +#include "base/values.h" + +namespace remoting { +namespace policy_hack { + +namespace { +// The time interval for rechecking policy. This is our fallback in case the +// delegate never reports a change to the ReloadObserver. +const int kFallbackReloadDelayMinutes = 15; + +} // namespace + +const char NatPolicy::kNatPolicyName[] = "RemoteAccessHostFirewallTraversal"; + +NatPolicy::NatPolicy(base::MessageLoopProxy* message_loop_proxy) + : message_loop_proxy_(message_loop_proxy), + current_nat_enabled_state_(false), + first_state_published_(false), + ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) { +} + +NatPolicy::~NatPolicy() { +} + +void NatPolicy::StartWatching(const NatEnabledCallback& nat_enabled_cb) { + if (!OnPolicyThread()) { + message_loop_proxy_->PostTask(FROM_HERE, + base::Bind(&NatPolicy::StartWatching, + base::Unretained(this), + nat_enabled_cb)); + return; + } + + nat_enabled_cb_ = nat_enabled_cb; + StartWatchingInternal(); +} + +void NatPolicy::StopWatching(base::WaitableEvent* done) { + if (!OnPolicyThread()) { + message_loop_proxy_->PostTask(FROM_HERE, + base::Bind(&NatPolicy::StopWatching, + base::Unretained(this), done)); + return; + } + + StopWatchingInternal(); + weak_factory_.InvalidateWeakPtrs(); + nat_enabled_cb_.Reset(); + + done->Signal(); +} + +void NatPolicy::ScheduleFallbackReloadTask() { + DCHECK(OnPolicyThread()); + ScheduleReloadTask( + base::TimeDelta::FromMinutes(kFallbackReloadDelayMinutes)); +} + +void NatPolicy::ScheduleReloadTask(const base::TimeDelta& delay) { + DCHECK(OnPolicyThread()); + message_loop_proxy_->PostDelayedTask( + FROM_HERE, + base::Bind(&NatPolicy::Reload, weak_factory_.GetWeakPtr()), + delay.InMilliseconds()); +} + +bool NatPolicy::OnPolicyThread() const { + return message_loop_proxy_->BelongsToCurrentThread(); +} + +void NatPolicy::UpdateNatPolicy(base::DictionaryValue* new_policy) { + DCHECK(OnPolicyThread()); + bool new_nat_enabled_state = false; + if (!new_policy->HasKey(kNatPolicyName)) { + // If unspecified, the default value of this policy is true. + new_nat_enabled_state = true; + } else { + // Otherwise, try to parse the value and only change from false if we get + // a successful read. + base::Value* value; + if (new_policy->Get(kNatPolicyName, &value) && + value->IsType(base::Value::TYPE_BOOLEAN)) { + CHECK(value->GetAsBoolean(&new_nat_enabled_state)); + } + } + + if (!first_state_published_ || + (new_nat_enabled_state != current_nat_enabled_state_)) { + first_state_published_ = true; + current_nat_enabled_state_ = new_nat_enabled_state; + nat_enabled_cb_.Run(current_nat_enabled_state_); + } +} + +} // namespace policy_hack +} // namespace remoting diff --git a/remoting/host/policy_hack/nat_policy.h b/remoting/host/policy_hack/nat_policy.h new file mode 100644 index 0000000..4984d1f --- /dev/null +++ b/remoting/host/policy_hack/nat_policy.h @@ -0,0 +1,78 @@ +// Copyright (c) 2012 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. + +#ifndef REMOTING_HOST_POLICY_HACK_NAT_POLICY_H_ +#define REMOTING_HOST_POLICY_HACK_NAT_POLICY_H_ + +#include "base/callback.h" +#include "base/memory/weak_ptr.h" + +namespace base { +class DictionaryValue; +class MessageLoopProxy; +class TimeDelta; +class WaitableEvent; +} // namespace base + +namespace remoting { +namespace policy_hack { + +// Watches for changes to the managed remote access host NAT policies. +// If StartWatching() has been called, then before this object can be deleted, +// StopWatching() have completed (the provided |done| event must be signaled). +class NatPolicy { + public: + // Called with the current status of whether or not NAT traversal is enabled. + typedef base::Callback<void(bool)> NatEnabledCallback; + + explicit NatPolicy(base::MessageLoopProxy* message_loop_proxy); + virtual ~NatPolicy(); + + // This guarantees that the |nat_enabled_cb| is called at least once with + // the current policy. After that, |nat_enabled_cb| will be called whenever + // a change to the nat policy is detected. + virtual void StartWatching(const NatEnabledCallback& nat_enabled_cb); + + // Should be called after StartWatching() before the object is deleted. Calls + // just wait for |done| to be signaled before deleting the object. + virtual void StopWatching(base::WaitableEvent* done); + + // Implemented by each platform. This message loop should be an IO message + // loop. + static NatPolicy* Create(base::MessageLoopProxy* message_loop_proxy); + + protected: + virtual void StartWatchingInternal() = 0; + virtual void StopWatchingInternal() = 0; + virtual void Reload() = 0; + + // Used to check if the class is on the right thread. + bool OnPolicyThread() const; + + // Takes the policy dictionary from the OS specific store and extracts the + // NAT traversal setting. + void UpdateNatPolicy(base::DictionaryValue* new_policy); + + // Used for time-based reloads in case something goes wrong with the + // notification system. + void ScheduleFallbackReloadTask(); + void ScheduleReloadTask(const base::TimeDelta& delay); + + static const char kNatPolicyName[]; + + private: + scoped_refptr<base::MessageLoopProxy> message_loop_proxy_; + + NatEnabledCallback nat_enabled_cb_; + bool current_nat_enabled_state_; + bool first_state_published_; + + // Allows us to cancel any inflight FileWatcher events or scheduled reloads. + base::WeakPtrFactory<NatPolicy> weak_factory_; +}; + +} // namespace policy_hack +} // namespace remoting + +#endif // REMOTING_HOST_POLICY_HACK_NAT_POLICY_H_ diff --git a/remoting/host/policy_hack/nat_policy_linux.cc b/remoting/host/policy_hack/nat_policy_linux.cc new file mode 100644 index 0000000..6037ddc --- /dev/null +++ b/remoting/host/policy_hack/nat_policy_linux.cc @@ -0,0 +1,273 @@ +// Copyright (c) 2012 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. + +// Most of this code is copied from various classes in +// src/chrome/browser/policy. In particular, look at +// +// file_based_policy_loader.{h,cc} +// config_dir_policy_provider.{h,cc} +// +// This is a reduction of the functionality in those classes. + +#include <set> + +#include "remoting/host/policy_hack/nat_policy.h" + +#include "base/bind.h" +#include "base/compiler_specific.h" +#include "base/file_path.h" +#include "base/file_util.h" +#include "base/files/file_path_watcher.h" +#include "base/json/json_value_serializer.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" +#include "base/message_loop_proxy.h" +#include "base/synchronization/waitable_event.h" +#include "base/time.h" +#include "base/values.h" + +namespace remoting { +namespace policy_hack { + +namespace { + +const FilePath::CharType kPolicyDir[] = + FILE_PATH_LITERAL("/etc/opt/chrome/policies/managed"); + +// Amount of time we wait for the files on disk to settle before trying to load +// them. This alleviates the problem of reading partially written files and +// makes it possible to batch quasi-simultaneous changes. +const int kSettleIntervalSeconds = 5; + +} // namespace + +class NatPolicyLinux : public NatPolicy { + public: + NatPolicyLinux(base::MessageLoopProxy* message_loop_proxy, + const FilePath& config_dir) + : NatPolicy(message_loop_proxy), + config_dir_(config_dir), + ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) { + // Detach the factory because we ensure that only the policy thread ever + // calls methods on this. Also, the API contract of having to call + // StopWatching() (which signals completion) after StartWatching() + // before this object can be destructed ensures there are no users of + // this object before it is destructed. + weak_factory_.DetachFromThread(); + } + + virtual ~NatPolicyLinux() {} + + protected: + virtual void StartWatchingInternal() OVERRIDE { + DCHECK(OnPolicyThread()); + watcher_.reset(new base::files::FilePathWatcher()); + + if (!config_dir_.empty() && + !watcher_->Watch( + config_dir_, + new FilePathWatcherDelegate(weak_factory_.GetWeakPtr()))) { + OnFilePathError(config_dir_); + } + + // There might have been changes to the directory in the time between + // construction of the loader and initialization of the watcher. Call reload + // to detect if that is the case. + Reload(); + + ScheduleFallbackReloadTask(); + } + + virtual void StopWatchingInternal() OVERRIDE { + DCHECK(OnPolicyThread()); + // Cancel any inflight requests. + watcher_.reset(); + } + + // Called by FilePathWatcherDelegate. + virtual void OnFilePathError(const FilePath& path) { + LOG(ERROR) << "NatPolicyLinux on " << path.value() + << " failed."; + } + + // Called by FilePathWatcherDelegate. + virtual void OnFilePathChanged(const FilePath& path) { + DCHECK(OnPolicyThread()); + + Reload(); + } + + private: + // Needed to avoid refcounting NatPolicyLinux. + class FilePathWatcherDelegate : + public base::files::FilePathWatcher::Delegate { + public: + FilePathWatcherDelegate(base::WeakPtr<NatPolicyLinux> policy_watcher) + : policy_watcher_(policy_watcher) { + } + + virtual void OnFilePathError(const FilePath& path) { + if (policy_watcher_) { + policy_watcher_->OnFilePathError(path); + } + } + + virtual void OnFilePathChanged(const FilePath& path) { + if (policy_watcher_) { + policy_watcher_->OnFilePathChanged(path); + } + } + + private: + base::WeakPtr<NatPolicyLinux> policy_watcher_; + }; + + base::Time GetLastModification() { + DCHECK(OnPolicyThread()); + base::Time last_modification = base::Time(); + base::PlatformFileInfo file_info; + + // If the path does not exist or points to a directory, it's safe to load. + if (!file_util::GetFileInfo(config_dir_, &file_info) || + !file_info.is_directory) { + return last_modification; + } + + // Enumerate the files and find the most recent modification timestamp. + file_util::FileEnumerator file_enumerator(config_dir_, + false, + file_util::FileEnumerator::FILES); + for (FilePath config_file = file_enumerator.Next(); + !config_file.empty(); + config_file = file_enumerator.Next()) { + if (file_util::GetFileInfo(config_file, &file_info) && + !file_info.is_directory) { + last_modification = std::max(last_modification, + file_info.last_modified); + } + } + + return last_modification; + } + + // Caller owns the value. + DictionaryValue* Load() { + DCHECK(OnPolicyThread()); + // Enumerate the files and sort them lexicographically. + std::set<FilePath> files; + file_util::FileEnumerator file_enumerator(config_dir_, false, + file_util::FileEnumerator::FILES); + for (FilePath config_file_path = file_enumerator.Next(); + !config_file_path.empty(); config_file_path = file_enumerator.Next()) + files.insert(config_file_path); + + // Start with an empty dictionary and merge the files' contents. + DictionaryValue* policy = new DictionaryValue(); + for (std::set<FilePath>::iterator config_file_iter = files.begin(); + config_file_iter != files.end(); ++config_file_iter) { + JSONFileValueSerializer deserializer(*config_file_iter); + int error_code = 0; + std::string error_msg; + scoped_ptr<Value> value( + deserializer.Deserialize(&error_code, &error_msg)); + if (!value.get()) { + LOG(WARNING) << "Failed to read configuration file " + << config_file_iter->value() << ": " << error_msg; + continue; + } + if (!value->IsType(Value::TYPE_DICTIONARY)) { + LOG(WARNING) << "Expected JSON dictionary in configuration file " + << config_file_iter->value(); + continue; + } + policy->MergeDictionary(static_cast<DictionaryValue*>(value.get())); + } + + return policy; + } + + void Reload() { + DCHECK(OnPolicyThread()); + // Check the directory time in order to see whether a reload is required. + base::TimeDelta delay; + base::Time now = base::Time::Now(); + if (!IsSafeToReloadPolicy(now, &delay)) { + ScheduleReloadTask(delay); + return; + } + + // Check again in case the directory has changed while reading it. + if (!IsSafeToReloadPolicy(now, &delay)) { + ScheduleReloadTask(delay); + return; + } + + // Load the policy definitions. + scoped_ptr<DictionaryValue> new_policy(Load()); + UpdateNatPolicy(new_policy.get()); + + ScheduleFallbackReloadTask(); + } + + bool IsSafeToReloadPolicy(const base::Time& now, base::TimeDelta* delay) { + DCHECK(OnPolicyThread()); + DCHECK(delay); + const base::TimeDelta kSettleInterval = + base::TimeDelta::FromSeconds(kSettleIntervalSeconds); + + base::Time last_modification = GetLastModification(); + if (last_modification.is_null()) + return true; + + if (last_modification_file_.is_null()) + last_modification_file_ = last_modification; + + // If there was a change since the last recorded modification, wait some + // more. + if (last_modification != last_modification_file_) { + last_modification_file_ = last_modification; + last_modification_clock_ = now; + *delay = kSettleInterval; + return false; + } + + // Check whether the settle interval has elapsed. + base::TimeDelta age = now - last_modification_clock_; + if (age < kSettleInterval) { + *delay = kSettleInterval - age; + return false; + } + + return true; + } + + // Managed with a scoped_ptr rather than being declared as an inline member to + // decouple the watcher's life cycle from the NatPolicyLinux. This decoupling + // makes it possible to destroy the watcher before the loader's destructor is + // called (e.g. during Stop), since |watcher_| internally holds a reference to + // the loader and keeps it alive. + scoped_ptr<base::files::FilePathWatcher> watcher_; + + // Records last known modification timestamp of |config_dir_|. + base::Time last_modification_file_; + + // The wall clock time at which the last modification timestamp was + // recorded. It's better to not assume the file notification time and the + // wall clock times come from the same source, just in case there is some + // non-local filesystem involved. + base::Time last_modification_clock_; + + const FilePath config_dir_; + + // Allows us to cancel any inflight FileWatcher events or scheduled reloads. + base::WeakPtrFactory<NatPolicyLinux> weak_factory_; +}; + +NatPolicy* NatPolicy::Create(base::MessageLoopProxy* message_loop_proxy) { + FilePath policy_dir(kPolicyDir); + return new NatPolicyLinux(message_loop_proxy, policy_dir); +} + +} // namespace policy_hack +} // namespace remoting diff --git a/remoting/host/policy_hack/nat_policy_mac.mm b/remoting/host/policy_hack/nat_policy_mac.mm new file mode 100644 index 0000000..25cf6e7 --- /dev/null +++ b/remoting/host/policy_hack/nat_policy_mac.mm @@ -0,0 +1,71 @@ +// Copyright (c) 2012 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 "remoting/host/policy_hack/nat_policy.h" + +#include <CoreFoundation/CoreFoundation.h> + +#include "base/compiler_specific.h" +#include "base/mac/scoped_cftyperef.h" +#include "base/memory/scoped_ptr.h" +#include "base/message_loop_proxy.h" +#include "base/sys_string_conversions.h" +#include "base/values.h" + +namespace remoting { +namespace policy_hack { + +// The MacOS version does not watch files because it is accepted +// practice on the Mac that the user must logout/login for policies to be +// applied. This will actually pick up policies every +// |kFallbackReloadDelayMinutes| which is sufficient for right now. +class NatPolicyMac : public NatPolicy { + public: + explicit NatPolicyMac(base::MessageLoopProxy* message_loop_proxy) + : NatPolicy(message_loop_proxy) { + } + + virtual ~NatPolicyMac() { + } + + protected: + virtual void StartWatchingInternal() OVERRIDE { + Reload(); + } + + virtual void StopWatchingInternal() OVERRIDE { + } + + virtual void Reload() OVERRIDE { + DCHECK(OnPolicyThread()); + base::DictionaryValue policy; + + CFStringRef policy_bundle_id = CFSTR("com.google.Chrome"); + if (CFPreferencesAppSynchronize(policy_bundle_id)) { + base::mac::ScopedCFTypeRef<CFStringRef> policy_key( + base::SysUTF8ToCFStringRef(kNatPolicyName)); + Boolean valid = false; + bool allowed = CFPreferencesGetAppBooleanValue(policy_key, + policy_bundle_id, + &valid); + if (valid) { + policy.SetBoolean(kNatPolicyName, allowed); + } + } + + // Set policy. Policy must be set (even if it is empty) so that the + // default policy is picked up the first time reload is called. + UpdateNatPolicy(&policy); + + // Reschedule task. + ScheduleFallbackReloadTask(); + } +}; + +NatPolicy* NatPolicy::Create(base::MessageLoopProxy* message_loop_proxy) { + return new NatPolicyMac(message_loop_proxy); +} + +} // namespace policy_hack +} // namespace remoting diff --git a/remoting/host/policy_hack/nat_policy_win.cc b/remoting/host/policy_hack/nat_policy_win.cc new file mode 100644 index 0000000..1300b3b --- /dev/null +++ b/remoting/host/policy_hack/nat_policy_win.cc @@ -0,0 +1,185 @@ +// Copyright (c) 2012 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. + +// Most of this code is copied from various classes in +// src/chrome/browser/policy. In particular, look at +// +// configuration_policy_provider_delegate_win.{h,cc} +// configuration_policy_loader_win.{h,cc} +// +// This is a reduction of the functionality in those classes. + +#include "remoting/host/policy_hack/nat_policy.h" + +#include <userenv.h> + +#include "base/compiler_specific.h" +#include "base/memory/scoped_ptr.h" +#include "base/message_loop_proxy.h" +#include "base/string16.h" +#include "base/synchronization/waitable_event.h" +#include "base/utf_string_conversions.h" +#include "base/values.h" +#include "base/win/object_watcher.h" +#include "base/win/registry.h" + +// userenv.dll is required for RegisterGPNotification(). +#pragma comment(lib, "userenv.lib") + +using base::win::RegKey; + +namespace remoting { +namespace policy_hack { + +namespace { + +const wchar_t kRegistrySubKey[] = L"SOFTWARE\\Policies\\Google\\Chrome"; + +} // namespace + +class NatPolicyWin : + public NatPolicy, + public base::win::ObjectWatcher::Delegate { + public: + explicit NatPolicyWin(base::MessageLoopProxy* message_loop_proxy) + : NatPolicy(message_loop_proxy), + user_policy_changed_event_(false, false), + machine_policy_changed_event_(false, false), + user_policy_watcher_failed_(false), + machine_policy_watcher_failed_(false) { + } + + virtual ~NatPolicyWin() { + } + + virtual void StartWatchingInternal() OVERRIDE { + DCHECK(OnPolicyThread()); + + if (!RegisterGPNotification(user_policy_changed_event_.handle(), false)) { + PLOG(WARNING) << "Failed to register user group policy notification"; + user_policy_watcher_failed_ = true; + } + + if (!RegisterGPNotification(machine_policy_changed_event_.handle(), true)) { + PLOG(WARNING) << "Failed to register machine group policy notification."; + machine_policy_watcher_failed_ = true; + } + + Reload(); + } + + virtual void StopWatchingInternal() OVERRIDE { + DCHECK(OnPolicyThread()); + + if (!UnregisterGPNotification(user_policy_changed_event_.handle())) { + PLOG(WARNING) << "Failed to unregister user group policy notification"; + } + + if (!UnregisterGPNotification(machine_policy_changed_event_.handle())) { + PLOG(WARNING) << + "Failed to unregister machine group policy notification."; + } + + user_policy_watcher_.StopWatching(); + machine_policy_watcher_.StopWatching(); + } + + private: + // Updates the watchers and schedules the reload task if appropriate. + void SetupWatches() { + DCHECK(OnPolicyThread()); + + if (!user_policy_watcher_failed_ && + !user_policy_watcher_.GetWatchedObject() && + !user_policy_watcher_.StartWatching( + user_policy_changed_event_.handle(), this)) { + LOG(WARNING) << "Failed to start watch for user policy change event"; + user_policy_watcher_failed_ = true; + } + + if (!machine_policy_watcher_failed_ && + !machine_policy_watcher_.GetWatchedObject() && + !machine_policy_watcher_.StartWatching( + machine_policy_changed_event_.handle(), this)) { + LOG(WARNING) << "Failed to start watch for machine policy change event"; + machine_policy_watcher_failed_ = true; + } + + if (user_policy_watcher_failed_ || machine_policy_watcher_failed_) { + ScheduleFallbackReloadTask(); + } + } + + bool GetRegistryPolicyInteger(const string16& value_name, + uint32* result) const { + DWORD value = 0; + RegKey policy_key(HKEY_LOCAL_MACHINE, kRegistrySubKey, KEY_READ); + if (policy_key.ReadValueDW(value_name.c_str(), &value) == ERROR_SUCCESS) { + *result = value; + return true; + } + + if (policy_key.Open(HKEY_CURRENT_USER, kRegistrySubKey, KEY_READ) == + ERROR_SUCCESS) { + if (policy_key.ReadValueDW(value_name.c_str(), &value) == ERROR_SUCCESS) { + *result = value; + return true; + } + } + return false; + } + + bool GetRegistryPolicyBoolean(const string16& value_name, + bool* result) const { + uint32 local_result = 0; + bool ret = GetRegistryPolicyInteger(value_name, &local_result); + if (ret) + *result = local_result != 0; + return ret; + } + + base::DictionaryValue* Load() { + base::DictionaryValue* policy = new base::DictionaryValue(); + + bool bool_value; + const string16 name(ASCIIToUTF16(kNatPolicyName)); + if (GetRegistryPolicyBoolean(name, &bool_value)) { + policy->SetBoolean(kNatPolicyName, bool_value); + } + + return policy; + } + + // Post a reload notification and update the watch machinery. + void Reload() { + DCHECK(OnPolicyThread()); + SetupWatches(); + scoped_ptr<DictionaryValue> new_policy(Load()); + UpdateNatPolicy(new_policy.get()); + } + + // ObjectWatcher::Delegate overrides: + virtual void OnObjectSignaled(HANDLE object) { + DCHECK(OnPolicyThread()); + DCHECK(object == user_policy_changed_event_.handle() || + object == machine_policy_changed_event_.handle()) + << "unexpected object signaled policy reload, obj = " + << std::showbase << std::hex << object; + Reload(); + } + + base::WaitableEvent user_policy_changed_event_; + base::WaitableEvent machine_policy_changed_event_; + base::win::ObjectWatcher user_policy_watcher_; + base::win::ObjectWatcher machine_policy_watcher_; + bool user_policy_watcher_failed_; + bool machine_policy_watcher_failed_; +}; + +NatPolicy* NatPolicy::Create(base::MessageLoopProxy* message_loop_proxy) { + return new NatPolicyWin(message_loop_proxy); +} + +} // namespace policy_hack +} // namespace remoting |