diff options
author | ajwong@chromium.org <ajwong@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-17 22:07:55 +0000 |
---|---|---|
committer | ajwong@chromium.org <ajwong@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-17 22:07:55 +0000 |
commit | f992585f348f555bbe8eef137eaf859e4d530db1 (patch) | |
tree | 2c9881cdb589c23e890953e4e7edda924ead6343 /remoting/host | |
parent | 540ac80c83db3f4865d007288a4f1b8524e0aa86 (diff) | |
download | chromium_src-f992585f348f555bbe8eef137eaf859e4d530db1.zip chromium_src-f992585f348f555bbe8eef137eaf859e4d530db1.tar.gz chromium_src-f992585f348f555bbe8eef137eaf859e4d530db1.tar.bz2 |
Implement Windows NAT traversal policy support for the Chromoting host plugin.
BUG=92576
TEST=change policy from traversal enabled -> disabled while host is running and make sure it disconnects.
Review URL: http://codereview.chromium.org/7664006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@97220 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting/host')
-rw-r--r-- | remoting/host/plugin/policy_hack/nat_policy.cc | 113 | ||||
-rw-r--r-- | remoting/host/plugin/policy_hack/nat_policy.h | 45 | ||||
-rw-r--r-- | remoting/host/plugin/policy_hack/nat_policy_linux.cc | 107 | ||||
-rw-r--r-- | remoting/host/plugin/policy_hack/nat_policy_mac.mm | 23 | ||||
-rw-r--r-- | remoting/host/plugin/policy_hack/nat_policy_win.cc | 171 |
5 files changed, 340 insertions, 119 deletions
diff --git a/remoting/host/plugin/policy_hack/nat_policy.cc b/remoting/host/plugin/policy_hack/nat_policy.cc new file mode 100644 index 0000000..07a28de --- /dev/null +++ b/remoting/host/plugin/policy_hack/nat_policy.cc @@ -0,0 +1,113 @@ +// 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. + +// Most of this code is copied from: +// src/chrome/browser/policy/asynchronous_policy_loader.{h,cc} + +#include "remoting/host/plugin/policy_hack/nat_policy.h" + +#include "base/bind.h" +#include "base/compiler_specific.h" +#include "base/message_loop_proxy.h" +#include "base/memory/weak_ptr.h" +#include "base/synchronization/waitable_event.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. + // + // TODO(ajwong): Currently defaults to false until we have policy + // implemented and verified in all 3 platforms. + new_nat_enabled_state = false; + } 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/plugin/policy_hack/nat_policy.h b/remoting/host/plugin/policy_hack/nat_policy.h index 2ac2530..edf9569 100644 --- a/remoting/host/plugin/policy_hack/nat_policy.h +++ b/remoting/host/plugin/policy_hack/nat_policy.h @@ -6,10 +6,12 @@ #define REMOTING_HOST_PLUGIN_POLICY_HACK_NAT_POLICY_H_ #include "base/callback.h" -#include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" namespace base { +class DictionaryValue; class MessageLoopProxy; +class TimeDelta; class WaitableEvent; } // namespace base @@ -24,23 +26,50 @@ class NatPolicy { // Called with the current status of whether or not NAT traversal is enabled. typedef base::Callback<void(bool)> NatEnabledCallback; - NatPolicy() {} - virtual ~NatPolicy() {} + 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) = 0; + 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) = 0; + virtual void StopWatching(base::WaitableEvent* done); // Implemented by each platform. This message loop should be an IO message - // loop on linux. - // - // TODO(ajwong): figure out the right message loop for win/mac. + // 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 diff --git a/remoting/host/plugin/policy_hack/nat_policy_linux.cc b/remoting/host/plugin/policy_hack/nat_policy_linux.cc index a954230..8255660 100644 --- a/remoting/host/plugin/policy_hack/nat_policy_linux.cc +++ b/remoting/host/plugin/policy_hack/nat_policy_linux.cc @@ -3,9 +3,8 @@ // found in the LICENSE file. // Most of this code is copied from various classes in -// src/chrome/browser/policy. In partiuclar, look at +// src/chrome/browser/policy. In particular, look at // -// asynchronous_policy_loader.{h,cc} // file_based_policy_loader.{h,cc} // config_dir_policy_provider.{h,cc} // @@ -41,10 +40,6 @@ const FilePath::CharType kPolicyDir[] = FILE_PATH_LITERAL("/etc/chromium/policies/managed"); #endif -// 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; - // 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. @@ -56,14 +51,12 @@ class NatPolicyLinux : public NatPolicy { public: NatPolicyLinux(base::MessageLoopProxy* message_loop_proxy, const FilePath& config_dir) - : message_loop_proxy_(message_loop_proxy), + : NatPolicy(message_loop_proxy), config_dir_(config_dir), - current_nat_enabled_state_(false), - first_state_published_(false), ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) { - // Detach the factory because we ensure that only the |message_loop_proxy_| - // thread ever calls methods on this. Also, the API contract of having - // to call StopWatching() (which signals completion) after StopWatching() + // 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(); @@ -71,17 +64,9 @@ class NatPolicyLinux : public NatPolicy { virtual ~NatPolicyLinux() {} - virtual void StartWatching(const NatEnabledCallback& nat_enabled_cb) - OVERRIDE { - if (!message_loop_proxy_->BelongsToCurrentThread()) { - message_loop_proxy_->PostTask(FROM_HERE, - base::Bind(&NatPolicyLinux::StartWatching, - base::Unretained(this), - nat_enabled_cb)); - return; - } - - nat_enabled_cb_ = nat_enabled_cb; + protected: + virtual void StartWatchingInternal() OVERRIDE { + DCHECK(OnPolicyThread()); watcher_.reset(new base::files::FilePathWatcher()); if (!config_dir_.empty() && @@ -99,20 +84,10 @@ class NatPolicyLinux : public NatPolicy { ScheduleFallbackReloadTask(); } - virtual void StopWatching(base::WaitableEvent* done) OVERRIDE { - if (!message_loop_proxy_->BelongsToCurrentThread()) { - message_loop_proxy_->PostTask(FROM_HERE, - base::Bind(&NatPolicyLinux::StopWatching, - base::Unretained(this), done)); - return; - } - + virtual void StopWatchingInternal() OVERRIDE { + DCHECK(OnPolicyThread()); // Cancel any inflight requests. - weak_factory_.InvalidateWeakPtrs(); watcher_.reset(); - nat_enabled_cb_.Reset(); - - done->Signal(); } // Called by FilePathWatcherDelegate. @@ -123,7 +98,7 @@ class NatPolicyLinux : public NatPolicy { // Called by FilePathWatcherDelegate. virtual void OnFilePathChanged(const FilePath& path) { - DCHECK(message_loop_proxy_->BelongsToCurrentThread()); + DCHECK(OnPolicyThread()); Reload(); } @@ -153,22 +128,8 @@ class NatPolicyLinux : public NatPolicy { base::WeakPtr<NatPolicyLinux> policy_watcher_; }; - void ScheduleFallbackReloadTask() { - DCHECK(message_loop_proxy_->BelongsToCurrentThread()); - ScheduleReloadTask( - base::TimeDelta::FromMinutes(kFallbackReloadDelayMinutes)); - } - - void ScheduleReloadTask(const base::TimeDelta& delay) { - DCHECK(message_loop_proxy_->BelongsToCurrentThread()); - message_loop_proxy_->PostDelayedTask( - FROM_HERE, - base::Bind(&NatPolicyLinux::Reload, weak_factory_.GetWeakPtr()), - delay.InMilliseconds()); - } - base::Time GetLastModification() { - DCHECK(message_loop_proxy_->BelongsToCurrentThread()); + DCHECK(OnPolicyThread()); base::Time last_modification = base::Time(); base::PlatformFileInfo file_info; @@ -197,7 +158,7 @@ class NatPolicyLinux : public NatPolicy { // Caller owns the value. DictionaryValue* Load() { - DCHECK(message_loop_proxy_->BelongsToCurrentThread()); + DCHECK(OnPolicyThread()); // Enumerate the files and sort them lexicographically. std::set<FilePath> files; file_util::FileEnumerator file_enumerator(config_dir_, false, @@ -207,7 +168,7 @@ class NatPolicyLinux : public NatPolicy { files.insert(config_file_path); // Start with an empty dictionary and merge the files' contents. - DictionaryValue* policy = new DictionaryValue; + 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); @@ -232,7 +193,7 @@ class NatPolicyLinux : public NatPolicy { } void Reload() { - DCHECK(message_loop_proxy_->BelongsToCurrentThread()); + DCHECK(OnPolicyThread()); // Check the directory time in order to see whether a reload is required. base::TimeDelta delay; base::Time now = base::Time::Now(); @@ -241,46 +202,21 @@ class NatPolicyLinux : public NatPolicy { return; } - // Load the policy definitions. - scoped_ptr<DictionaryValue> new_policy(Load()); - // Check again in case the directory has changed while reading it. if (!IsSafeToReloadPolicy(now, &delay)) { ScheduleReloadTask(delay); return; } - // Read out just the host firewall traversal policy. Name of policy taken - // from the generated policy/policy_constants.h file. - bool new_nat_enabled_state = false; - if (!new_policy->HasKey("RemoteAccessHostFirewallTraversal")) { - // If unspecified, the default value of this policy is true. - // - // TODO(ajwong): Current default to false until we have policy - // implemented and verified in all 3 platforms. - new_nat_enabled_state = false; - } 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("RemoteAccessHostFirewallTraversal", &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_); - } + // 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(message_loop_proxy_->BelongsToCurrentThread()); + DCHECK(OnPolicyThread()); DCHECK(delay); const base::TimeDelta kSettleInterval = base::TimeDelta::FromSeconds(kSettleIntervalSeconds); @@ -324,12 +260,7 @@ class NatPolicyLinux : public NatPolicy { // non-local filesystem involved. base::Time last_modification_clock_; - scoped_refptr<base::MessageLoopProxy> message_loop_proxy_; const FilePath config_dir_; - 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<NatPolicyLinux> weak_factory_; diff --git a/remoting/host/plugin/policy_hack/nat_policy_mac.mm b/remoting/host/plugin/policy_hack/nat_policy_mac.mm index abddd8f..f6514ab 100644 --- a/remoting/host/plugin/policy_hack/nat_policy_mac.mm +++ b/remoting/host/plugin/policy_hack/nat_policy_mac.mm @@ -6,36 +6,35 @@ #include "base/compiler_specific.h" #include "base/message_loop_proxy.h" -#include "base/synchronization/waitable_event.h" +#include "base/scoped_ptr.h" +#include "base/values.h" namespace remoting { namespace policy_hack { class NatPolicyMac : public NatPolicy { public: - NatPolicyMac() { + explicit NatPolicyMac(base::MessageLoopProxy* message_loop_proxy) + : NatPolicy(message_loop_proxy) { } virtual ~NatPolicyMac() { } - virtual void StartWatching(const NatEnabledCallback& nat_enabled_cb) - OVERRIDE { - nat_enabled_cb_ = nat_enabled_cb; - nat_enabled_cb_.Run(false); + virtual void StartWatchingInternal() OVERRIDE { + scoped_ptr<base::DictionaryValue> new_policy(new base::DictionaryValue()); + UpdateNatPolicy(new_policy.get()); } - virtual void StopWatching(base::WaitableEvent* done) OVERRIDE { - nat_enabled_cb_.Reset(); - done->Signal(); + virtual void StopWatchingInternal() OVERRIDE { } - private: - NatEnabledCallback nat_enabled_cb_; + virtual void Reload() OVERRIDE { + } }; NatPolicy* NatPolicy::Create(base::MessageLoopProxy* message_loop_proxy) { - return new NatPolicyMac(); + return new NatPolicyMac(message_loop_proxy); } } // namespace policy_hack diff --git a/remoting/host/plugin/policy_hack/nat_policy_win.cc b/remoting/host/plugin/policy_hack/nat_policy_win.cc index 111fab4..60630cd 100644 --- a/remoting/host/plugin/policy_hack/nat_policy_win.cc +++ b/remoting/host/plugin/policy_hack/nat_policy_win.cc @@ -2,40 +2,189 @@ // 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/plugin/policy_hack/nat_policy.h" +#include <userenv.h> + #include "base/compiler_specific.h" +#include "base/string16.h" +#include "base/utf_string_conversions.h" +#include "base/win/registry.h" #include "base/message_loop_proxy.h" +#include "base/scoped_ptr.h" #include "base/synchronization/waitable_event.h" +#include "base/values.h" +#include "base/win/object_watcher.h" + +// userenv.dll is required for RegisterGPNotification(). +#pragma comment(lib, "userenv.lib") + +using base::win::RegKey; namespace remoting { namespace policy_hack { -class NatPolicyWin : public NatPolicy { +namespace { + +#if defined(OS_WIN) +#if defined(GOOGLE_CHROME_BUILD) +const wchar_t kRegistrySubKey[] = L"SOFTWARE\\Policies\\Google\\Chrome"; +#else +const wchar_t kRegistrySubKey[] = L"SOFTWARE\\Policies\\Chromium"; +#endif +#endif + +} // namespace + +class NatPolicyWin : + public NatPolicy, + public base::win::ObjectWatcher::Delegate { public: - NatPolicyWin() { + 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 StartWatching(const NatEnabledCallback& nat_enabled_cb) - OVERRIDE { - nat_enabled_cb_ = nat_enabled_cb; - nat_enabled_cb_.Run(false); + 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 StopWatching(base::WaitableEvent* done) OVERRIDE { - nat_enabled_cb_.Reset(); - done->Signal(); + 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: - NatEnabledCallback nat_enabled_cb_; + // 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(); + return new NatPolicyWin(message_loop_proxy); } } // namespace policy_hack |