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 "remoting/host/config_file_watcher.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind_helpers.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/file_util.h"
12eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/files/file_path_watcher.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/weak_ptr.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/single_thread_task_runner.h"
16eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/timer/timer.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace remoting {
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The name of the command-line switch used to specify the host configuration
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// file to use.
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kHostConfigSwitchName[] = "host-config";
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const base::FilePath::CharType kDefaultHostConfigFile[] =
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FILE_PATH_LITERAL("host.json");
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Maximum number of times to try reading the configuration file before
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// reporting an error.
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kMaxRetries = 3;
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ConfigFileWatcherImpl
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : public base::RefCountedThreadSafe<ConfigFileWatcherImpl> {
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Creates a configuration file watcher that lives on the |io_task_runner|
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // thread but posts config file updates on on |main_task_runner|.
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ConfigFileWatcherImpl(
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ConfigFileWatcher::Delegate* delegate);
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Starts watching |config_path|.
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void Watch(const base::FilePath& config_path);
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Stops watching the configuration file.
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void StopWatching();
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  friend class base::RefCountedThreadSafe<ConfigFileWatcherImpl>;
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~ConfigFileWatcherImpl();
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void FinishStopping();
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Called every time the host configuration file is updated.
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void OnConfigUpdated(const base::FilePath& path, bool error);
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Reads the configuration file and passes it to the delegate.
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void ReloadConfig();
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string config_;
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath config_path_;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<base::DelayTimer<ConfigFileWatcherImpl> > config_updated_timer_;
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Number of times an attempt to read the configuration file failed.
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int retries_;
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Monitors the host configuration file.
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<base::FilePathWatcher> config_watcher_;
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::WeakPtrFactory<ConfigFileWatcher::Delegate> delegate_weak_factory_;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::WeakPtr<ConfigFileWatcher::Delegate> delegate_;
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(ConfigFileWatcherImpl);
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ConfigFileWatcher::Delegate::~Delegate() {
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ConfigFileWatcher::ConfigFileWatcher(
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Delegate* delegate)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : impl_(new ConfigFileWatcherImpl(main_task_runner,
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      io_task_runner, delegate)) {
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ConfigFileWatcher::~ConfigFileWatcher() {
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  impl_->StopWatching();
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  impl_ = NULL;
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ConfigFileWatcher::Watch(const base::FilePath& config_path) {
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  impl_->Watch(config_path);
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ConfigFileWatcherImpl::ConfigFileWatcherImpl(
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ConfigFileWatcher::Delegate* delegate)
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : retries_(0),
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      delegate_weak_factory_(delegate),
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delegate_(delegate_weak_factory_.GetWeakPtr()),
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      main_task_runner_(main_task_runner),
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      io_task_runner_(io_task_runner) {
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(main_task_runner_->BelongsToCurrentThread());
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ConfigFileWatcherImpl::Watch(const base::FilePath& config_path) {
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!io_task_runner_->BelongsToCurrentThread()) {
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    io_task_runner_->PostTask(
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&ConfigFileWatcherImpl::Watch, this, config_path));
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(config_path_.empty());
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!config_updated_timer_);
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!config_watcher_);
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create the timer that will be used for delayed-reading the configuration
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // file.
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  config_updated_timer_.reset(new base::DelayTimer<ConfigFileWatcherImpl>(
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE, base::TimeDelta::FromSeconds(2), this,
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &ConfigFileWatcherImpl::ReloadConfig));
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Start watching the configuration file.
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  config_watcher_.reset(new base::FilePathWatcher());
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  config_path_ = config_path;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!config_watcher_->Watch(
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          config_path_, false,
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          base::Bind(&ConfigFileWatcherImpl::OnConfigUpdated, this))) {
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    PLOG(ERROR) << "Couldn't watch file '" << config_path_.value() << "'";
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    main_task_runner_->PostTask(
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&ConfigFileWatcher::Delegate::OnConfigWatcherError,
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   delegate_));
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Force reloading of the configuration file at least once.
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReloadConfig();
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ConfigFileWatcherImpl::StopWatching() {
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(main_task_runner_->BelongsToCurrentThread());
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delegate_weak_factory_.InvalidateWeakPtrs();
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  io_task_runner_->PostTask(
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE, base::Bind(&ConfigFileWatcherImpl::FinishStopping, this));
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ConfigFileWatcherImpl::~ConfigFileWatcherImpl() {
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!config_updated_timer_);
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!config_watcher_);
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ConfigFileWatcherImpl::FinishStopping() {
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(io_task_runner_->BelongsToCurrentThread());
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  config_updated_timer_.reset();
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  config_watcher_.reset();
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ConfigFileWatcherImpl::OnConfigUpdated(const base::FilePath& path,
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                            bool error) {
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(io_task_runner_->BelongsToCurrentThread());
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Call ReloadConfig() after a short delay, so that we will not try to read
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the updated configuration file before it has been completely written.
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the writer moves the new configuration file into place atomically,
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // this delay may not be necessary.
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!error && config_path_ == path)
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    config_updated_timer_->Reset();
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ConfigFileWatcherImpl::ReloadConfig() {
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(io_task_runner_->BelongsToCurrentThread());
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string config;
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!file_util::ReadFileToString(config_path_, &config)) {
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(OS_WIN)
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // EACCESS may indicate a locking or sharing violation. Retry a few times
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // before reporting an error.
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (errno == EACCES && retries_ < kMaxRetries) {
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      PLOG(WARNING) << "Failed to read '" << config_path_.value() << "'";
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      retries_ += 1;
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      config_updated_timer_->Reset();
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif  // defined(OS_WIN)
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    PLOG(ERROR) << "Failed to read '" << config_path_.value() << "'";
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    main_task_runner_->PostTask(
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&ConfigFileWatcher::Delegate::OnConfigWatcherError,
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   delegate_));
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  retries_ = 0;
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Post an updated configuration only if it has actually changed.
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (config_ != config) {
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    config_ = config;
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    main_task_runner_->PostTask(
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&ConfigFileWatcher::Delegate::OnConfigUpdated, delegate_,
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   config_));
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace remoting
217