Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(316)

Unified Diff: remoting/host/linux/certificate_watcher.cc

Issue 1977963002: [remoting host] Only watch for material changes to NSS DB files (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « remoting/host/linux/certificate_watcher.h ('k') | remoting/host/linux/certificate_watcher_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: remoting/host/linux/certificate_watcher.cc
diff --git a/remoting/host/linux/certificate_watcher.cc b/remoting/host/linux/certificate_watcher.cc
index 4340667b2f1c4c09bba9d83797011a03c4944168..1f5c66113978844139f2dfc63fadcaa4930d090b 100644
--- a/remoting/host/linux/certificate_watcher.cc
+++ b/remoting/host/linux/certificate_watcher.cc
@@ -6,28 +6,172 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
+#include "base/files/file_util.h"
+#include "base/hash.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/path_service.h"
+#include "base/threading/thread_checker.h"
#include "base/threading/thread_task_runner_handle.h"
namespace remoting {
-// Delay time to restart the host when a change of certificate is detected.
-// This is to avoid repeating restarts when continuous writes to the database
-// occur.
-const int kRestartDelayInSecond = 2;
+namespace {
+
+// Delay before re-reading the cert DB when a change is detected.
+const int kReadDelayInSeconds = 2;
// Full Path: $HOME/.pki/nssdb
const char kCertDirectoryPath[] = ".pki/nssdb";
+const char* const kCertFiles[] = {"cert9.db", "key4.db", "pkcs11.txt"};
+
+} // namespace
+
+// This class lives on the IO thread, watches the certificate database files,
+// and notifies the caller_task_runner thread of any updates.
+class CertDbContentWatcher {
+ public:
+ CertDbContentWatcher(
+ base::WeakPtr<CertificateWatcher> watcher,
+ scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
+ base::FilePath cert_watch_path,
+ base::TimeDelta read_delay);
+ ~CertDbContentWatcher();
+
+ void StartWatching();
+
+ private:
+ base::ThreadChecker thread_checker_;
+
+ // size_t is the return type of base::HashInts() which is used to accumulate
+ // a hash-code while iterating over the database files.
+ typedef size_t HashValue;
+
+ // Called by the FileWatcher when it detects any changes.
+ void OnCertDirectoryChanged(const base::FilePath& path, bool error);
+
+ // Called by |read_timer_| to trigger re-reading the DB content.
+ void OnTimer();
+
+ // Reads the certificate database files and returns a hash of their contents.
+ HashValue ComputeHash();
+
+ base::WeakPtr<CertificateWatcher> watcher_;
+
+ // The TaskRunner to be notified of any changes.
+ scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner_;
+
+ // The file watcher to watch changes inside the certificate folder.
+ std::unique_ptr<base::FilePathWatcher> file_watcher_;
+
+ // Path of the certificate files/directories.
+ base::FilePath cert_watch_path_;
+
+ // Timer to delay reading the DB files after a change notification from the
+ // FileWatcher. This is done to avoid triggering multiple notifications when
+ // the DB is written to. It also avoids a false notification in case the NSS
+ // DB content is quickly changed and reverted.
+ std::unique_ptr<base::DelayTimer> read_timer_;
+
+ // The time to wait before re-reading the DB files after a change is
+ // detected.
+ base::TimeDelta delay_;
+
+ // The hash code of the current certificate database contents. When the
+ // FileWatcher detects changes, the code is re-computed and compared with
+ // this stored value.
+ HashValue current_hash_;
+
+ DISALLOW_COPY_AND_ASSIGN(CertDbContentWatcher);
+};
+
+CertDbContentWatcher::CertDbContentWatcher(
+ base::WeakPtr<CertificateWatcher> watcher,
+ scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
+ base::FilePath cert_watch_path,
+ base::TimeDelta read_delay)
+ : watcher_(watcher),
+ caller_task_runner_(caller_task_runner),
+ cert_watch_path_(cert_watch_path),
+ delay_(read_delay) {
+ thread_checker_.DetachFromThread();
+}
+
+CertDbContentWatcher::~CertDbContentWatcher() {}
+
+void CertDbContentWatcher::StartWatching() {
+ DCHECK(!cert_watch_path_.empty());
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ file_watcher_.reset(new base::FilePathWatcher());
+
+ // Initialize hash value.
+ current_hash_ = ComputeHash();
+
+ // base::Unretained() is safe since this class owns the FileWatcher.
+ file_watcher_->Watch(cert_watch_path_, true,
+ base::Bind(&CertDbContentWatcher::OnCertDirectoryChanged,
+ base::Unretained(this)));
+
+ read_timer_.reset(new base::DelayTimer(FROM_HERE, delay_, this,
+ &CertDbContentWatcher::OnTimer));
+}
+
+void CertDbContentWatcher::OnCertDirectoryChanged(const base::FilePath& path,
+ bool error) {
+ DCHECK(path == cert_watch_path_);
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ if (error) {
+ LOG(FATAL) << "Error occurred while watching for changes of file: "
+ << cert_watch_path_.MaybeAsASCII();
+ }
+
+ read_timer_->Reset();
+}
+
+void CertDbContentWatcher::OnTimer() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ HashValue new_hash = ComputeHash();
+ if (new_hash != current_hash_) {
+ current_hash_ = new_hash;
+ caller_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&CertificateWatcher::DatabaseChanged, watcher_));
+ } else {
+ VLOG(1) << "Directory changed but contents are the same.";
+ }
+}
+
+CertDbContentWatcher::HashValue CertDbContentWatcher::ComputeHash() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ HashValue result = 0;
+
+ for (const char* file : kCertFiles) {
+ base::FilePath path = cert_watch_path_.AppendASCII(file);
+ std::string content;
+ HashValue file_hash = 0;
+
+ // It's possible the file might not exist. Compute the overall hash in a
+ // consistent way for the set of files that do exist. If a new file comes
+ // into existence, the resulting hash-code should change.
+ if (base::ReadFileToString(path, &content)) {
+ file_hash = base::Hash(content);
+ }
+ result = base::HashInts(result, file_hash);
+ }
+ return result;
+}
+
CertificateWatcher::CertificateWatcher(
const base::Closure& restart_action,
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner)
: restart_action_(restart_action),
caller_task_runner_(base::ThreadTaskRunnerHandle::Get()),
io_task_runner_(io_task_runner),
- delay_(base::TimeDelta::FromSeconds(kRestartDelayInSecond)),
+ delay_(base::TimeDelta::FromSeconds(kReadDelayInSeconds)),
weak_factory_(this) {
if (!base::PathService::Get(base::DIR_HOME, &cert_watch_path_)) {
LOG(FATAL) << "Failed to get path of the home directory.";
@@ -44,7 +188,7 @@ CertificateWatcher::~CertificateWatcher() {
if (monitor_) {
monitor_->RemoveStatusObserver(this);
}
- io_task_runner_->DeleteSoon(FROM_HERE, file_watcher_.release());
+ io_task_runner_->DeleteSoon(FROM_HERE, content_watcher_.release());
VLOG(1) << "Stopped watching certificate changes.";
}
@@ -53,15 +197,13 @@ void CertificateWatcher::Start() {
DCHECK(caller_task_runner_->BelongsToCurrentThread());
DCHECK(!cert_watch_path_.empty());
- file_watcher_.reset(new base::FilePathWatcher());
+ content_watcher_.reset(new CertDbContentWatcher(weak_factory_.GetWeakPtr(),
+ caller_task_runner_,
+ cert_watch_path_, delay_));
+
io_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(base::IgnoreResult(&base::FilePathWatcher::Watch),
- base::Unretained(file_watcher_.get()), cert_watch_path_, true,
- base::Bind(&CertificateWatcher::OnCertDirectoryChanged,
- caller_task_runner_, weak_factory_.GetWeakPtr())));
- restart_timer_.reset(new base::DelayTimer(FROM_HERE, delay_, this,
- &CertificateWatcher::OnTimer));
+ FROM_HERE, base::Bind(&CertDbContentWatcher::StartWatching,
+ base::Unretained(content_watcher_.get())));
VLOG(1) << "Started watching certificate changes.";
}
@@ -103,34 +245,10 @@ void CertificateWatcher::SetWatchPathForTests(
}
bool CertificateWatcher::is_started() const {
- return file_watcher_ != nullptr;
-}
-
-// static
-void CertificateWatcher::OnCertDirectoryChanged(
- scoped_refptr<base::SingleThreadTaskRunner> network_task_runner,
- base::WeakPtr<CertificateWatcher> watcher_,
- const base::FilePath& path,
- bool error) {
- network_task_runner->PostTask(
- FROM_HERE,
- base::Bind(&CertificateWatcher::DirectoryChanged, watcher_, path, error));
-}
-
-void CertificateWatcher::DirectoryChanged(const base::FilePath& path,
- bool error) {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- DCHECK(path == cert_watch_path_);
-
- if (error) {
- LOG(FATAL) << "Error occurs when watching changes of file "
- << cert_watch_path_.MaybeAsASCII();
- }
-
- restart_timer_->Reset();
+ return content_watcher_ != nullptr;
}
-void CertificateWatcher::OnTimer() {
+void CertificateWatcher::DatabaseChanged() {
DCHECK(caller_task_runner_->BelongsToCurrentThread());
if (inhibit_mode_) {
« no previous file with comments | « remoting/host/linux/certificate_watcher.h ('k') | remoting/host/linux/certificate_watcher_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698