xref: /aosp_15_r20/external/cronet/net/dns/dns_config_service.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2012 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #ifndef NET_DNS_DNS_CONFIG_SERVICE_H_
6*6777b538SAndroid Build Coastguard Worker #define NET_DNS_DNS_CONFIG_SERVICE_H_
7*6777b538SAndroid Build Coastguard Worker 
8*6777b538SAndroid Build Coastguard Worker #include <map>
9*6777b538SAndroid Build Coastguard Worker #include <memory>
10*6777b538SAndroid Build Coastguard Worker #include <optional>
11*6777b538SAndroid Build Coastguard Worker 
12*6777b538SAndroid Build Coastguard Worker #include "base/files/file_path.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/memory/raw_ptr.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/memory/weak_ptr.h"
15*6777b538SAndroid Build Coastguard Worker #include "base/sequence_checker.h"
16*6777b538SAndroid Build Coastguard Worker #include "base/time/time.h"
17*6777b538SAndroid Build Coastguard Worker #include "base/timer/timer.h"
18*6777b538SAndroid Build Coastguard Worker #include "net/base/net_export.h"
19*6777b538SAndroid Build Coastguard Worker #include "net/dns/dns_config.h"
20*6777b538SAndroid Build Coastguard Worker #include "net/dns/dns_hosts.h"
21*6777b538SAndroid Build Coastguard Worker #include "net/dns/serial_worker.h"
22*6777b538SAndroid Build Coastguard Worker #include "url/gurl.h"
23*6777b538SAndroid Build Coastguard Worker 
24*6777b538SAndroid Build Coastguard Worker namespace net {
25*6777b538SAndroid Build Coastguard Worker 
26*6777b538SAndroid Build Coastguard Worker // Service for reading system DNS settings, on demand or when signalled by
27*6777b538SAndroid Build Coastguard Worker // internal watchers and NetworkChangeNotifier. This object is not thread-safe
28*6777b538SAndroid Build Coastguard Worker // and methods may perform blocking I/O so methods must be called on a sequence
29*6777b538SAndroid Build Coastguard Worker // that allows blocking (i.e. base::MayBlock).
30*6777b538SAndroid Build Coastguard Worker class NET_EXPORT_PRIVATE DnsConfigService {
31*6777b538SAndroid Build Coastguard Worker  public:
32*6777b538SAndroid Build Coastguard Worker   // Callback interface for the client, called on the same thread as
33*6777b538SAndroid Build Coastguard Worker   // ReadConfig() and WatchConfig().
34*6777b538SAndroid Build Coastguard Worker   typedef base::RepeatingCallback<void(const DnsConfig& config)> CallbackType;
35*6777b538SAndroid Build Coastguard Worker 
36*6777b538SAndroid Build Coastguard Worker   // DHCP and user-induced changes are on the order of seconds, so 150ms should
37*6777b538SAndroid Build Coastguard Worker   // not add perceivable delay. On the other hand, config readers should finish
38*6777b538SAndroid Build Coastguard Worker   // within 150ms with the rare exception of I/O block or extra large HOSTS.
39*6777b538SAndroid Build Coastguard Worker   static const base::TimeDelta kInvalidationTimeout;
40*6777b538SAndroid Build Coastguard Worker 
41*6777b538SAndroid Build Coastguard Worker   // Creates the platform-specific DnsConfigService. May return |nullptr| if
42*6777b538SAndroid Build Coastguard Worker   // reading system DNS settings is not supported on the current platform.
43*6777b538SAndroid Build Coastguard Worker   static std::unique_ptr<DnsConfigService> CreateSystemService();
44*6777b538SAndroid Build Coastguard Worker 
45*6777b538SAndroid Build Coastguard Worker   DnsConfigService(const DnsConfigService&) = delete;
46*6777b538SAndroid Build Coastguard Worker   DnsConfigService& operator=(const DnsConfigService&) = delete;
47*6777b538SAndroid Build Coastguard Worker 
48*6777b538SAndroid Build Coastguard Worker   virtual ~DnsConfigService();
49*6777b538SAndroid Build Coastguard Worker 
50*6777b538SAndroid Build Coastguard Worker   // Attempts to read the configuration. Will run |callback| when succeeded.
51*6777b538SAndroid Build Coastguard Worker   // Can be called at most once.
52*6777b538SAndroid Build Coastguard Worker   void ReadConfig(const CallbackType& callback);
53*6777b538SAndroid Build Coastguard Worker 
54*6777b538SAndroid Build Coastguard Worker   // Registers systems watchers. Will attempt to read config after watch starts,
55*6777b538SAndroid Build Coastguard Worker   // but only if watchers started successfully. Will run |callback| iff config
56*6777b538SAndroid Build Coastguard Worker   // changes from last call or has to be withdrawn. Can be called at most once.
57*6777b538SAndroid Build Coastguard Worker   // Might require MessageLoopForIO.
58*6777b538SAndroid Build Coastguard Worker   void WatchConfig(const CallbackType& callback);
59*6777b538SAndroid Build Coastguard Worker 
60*6777b538SAndroid Build Coastguard Worker   // Triggers invalidation and re-read of the current configuration (followed by
61*6777b538SAndroid Build Coastguard Worker   // invocation of the callback). For use only on platforms expecting
62*6777b538SAndroid Build Coastguard Worker   // network-stack-external notifications of DNS config changes.
63*6777b538SAndroid Build Coastguard Worker   virtual void RefreshConfig();
64*6777b538SAndroid Build Coastguard Worker 
set_watch_failed_for_testing(bool watch_failed)65*6777b538SAndroid Build Coastguard Worker   void set_watch_failed_for_testing(bool watch_failed) {
66*6777b538SAndroid Build Coastguard Worker     watch_failed_ = watch_failed;
67*6777b538SAndroid Build Coastguard Worker   }
68*6777b538SAndroid Build Coastguard Worker 
69*6777b538SAndroid Build Coastguard Worker   // Simulates a watcher trigger by calling OnConfigChanged().
TriggerOnConfigChangedForTesting(bool succeeded)70*6777b538SAndroid Build Coastguard Worker   void TriggerOnConfigChangedForTesting(bool succeeded) {
71*6777b538SAndroid Build Coastguard Worker     // Directly call ...Delayed() version to skip past delay logic.
72*6777b538SAndroid Build Coastguard Worker     OnConfigChangedDelayed(succeeded);
73*6777b538SAndroid Build Coastguard Worker   }
74*6777b538SAndroid Build Coastguard Worker 
75*6777b538SAndroid Build Coastguard Worker  protected:
76*6777b538SAndroid Build Coastguard Worker   // Watcher to observe for changes to DNS config or HOSTS (via overriding
77*6777b538SAndroid Build Coastguard Worker   // `Watch()` with platform specifics) and trigger necessary refreshes on
78*6777b538SAndroid Build Coastguard Worker   // changes.
79*6777b538SAndroid Build Coastguard Worker   class NET_EXPORT_PRIVATE Watcher {
80*6777b538SAndroid Build Coastguard Worker    public:
81*6777b538SAndroid Build Coastguard Worker     // `service` is expected to own the created Watcher and thus stay valid for
82*6777b538SAndroid Build Coastguard Worker     // the lifetime of the created Watcher.
83*6777b538SAndroid Build Coastguard Worker     explicit Watcher(DnsConfigService& service);
84*6777b538SAndroid Build Coastguard Worker     virtual ~Watcher();
85*6777b538SAndroid Build Coastguard Worker 
86*6777b538SAndroid Build Coastguard Worker     Watcher(const Watcher&) = delete;
87*6777b538SAndroid Build Coastguard Worker     Watcher& operator=(const Watcher&) = delete;
88*6777b538SAndroid Build Coastguard Worker 
89*6777b538SAndroid Build Coastguard Worker     virtual bool Watch() = 0;
90*6777b538SAndroid Build Coastguard Worker 
91*6777b538SAndroid Build Coastguard Worker    protected:
92*6777b538SAndroid Build Coastguard Worker     // Hooks for detected changes. `succeeded` false to indicate that there was
93*6777b538SAndroid Build Coastguard Worker     // an error watching for the change.
94*6777b538SAndroid Build Coastguard Worker     void OnConfigChanged(bool succeeded);
95*6777b538SAndroid Build Coastguard Worker     void OnHostsChanged(bool succeeded);
96*6777b538SAndroid Build Coastguard Worker 
97*6777b538SAndroid Build Coastguard Worker     void CheckOnCorrectSequence();
98*6777b538SAndroid Build Coastguard Worker 
99*6777b538SAndroid Build Coastguard Worker    private:
100*6777b538SAndroid Build Coastguard Worker     // Back pointer. `this` is expected to be owned by `service_`, making this
101*6777b538SAndroid Build Coastguard Worker     // raw pointer safe.
102*6777b538SAndroid Build Coastguard Worker     const raw_ptr<DnsConfigService> service_;
103*6777b538SAndroid Build Coastguard Worker 
104*6777b538SAndroid Build Coastguard Worker     SEQUENCE_CHECKER(sequence_checker_);
105*6777b538SAndroid Build Coastguard Worker   };
106*6777b538SAndroid Build Coastguard Worker 
107*6777b538SAndroid Build Coastguard Worker   // Reader of HOSTS files. In this base implementation, uses standard logic
108*6777b538SAndroid Build Coastguard Worker   // appropriate to most platforms to read the HOSTS file located at
109*6777b538SAndroid Build Coastguard Worker   // `hosts_file_path`.
110*6777b538SAndroid Build Coastguard Worker   class NET_EXPORT_PRIVATE HostsReader : public SerialWorker {
111*6777b538SAndroid Build Coastguard Worker    public:
112*6777b538SAndroid Build Coastguard Worker     // `service` is expected to own the created reader and thus stay valid for
113*6777b538SAndroid Build Coastguard Worker     // the lifetime of the created reader.
114*6777b538SAndroid Build Coastguard Worker     HostsReader(base::FilePath::StringPieceType hosts_file_path,
115*6777b538SAndroid Build Coastguard Worker                 DnsConfigService& service);
116*6777b538SAndroid Build Coastguard Worker     ~HostsReader() override;
117*6777b538SAndroid Build Coastguard Worker 
118*6777b538SAndroid Build Coastguard Worker     HostsReader(const HostsReader&) = delete;
119*6777b538SAndroid Build Coastguard Worker     HostsReader& operator=(const HostsReader&) = delete;
120*6777b538SAndroid Build Coastguard Worker 
121*6777b538SAndroid Build Coastguard Worker    protected:
122*6777b538SAndroid Build Coastguard Worker     class NET_EXPORT_PRIVATE WorkItem : public SerialWorker::WorkItem {
123*6777b538SAndroid Build Coastguard Worker      public:
124*6777b538SAndroid Build Coastguard Worker       explicit WorkItem(std::unique_ptr<DnsHostsParser> dns_hosts_parser);
125*6777b538SAndroid Build Coastguard Worker       ~WorkItem() override;
126*6777b538SAndroid Build Coastguard Worker 
127*6777b538SAndroid Build Coastguard Worker       // Override if needed to implement platform-specific behavior, e.g. for a
128*6777b538SAndroid Build Coastguard Worker       // platform-specific HOSTS format.
129*6777b538SAndroid Build Coastguard Worker       virtual std::optional<DnsHosts> ReadHosts();
130*6777b538SAndroid Build Coastguard Worker 
131*6777b538SAndroid Build Coastguard Worker       // Adds any necessary additional entries to the given `DnsHosts`. Returns
132*6777b538SAndroid Build Coastguard Worker       // false on failure.
133*6777b538SAndroid Build Coastguard Worker       //
134*6777b538SAndroid Build Coastguard Worker       // Override if needed to implement platform-specific behavior.
135*6777b538SAndroid Build Coastguard Worker       virtual bool AddAdditionalHostsTo(DnsHosts& in_out_dns_hosts);
136*6777b538SAndroid Build Coastguard Worker 
137*6777b538SAndroid Build Coastguard Worker       // SerialWorker::WorkItem:
138*6777b538SAndroid Build Coastguard Worker       void DoWork() final;
139*6777b538SAndroid Build Coastguard Worker 
140*6777b538SAndroid Build Coastguard Worker      private:
141*6777b538SAndroid Build Coastguard Worker       friend HostsReader;
142*6777b538SAndroid Build Coastguard Worker 
143*6777b538SAndroid Build Coastguard Worker       std::optional<DnsHosts> hosts_;
144*6777b538SAndroid Build Coastguard Worker       std::unique_ptr<DnsHostsParser> dns_hosts_parser_;
145*6777b538SAndroid Build Coastguard Worker     };
146*6777b538SAndroid Build Coastguard Worker 
147*6777b538SAndroid Build Coastguard Worker     // SerialWorker:
148*6777b538SAndroid Build Coastguard Worker     std::unique_ptr<SerialWorker::WorkItem> CreateWorkItem() override;
149*6777b538SAndroid Build Coastguard Worker     bool OnWorkFinished(
150*6777b538SAndroid Build Coastguard Worker         std::unique_ptr<SerialWorker::WorkItem> work_item) final;
151*6777b538SAndroid Build Coastguard Worker 
152*6777b538SAndroid Build Coastguard Worker    private:
153*6777b538SAndroid Build Coastguard Worker     // Raw pointer to owning DnsConfigService. This must never be accessed
154*6777b538SAndroid Build Coastguard Worker     // inside DoWork(), since service may be destroyed while SerialWorker is
155*6777b538SAndroid Build Coastguard Worker     // running on worker thread.
156*6777b538SAndroid Build Coastguard Worker     const raw_ptr<DnsConfigService> service_;
157*6777b538SAndroid Build Coastguard Worker 
158*6777b538SAndroid Build Coastguard Worker     const base::FilePath hosts_file_path_;
159*6777b538SAndroid Build Coastguard Worker   };
160*6777b538SAndroid Build Coastguard Worker 
161*6777b538SAndroid Build Coastguard Worker   // On detecting config change, will post and wait `config_change_delay` before
162*6777b538SAndroid Build Coastguard Worker   // triggering refreshes. Will trigger refreshes synchronously on nullopt.
163*6777b538SAndroid Build Coastguard Worker   // Useful for platforms where multiple changes may be made and detected before
164*6777b538SAndroid Build Coastguard Worker   // the config is stabilized and ready to be read.
165*6777b538SAndroid Build Coastguard Worker   explicit DnsConfigService(base::FilePath::StringPieceType hosts_file_path,
166*6777b538SAndroid Build Coastguard Worker                             std::optional<base::TimeDelta> config_change_delay =
167*6777b538SAndroid Build Coastguard Worker                                 base::Milliseconds(50));
168*6777b538SAndroid Build Coastguard Worker 
169*6777b538SAndroid Build Coastguard Worker   // Immediately attempts to read the current configuration.
170*6777b538SAndroid Build Coastguard Worker   virtual void ReadConfigNow() = 0;
171*6777b538SAndroid Build Coastguard Worker   virtual void ReadHostsNow();
172*6777b538SAndroid Build Coastguard Worker   // Registers system watchers. Returns true iff succeeds.
173*6777b538SAndroid Build Coastguard Worker   virtual bool StartWatching() = 0;
174*6777b538SAndroid Build Coastguard Worker 
175*6777b538SAndroid Build Coastguard Worker   // Called when the current config (except hosts) has changed.
176*6777b538SAndroid Build Coastguard Worker   void InvalidateConfig();
177*6777b538SAndroid Build Coastguard Worker   // Called when the current hosts have changed.
178*6777b538SAndroid Build Coastguard Worker   void InvalidateHosts();
179*6777b538SAndroid Build Coastguard Worker 
180*6777b538SAndroid Build Coastguard Worker   // Called with new config. |config|.hosts is ignored.
181*6777b538SAndroid Build Coastguard Worker   void OnConfigRead(DnsConfig config);
182*6777b538SAndroid Build Coastguard Worker   // Called with new hosts. Rest of the config is assumed unchanged.
183*6777b538SAndroid Build Coastguard Worker   void OnHostsRead(DnsHosts hosts);
184*6777b538SAndroid Build Coastguard Worker 
185*6777b538SAndroid Build Coastguard Worker   // Called when config refresh is required. `succeeded` false to indicate that
186*6777b538SAndroid Build Coastguard Worker   // there was an error while watching for the change.
187*6777b538SAndroid Build Coastguard Worker   void OnConfigChanged(bool succeeded);
188*6777b538SAndroid Build Coastguard Worker 
189*6777b538SAndroid Build Coastguard Worker   SEQUENCE_CHECKER(sequence_checker_);
190*6777b538SAndroid Build Coastguard Worker 
191*6777b538SAndroid Build Coastguard Worker  private:
192*6777b538SAndroid Build Coastguard Worker   // The timer counts from the last Invalidate* until complete config is read.
193*6777b538SAndroid Build Coastguard Worker   void StartTimer();
194*6777b538SAndroid Build Coastguard Worker   void OnTimeout();
195*6777b538SAndroid Build Coastguard Worker   // Called when the config becomes complete. Stops the timer.
196*6777b538SAndroid Build Coastguard Worker   void OnCompleteConfig();
197*6777b538SAndroid Build Coastguard Worker 
198*6777b538SAndroid Build Coastguard Worker   // Hooks for Watcher change notifications. `succeeded` false to indicate that
199*6777b538SAndroid Build Coastguard Worker   // there was an error watching for the change.
200*6777b538SAndroid Build Coastguard Worker   void OnHostsChanged(bool succeeded);
201*6777b538SAndroid Build Coastguard Worker   void OnConfigChangedDelayed(bool succeeded);
202*6777b538SAndroid Build Coastguard Worker 
203*6777b538SAndroid Build Coastguard Worker   CallbackType callback_;
204*6777b538SAndroid Build Coastguard Worker 
205*6777b538SAndroid Build Coastguard Worker   DnsConfig dns_config_;
206*6777b538SAndroid Build Coastguard Worker 
207*6777b538SAndroid Build Coastguard Worker   // True if any of the necessary watchers failed. In that case, the service
208*6777b538SAndroid Build Coastguard Worker   // will communicate changes via OnTimeout, but will only send empty DnsConfig.
209*6777b538SAndroid Build Coastguard Worker   bool watch_failed_ = false;
210*6777b538SAndroid Build Coastguard Worker   // True after On*Read, before Invalidate*. Tells if the config is complete.
211*6777b538SAndroid Build Coastguard Worker   bool have_config_ = false;
212*6777b538SAndroid Build Coastguard Worker   bool have_hosts_ = false;
213*6777b538SAndroid Build Coastguard Worker   // True if receiver needs to be updated when the config becomes complete.
214*6777b538SAndroid Build Coastguard Worker   bool need_update_ = false;
215*6777b538SAndroid Build Coastguard Worker   // True if the last config sent was empty (instead of |dns_config_|).
216*6777b538SAndroid Build Coastguard Worker   // Set when |timer_| expires.
217*6777b538SAndroid Build Coastguard Worker   bool last_sent_empty_ = true;
218*6777b538SAndroid Build Coastguard Worker 
219*6777b538SAndroid Build Coastguard Worker   const std::optional<base::TimeDelta> config_change_delay_;
220*6777b538SAndroid Build Coastguard Worker   const base::FilePath hosts_file_path_;
221*6777b538SAndroid Build Coastguard Worker 
222*6777b538SAndroid Build Coastguard Worker   // Created only if needed in ReadHostsNow() to avoid creating unnecessarily if
223*6777b538SAndroid Build Coastguard Worker   // overridden for a platform-specific implementation.
224*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<HostsReader> hosts_reader_;
225*6777b538SAndroid Build Coastguard Worker 
226*6777b538SAndroid Build Coastguard Worker   // Started in Invalidate*, cleared in On*Read.
227*6777b538SAndroid Build Coastguard Worker   base::OneShotTimer timer_;
228*6777b538SAndroid Build Coastguard Worker 
229*6777b538SAndroid Build Coastguard Worker   base::WeakPtrFactory<DnsConfigService> weak_factory_{this};
230*6777b538SAndroid Build Coastguard Worker };
231*6777b538SAndroid Build Coastguard Worker 
232*6777b538SAndroid Build Coastguard Worker }  // namespace net
233*6777b538SAndroid Build Coastguard Worker 
234*6777b538SAndroid Build Coastguard Worker #endif  // NET_DNS_DNS_CONFIG_SERVICE_H_
235