File: dns_config_service.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (233 lines) | stat: -rw-r--r-- 8,655 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
// Copyright 2012 The Chromium Authors
// 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 <optional>

#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"

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:
    // 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::StringViewType 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 std::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;

      std::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::StringViewType hosts_file_path,
                            std::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);

  // Called when config refresh is required. `succeeded` false to indicate that
  // there was an error while watching for the change.
  void OnConfigChanged(bool succeeded);

  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 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 std::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_