File: host_resolver_manager_job.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 (377 lines) | stat: -rw-r--r-- 13,255 bytes parent folder | download | duplicates (5)
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
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
// Copyright 2024 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_HOST_RESOLVER_MANAGER_JOB_H_
#define NET_DNS_HOST_RESOLVER_MANAGER_JOB_H_

#include <array>
#include <deque>
#include <memory>
#include <optional>
#include <variant>
#include <vector>

#include "base/containers/linked_list.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/safe_ref.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "net/base/address_family.h"
#include "net/base/network_anonymization_key.h"
#include "net/base/network_handle.h"
#include "net/base/prioritized_dispatcher.h"
#include "net/dns/dns_task_results_manager.h"
#include "net/dns/host_cache.h"
#include "net/dns/host_resolver.h"
#include "net/dns/host_resolver_dns_task.h"
#include "net/dns/host_resolver_manager.h"
#include "net/dns/public/dns_query_type.h"
#include "net/dns/public/secure_dns_mode.h"
#include "net/log/net_log_with_source.h"

namespace net {

class ResolveContext;
class HostResolverMdnsTask;
class HostResolverNat64Task;

// Key used to identify a HostResolverManager::Job.
struct HostResolverManager::JobKey {
  JobKey(HostResolver::Host host, ResolveContext* resolve_context);
  ~JobKey();

  JobKey(const JobKey& other);
  JobKey& operator=(const JobKey& other);

  bool operator<(const JobKey& other) const;
  bool operator==(const JobKey& other) const;

  HostResolver::Host host;
  NetworkAnonymizationKey network_anonymization_key;
  DnsQueryTypeSet query_types;
  HostResolverFlags flags;
  HostResolverSource source;
  SecureDnsMode secure_dns_mode;
  base::WeakPtr<ResolveContext> resolve_context;

  HostCache::Key ToCacheKey(bool secure) const;

  handles::NetworkHandle GetTargetNetwork() const;
};

// Aggregates all Requests for the same Key. Dispatched via
// PrioritizedDispatcher.
class HostResolverManager::Job : public PrioritizedDispatcher::Job,
                                 public HostResolverDnsTask::Delegate,
                                 public DnsTaskResultsManager::Delegate {
 public:
  // Creates new job for |key| where |request_net_log| is bound to the
  // request that spawned it.
  Job(const base::WeakPtr<HostResolverManager>& resolver,
      JobKey key,
      ResolveHostParameters::CacheUsage cache_usage,
      HostCache* host_cache,
      std::deque<TaskType> tasks,
      RequestPriority priority,
      const NetLogWithSource& source_net_log,
      const base::TickClock* tick_clock,
      const HostResolver::HttpsSvcbOptions& https_svcb_options);
  ~Job() override;

  // Add this job to the dispatcher.  If "at_head" is true, adds at the front
  // of the queue.
  void Schedule(bool at_head);

  void AddRequest(RequestImpl* request);

  void ChangeRequestPriority(RequestImpl* req, RequestPriority priority);

  // Detach cancelled request. If it was the last active Request, also finishes
  // this Job.
  void CancelRequest(RequestImpl* request);

  void AddServiceEndpointRequest(ServiceEndpointRequestImpl* request);

  // Similar to CancelRequest(), if `request` was the last active one, finishes
  // this job.
  void CancelServiceEndpointRequest(ServiceEndpointRequestImpl* request);

  // Similar to ChangeRequestPriority(), but for a ServiceEndpointRequest.
  void ChangeServiceEndpointRequestPriority(ServiceEndpointRequestImpl* request,
                                            RequestPriority priority);

  // Called from AbortJobsWithoutTargetNetwork(). Completes all requests and
  // destroys the job. This currently assumes the abort is due to a network
  // change.
  // TODO This should not delete |this|.
  void Abort();

  // Gets a closure that will abort an insecure DnsTask (see
  // AbortInsecureDnsTask()) iff |this| is still valid. Useful if aborting a
  // list of Jobs as some may be cancelled while aborting others.
  base::OnceClosure GetAbortInsecureDnsTaskClosure(int error,
                                                   bool fallback_only);

  // Aborts or removes any current/future insecure DnsTasks if a
  // HostResolverSystemTask is available for fallback. If no fallback is
  // available and |fallback_only| is false, a job that is currently running an
  // insecure DnsTask will be completed with |error|.
  void AbortInsecureDnsTask(int error, bool fallback_only);

  // Called by HostResolverManager when this job is evicted due to queue
  // overflow. Completes all requests and destroys the job. The job could have
  // waiting requests that will receive completion callbacks, so cleanup
  // asynchronously to avoid reentrancy.
  void OnEvicted();

  // Attempts to serve the job from HOSTS. Returns true if succeeded and
  // this Job was destroyed.
  bool ServeFromHosts();

  void OnAddedToJobMap(JobMap::iterator iterator);

  void OnRemovedFromJobMap();

  void RunNextTask();

  const JobKey& key() const { return key_; }

  bool is_queued() const { return !handle_.is_null(); }

  bool is_running() const { return job_running_; }

  bool HasTargetNetwork() const {
    return key_.GetTargetNetwork() != handles::kInvalidNetworkHandle;
  }

  DnsTaskResultsManager* dns_task_results_manager() const {
    return dns_task_results_manager_.get();
  }

 private:
  // Keeps track of the highest priority.
  class PriorityTracker {
   public:
    explicit PriorityTracker(RequestPriority initial_priority)
        : highest_priority_(initial_priority) {}

    RequestPriority highest_priority() const { return highest_priority_; }

    size_t total_count() const { return total_count_; }

    void Add(RequestPriority req_priority) {
      ++total_count_;
      ++counts_[req_priority];
      if (highest_priority_ < req_priority) {
        highest_priority_ = req_priority;
      }
    }

    void Remove(RequestPriority req_priority) {
      DCHECK_GT(total_count_, 0u);
      DCHECK_GT(counts_[req_priority], 0u);
      --total_count_;
      --counts_[req_priority];
      size_t i;
      for (i = highest_priority_; i > MINIMUM_PRIORITY && !counts_[i]; --i) {
      }
      highest_priority_ = static_cast<RequestPriority>(i);

      // In absence of requests, default to MINIMUM_PRIORITY.
      if (total_count_ == 0) {
        DCHECK_EQ(MINIMUM_PRIORITY, highest_priority_);
      }
    }

   private:
    RequestPriority highest_priority_;
    size_t total_count_ = 0;
    std::array<size_t, NUM_PRIORITIES> counts_ = {};
  };

  base::Value::Dict NetLogJobCreationParams(const NetLogSource& source);

  void Finish();

  void KillDnsTask();

  // Reduce the number of job slots occupied and queued in the dispatcher by
  // one. If the next Job slot is queued in the dispatcher, cancels the queued
  // job. Otherwise, the next Job has been started by the PrioritizedDispatcher,
  // so signals it is complete.
  void ReduceByOneJobSlot();

  // Common helper methods for adding and canceling a request.
  void AddRequestCommon(RequestPriority request_priority,
                        const NetLogWithSource& request_net_log,
                        bool is_speculative);
  void CancelRequestCommon(RequestPriority request_priority,
                           const NetLogWithSource& request_net_log);

  void UpdatePriority();

  // PrioritizedDispatcher::Job:
  void Start() override;

  // TODO(szym): Since DnsTransaction does not consume threads, we can increase
  // the limits on |dispatcher_|. But in order to keep the number of
  // ThreadPool threads low, we will need to use an "inner"
  // PrioritizedDispatcher with tighter limits.
  void StartSystemTask();
  // Called by HostResolverSystemTask when it completes.
  void OnSystemTaskComplete(base::TimeTicks start_time,
                            const AddressList& addr_list,
                            int /*os_error*/,
                            int net_error);

  void InsecureCacheLookup();

  void StartDnsTask(bool secure);
  void StartNextDnsTransaction();
  // Called if DnsTask fails. It is posted from StartDnsTask, so Job may be
  // deleted before this callback. In this case dns_task is deleted as well,
  // so we use it as indicator whether Job is still valid.
  void OnDnsTaskFailure(const base::WeakPtr<HostResolverDnsTask>& dns_task,
                        base::TimeDelta duration,
                        bool allow_fallback,
                        const HostCache::Entry& failure_results,
                        bool secure);
  // HostResolverDnsTask::Delegate implementation:
  void OnDnsTaskComplete(base::TimeTicks start_time,
                         bool allow_fallback,
                         HostResolverDnsTask::Results results,
                         bool secure) override;
  void OnIntermediateTransactionsComplete(
      std::optional<HostResolverDnsTask::SingleTransactionResults>
          single_transaction_results) override;
  bool IsHappyEyeballsV3Enabled() const override;
  void AddTransactionTimeQueued(base::TimeDelta time_queued) override;

  // DnsTaskResultsManager::Delegate implementation:
  void OnServiceEndpointsUpdated() override;

  void StartMdnsTask();
  void OnMdnsTaskComplete();
  void OnMdnsImmediateFailure(int rv);

  void StartNat64Task();
  void OnNat64TaskComplete();

  void RecordJobHistograms(const HostCache::Entry& results,
                           std::optional<TaskType> task_type);

  void MaybeCacheResult(const HostCache::Entry& results,
                        base::TimeDelta ttl,
                        bool secure);

  // Performs Job's last rites. Completes all Requests. Deletes this.
  //
  // If not |allow_cache|, result will not be stored in the host cache, even if
  // result would otherwise allow doing so. Update the key to reflect |secure|,
  // which indicates whether or not the result was obtained securely.
  void CompleteRequests(const HostCache::Entry& results,
                        base::TimeDelta ttl,
                        bool allow_cache,
                        bool secure,
                        std::optional<TaskType> task_type);

  void CompleteRequestsWithoutCache(
      const HostCache::Entry& results,
      std::optional<HostCache::EntryStaleness> stale_info,
      TaskType task_type);

  // Convenience wrapper for CompleteRequests in case of failure.
  void CompleteRequestsWithError(int net_error,
                                 std::optional<TaskType> task_type);

  RequestPriority priority() const override;

  // Number of non-canceled requests in |requests_|.
  size_t num_active_requests() const { return priority_tracker_.total_count(); }

  base::WeakPtr<HostResolverManager> resolver_;

  const JobKey key_;
  const ResolveHostParameters::CacheUsage cache_usage_;
  // TODO(crbug.com/41462480): Consider allowing requests within a single Job to
  // have different HostCaches.
  const raw_ptr<HostCache> host_cache_;

  struct CompletionResult {
    const HostCache::Entry entry;
    base::TimeDelta ttl;
    bool secure;
  };

  // Results to use in last-ditch attempt to complete request.
  std::vector<CompletionResult> completion_results_;

  // The sequence of tasks to run in this Job. Tasks may be aborted and removed
  // from the sequence, but otherwise the tasks will run in order until a
  // successful result is found.
  std::deque<TaskType> tasks_;

  // Whether the job is running.
  bool job_running_ = false;

  // Tracks the highest priority across |requests_|.
  PriorityTracker priority_tracker_;

  bool had_non_speculative_request_ = false;

  // Number of slots occupied by this Job in |dispatcher_|. Should be 0 when
  // the job is not registered with any dispatcher.
  int num_occupied_job_slots_ = 0;

  // True once this Job has been sent to `resolver_->dispatcher_`.
  bool dispatched_ = false;

  // Result of DnsTask.
  int dns_task_error_ = OK;

  raw_ptr<const base::TickClock> tick_clock_;
  base::TimeTicks start_time_;

  HostResolver::HttpsSvcbOptions https_svcb_options_;

  NetLogWithSource net_log_;

  // Resolves the host using the system DNS resolver, which can be overridden
  // for tests.
  std::unique_ptr<HostResolverSystemTask> system_task_;

  // Resolves the host using a DnsTransaction.
  std::unique_ptr<HostResolverDnsTask> dns_task_;

  // Resolves the host using MDnsClient.
  std::unique_ptr<HostResolverMdnsTask> mdns_task_;

  // Perform NAT64 address synthesis to a given IPv4 literal.
  std::unique_ptr<HostResolverNat64Task> nat64_task_;

  // All Requests waiting for the result of this Job. Some can be canceled.
  base::LinkedList<RequestImpl> requests_;

  // All ServiceEndpointRequests waiting for the result of this Job. Some can
  // be canceled.
  base::LinkedList<ServiceEndpointRequestImpl> service_endpoint_requests_;

  // Builds and updates intermediate service endpoints while executing
  // a DnsTransaction.
  std::unique_ptr<DnsTaskResultsManager> dns_task_results_manager_;

  // A handle used for |dispatcher_|.
  PrioritizedDispatcher::Handle handle_;

  // Iterator to |this| in the JobMap. |nullopt| if not owned by the JobMap.
  std::optional<JobMap::iterator> self_iterator_;

  base::TimeDelta total_transaction_time_queued_;

  base::WeakPtrFactory<Job> weak_ptr_factory_{this};
};

}  // namespace net

#endif  // NET_DNS_HOST_RESOLVER_MANAGER_JOB_H_