123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233 |
- // 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 NET_DNS_DNS_CONFIG_SERVICE_H_
- #define NET_DNS_DNS_CONFIG_SERVICE_H_
- #include <map>
- #include <memory>
- #include "base/files/file_path.h"
- #include "base/memory/raw_ptr.h"
- #include "base/memory/weak_ptr.h"
- #include "base/sequence_checker.h"
- #include "base/time/time.h"
- #include "base/timer/timer.h"
- #include "net/base/net_export.h"
- #include "net/dns/dns_config.h"
- #include "net/dns/dns_hosts.h"
- #include "net/dns/serial_worker.h"
- #include "third_party/abseil-cpp/absl/types/optional.h"
- #include "url/gurl.h"
- namespace net {
- // Service for reading system DNS settings, on demand or when signalled by
- // internal watchers and NetworkChangeNotifier. This object is not thread-safe
- // and methods may perform blocking I/O so methods must be called on a sequence
- // that allows blocking (i.e. base::MayBlock).
- class NET_EXPORT_PRIVATE DnsConfigService {
- public:
- // Callback interface for the client, called on the same thread as
- // ReadConfig() and WatchConfig().
- typedef base::RepeatingCallback<void(const DnsConfig& config)> CallbackType;
- // DHCP and user-induced changes are on the order of seconds, so 150ms should
- // not add perceivable delay. On the other hand, config readers should finish
- // within 150ms with the rare exception of I/O block or extra large HOSTS.
- static const base::TimeDelta kInvalidationTimeout;
- // Creates the platform-specific DnsConfigService. May return |nullptr| if
- // reading system DNS settings is not supported on the current platform.
- static std::unique_ptr<DnsConfigService> CreateSystemService();
- DnsConfigService(const DnsConfigService&) = delete;
- DnsConfigService& operator=(const DnsConfigService&) = delete;
- virtual ~DnsConfigService();
- // Attempts to read the configuration. Will run |callback| when succeeded.
- // Can be called at most once.
- void ReadConfig(const CallbackType& callback);
- // Registers systems watchers. Will attempt to read config after watch starts,
- // but only if watchers started successfully. Will run |callback| iff config
- // changes from last call or has to be withdrawn. Can be called at most once.
- // Might require MessageLoopForIO.
- void WatchConfig(const CallbackType& callback);
- // Triggers invalidation and re-read of the current configuration (followed by
- // invocation of the callback). For use only on platforms expecting
- // network-stack-external notifications of DNS config changes.
- virtual void RefreshConfig();
- void set_watch_failed_for_testing(bool watch_failed) {
- watch_failed_ = watch_failed;
- }
- // Simulates a watcher trigger by calling OnConfigChanged().
- void TriggerOnConfigChangedForTesting(bool succeeded) {
- // Directly call ...Delayed() version to skip past delay logic.
- OnConfigChangedDelayed(succeeded);
- }
- protected:
- // Watcher to observe for changes to DNS config or HOSTS (via overriding
- // `Watch()` with platform specifics) and trigger necessary refreshes on
- // changes.
- class NET_EXPORT_PRIVATE Watcher {
- public:
- // `service` is expected to own the created Watcher and thus stay valid for
- // the lifetime of the created Watcher.
- explicit Watcher(DnsConfigService& service);
- virtual ~Watcher();
- Watcher(const Watcher&) = delete;
- Watcher& operator=(const Watcher&) = delete;
- virtual bool Watch() = 0;
- protected:
- // Hooks for detected changes. `succeeded` false to indicate that there was
- // an error watching for the change.
- void OnConfigChanged(bool succeeded);
- void OnHostsChanged(bool succeeded);
- void CheckOnCorrectSequence();
- private:
- void OnConfigChangedDelayed(bool success);
- // Back pointer. `this` is expected to be owned by `service_`, making this
- // raw pointer safe.
- const raw_ptr<DnsConfigService> service_;
- SEQUENCE_CHECKER(sequence_checker_);
- };
- // Reader of HOSTS files. In this base implementation, uses standard logic
- // appropriate to most platforms to read the HOSTS file located at
- // `hosts_file_path`.
- class NET_EXPORT_PRIVATE HostsReader : public SerialWorker {
- public:
- // `service` is expected to own the created reader and thus stay valid for
- // the lifetime of the created reader.
- HostsReader(base::FilePath::StringPieceType hosts_file_path,
- DnsConfigService& service);
- ~HostsReader() override;
- HostsReader(const HostsReader&) = delete;
- HostsReader& operator=(const HostsReader&) = delete;
- protected:
- class NET_EXPORT_PRIVATE WorkItem : public SerialWorker::WorkItem {
- public:
- explicit WorkItem(std::unique_ptr<DnsHostsParser> dns_hosts_parser);
- ~WorkItem() override;
- // Override if needed to implement platform-specific behavior, e.g. for a
- // platform-specific HOSTS format.
- virtual absl::optional<DnsHosts> ReadHosts();
- // Adds any necessary additional entries to the given `DnsHosts`. Returns
- // false on failure.
- //
- // Override if needed to implement platform-specific behavior.
- virtual bool AddAdditionalHostsTo(DnsHosts& in_out_dns_hosts);
- // SerialWorker::WorkItem:
- void DoWork() final;
- private:
- friend HostsReader;
- absl::optional<DnsHosts> hosts_;
- std::unique_ptr<DnsHostsParser> dns_hosts_parser_;
- };
- // SerialWorker:
- std::unique_ptr<SerialWorker::WorkItem> CreateWorkItem() override;
- bool OnWorkFinished(
- std::unique_ptr<SerialWorker::WorkItem> work_item) final;
- private:
- // Raw pointer to owning DnsConfigService. This must never be accessed
- // inside DoWork(), since service may be destroyed while SerialWorker is
- // running on worker thread.
- const raw_ptr<DnsConfigService> service_;
- const base::FilePath hosts_file_path_;
- };
- // On detecting config change, will post and wait `config_change_delay` before
- // triggering refreshes. Will trigger refreshes synchronously on nullopt.
- // Useful for platforms where multiple changes may be made and detected before
- // the config is stabilized and ready to be read.
- explicit DnsConfigService(base::FilePath::StringPieceType hosts_file_path,
- absl::optional<base::TimeDelta>
- config_change_delay = base::Milliseconds(50));
- // Immediately attempts to read the current configuration.
- virtual void ReadConfigNow() = 0;
- virtual void ReadHostsNow();
- // Registers system watchers. Returns true iff succeeds.
- virtual bool StartWatching() = 0;
- // Called when the current config (except hosts) has changed.
- void InvalidateConfig();
- // Called when the current hosts have changed.
- void InvalidateHosts();
- // Called with new config. |config|.hosts is ignored.
- void OnConfigRead(DnsConfig config);
- // Called with new hosts. Rest of the config is assumed unchanged.
- void OnHostsRead(DnsHosts hosts);
- SEQUENCE_CHECKER(sequence_checker_);
- private:
- // The timer counts from the last Invalidate* until complete config is read.
- void StartTimer();
- void OnTimeout();
- // Called when the config becomes complete. Stops the timer.
- void OnCompleteConfig();
- // Hooks for Watcher change notifications. `succeeded` false to indicate that
- // there was an error watching for the change.
- void OnConfigChanged(bool succeeded);
- void OnHostsChanged(bool succeeded);
- void OnConfigChangedDelayed(bool succeeded);
- CallbackType callback_;
- DnsConfig dns_config_;
- // True if any of the necessary watchers failed. In that case, the service
- // will communicate changes via OnTimeout, but will only send empty DnsConfig.
- bool watch_failed_ = false;
- // True after On*Read, before Invalidate*. Tells if the config is complete.
- bool have_config_ = false;
- bool have_hosts_ = false;
- // True if receiver needs to be updated when the config becomes complete.
- bool need_update_ = false;
- // True if the last config sent was empty (instead of |dns_config_|).
- // Set when |timer_| expires.
- bool last_sent_empty_ = true;
- const absl::optional<base::TimeDelta> config_change_delay_;
- const base::FilePath hosts_file_path_;
- // Created only if needed in ReadHostsNow() to avoid creating unnecessarily if
- // overridden for a platform-specific implementation.
- std::unique_ptr<HostsReader> hosts_reader_;
- // Started in Invalidate*, cleared in On*Read.
- base::OneShotTimer timer_;
- base::WeakPtrFactory<DnsConfigService> weak_factory_{this};
- };
- } // namespace net
- #endif // NET_DNS_DNS_CONFIG_SERVICE_H_
|