xref: /aosp_15_r20/external/cronet/net/dns/host_resolver_manager_job.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2024 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef NET_DNS_HOST_RESOLVER_MANAGER_JOB_H_
6 #define NET_DNS_HOST_RESOLVER_MANAGER_JOB_H_
7 
8 #include <deque>
9 #include <memory>
10 #include <optional>
11 #include <vector>
12 
13 #include "base/containers/linked_list.h"
14 #include "base/memory/raw_ptr.h"
15 #include "base/memory/safe_ref.h"
16 #include "base/memory/weak_ptr.h"
17 #include "base/time/time.h"
18 #include "net/base/address_family.h"
19 #include "net/base/network_anonymization_key.h"
20 #include "net/base/network_handle.h"
21 #include "net/base/prioritized_dispatcher.h"
22 #include "net/dns/dns_task_results_manager.h"
23 #include "net/dns/host_cache.h"
24 #include "net/dns/host_resolver.h"
25 #include "net/dns/host_resolver_dns_task.h"
26 #include "net/dns/host_resolver_manager.h"
27 #include "net/dns/public/dns_query_type.h"
28 #include "net/dns/public/secure_dns_mode.h"
29 #include "net/log/net_log_with_source.h"
30 #include "third_party/abseil-cpp/absl/types/variant.h"
31 
32 namespace net {
33 
34 class ResolveContext;
35 class HostResolverMdnsTask;
36 class HostResolverNat64Task;
37 
38 // Key used to identify a HostResolverManager::Job.
39 struct HostResolverManager::JobKey {
40   JobKey(HostResolver::Host host, ResolveContext* resolve_context);
41   ~JobKey();
42 
43   JobKey(const JobKey& other);
44   JobKey& operator=(const JobKey& other);
45 
46   bool operator<(const JobKey& other) const;
47   bool operator==(const JobKey& other) const;
48 
49   HostResolver::Host host;
50   NetworkAnonymizationKey network_anonymization_key;
51   DnsQueryTypeSet query_types;
52   HostResolverFlags flags;
53   HostResolverSource source;
54   SecureDnsMode secure_dns_mode;
55   base::WeakPtr<ResolveContext> resolve_context;
56 
57   HostCache::Key ToCacheKey(bool secure) const;
58 
59   handles::NetworkHandle GetTargetNetwork() const;
60 };
61 
62 // Aggregates all Requests for the same Key. Dispatched via
63 // PrioritizedDispatcher.
64 class HostResolverManager::Job : public PrioritizedDispatcher::Job,
65                                  public HostResolverDnsTask::Delegate,
66                                  public DnsTaskResultsManager::Delegate {
67  public:
68   // Creates new job for |key| where |request_net_log| is bound to the
69   // request that spawned it.
70   Job(const base::WeakPtr<HostResolverManager>& resolver,
71       JobKey key,
72       ResolveHostParameters::CacheUsage cache_usage,
73       HostCache* host_cache,
74       std::deque<TaskType> tasks,
75       RequestPriority priority,
76       const NetLogWithSource& source_net_log,
77       const base::TickClock* tick_clock,
78       const HostResolver::HttpsSvcbOptions& https_svcb_options);
79   ~Job() override;
80 
81   // Add this job to the dispatcher.  If "at_head" is true, adds at the front
82   // of the queue.
83   void Schedule(bool at_head);
84 
85   void AddRequest(RequestImpl* request);
86 
87   void ChangeRequestPriority(RequestImpl* req, RequestPriority priority);
88 
89   // Detach cancelled request. If it was the last active Request, also finishes
90   // this Job.
91   void CancelRequest(RequestImpl* request);
92 
93   void AddServiceEndpointRequest(ServiceEndpointRequestImpl* request);
94 
95   // Similar to CancelRequest(), if `request` was the last active one, finishes
96   // this job.
97   void CancelServiceEndpointRequest(ServiceEndpointRequestImpl* request);
98 
99   // Called from AbortJobsWithoutTargetNetwork(). Completes all requests and
100   // destroys the job. This currently assumes the abort is due to a network
101   // change.
102   // TODO This should not delete |this|.
103   void Abort();
104 
105   // Gets a closure that will abort an insecure DnsTask (see
106   // AbortInsecureDnsTask()) iff |this| is still valid. Useful if aborting a
107   // list of Jobs as some may be cancelled while aborting others.
108   base::OnceClosure GetAbortInsecureDnsTaskClosure(int error,
109                                                    bool fallback_only);
110 
111   // Aborts or removes any current/future insecure DnsTasks if a
112   // HostResolverSystemTask is available for fallback. If no fallback is
113   // available and |fallback_only| is false, a job that is currently running an
114   // insecure DnsTask will be completed with |error|.
115   void AbortInsecureDnsTask(int error, bool fallback_only);
116 
117   // Called by HostResolverManager when this job is evicted due to queue
118   // overflow. Completes all requests and destroys the job. The job could have
119   // waiting requests that will receive completion callbacks, so cleanup
120   // asynchronously to avoid reentrancy.
121   void OnEvicted();
122 
123   // Attempts to serve the job from HOSTS. Returns true if succeeded and
124   // this Job was destroyed.
125   bool ServeFromHosts();
126 
127   void OnAddedToJobMap(JobMap::iterator iterator);
128 
129   void OnRemovedFromJobMap();
130 
131   void RunNextTask();
132 
key()133   const JobKey& key() const { return key_; }
134 
is_queued()135   bool is_queued() const { return !handle_.is_null(); }
136 
is_running()137   bool is_running() const { return job_running_; }
138 
HasTargetNetwork()139   bool HasTargetNetwork() const {
140     return key_.GetTargetNetwork() != handles::kInvalidNetworkHandle;
141   }
142 
dns_task_results_manager()143   DnsTaskResultsManager* dns_task_results_manager() const {
144     return dns_task_results_manager_.get();
145   }
146 
147  private:
148   // Keeps track of the highest priority.
149   class PriorityTracker {
150    public:
PriorityTracker(RequestPriority initial_priority)151     explicit PriorityTracker(RequestPriority initial_priority)
152         : highest_priority_(initial_priority) {}
153 
highest_priority()154     RequestPriority highest_priority() const { return highest_priority_; }
155 
total_count()156     size_t total_count() const { return total_count_; }
157 
Add(RequestPriority req_priority)158     void Add(RequestPriority req_priority) {
159       ++total_count_;
160       ++counts_[req_priority];
161       if (highest_priority_ < req_priority) {
162         highest_priority_ = req_priority;
163       }
164     }
165 
Remove(RequestPriority req_priority)166     void Remove(RequestPriority req_priority) {
167       DCHECK_GT(total_count_, 0u);
168       DCHECK_GT(counts_[req_priority], 0u);
169       --total_count_;
170       --counts_[req_priority];
171       size_t i;
172       for (i = highest_priority_; i > MINIMUM_PRIORITY && !counts_[i]; --i) {
173       }
174       highest_priority_ = static_cast<RequestPriority>(i);
175 
176       // In absence of requests, default to MINIMUM_PRIORITY.
177       if (total_count_ == 0) {
178         DCHECK_EQ(MINIMUM_PRIORITY, highest_priority_);
179       }
180     }
181 
182    private:
183     RequestPriority highest_priority_;
184     size_t total_count_ = 0;
185     size_t counts_[NUM_PRIORITIES] = {};
186   };
187 
188   base::Value::Dict NetLogJobCreationParams(const NetLogSource& source);
189 
190   void Finish();
191 
192   void KillDnsTask();
193 
194   // Reduce the number of job slots occupied and queued in the dispatcher by
195   // one. If the next Job slot is queued in the dispatcher, cancels the queued
196   // job. Otherwise, the next Job has been started by the PrioritizedDispatcher,
197   // so signals it is complete.
198   void ReduceByOneJobSlot();
199 
200   // Common helper methods for adding and canceling a request.
201   void AddRequestCommon(RequestPriority request_priority,
202                         const NetLogWithSource& request_net_log,
203                         bool is_speculative);
204   void CancelRequestCommon(RequestPriority request_priority,
205                            const NetLogWithSource& request_net_log);
206 
207   void UpdatePriority();
208 
209   // PrioritizedDispatcher::Job:
210   void Start() override;
211 
212   // TODO(szym): Since DnsTransaction does not consume threads, we can increase
213   // the limits on |dispatcher_|. But in order to keep the number of
214   // ThreadPool threads low, we will need to use an "inner"
215   // PrioritizedDispatcher with tighter limits.
216   void StartSystemTask();
217   // Called by HostResolverSystemTask when it completes.
218   void OnSystemTaskComplete(base::TimeTicks start_time,
219                             const AddressList& addr_list,
220                             int /*os_error*/,
221                             int net_error);
222 
223   void InsecureCacheLookup();
224 
225   void StartDnsTask(bool secure);
226   void StartNextDnsTransaction();
227   // Called if DnsTask fails. It is posted from StartDnsTask, so Job may be
228   // deleted before this callback. In this case dns_task is deleted as well,
229   // so we use it as indicator whether Job is still valid.
230   void OnDnsTaskFailure(const base::WeakPtr<HostResolverDnsTask>& dns_task,
231                         base::TimeDelta duration,
232                         bool allow_fallback,
233                         const HostCache::Entry& failure_results,
234                         bool secure);
235   // HostResolverDnsTask::Delegate implementation:
236   void OnDnsTaskComplete(base::TimeTicks start_time,
237                          bool allow_fallback,
238                          HostCache::Entry results,
239                          bool secure) override;
240   void OnIntermediateTransactionsComplete(
241       std::optional<HostResolverDnsTask::SingleTransactionResults>
242           single_transaction_results) override;
243   void AddTransactionTimeQueued(base::TimeDelta time_queued) override;
244 
245   // DnsTaskResultsManager::Delegate implementation:
246   void OnServiceEndpointsUpdated() override;
247 
248   void StartMdnsTask();
249   void OnMdnsTaskComplete();
250   void OnMdnsImmediateFailure(int rv);
251 
252   void StartNat64Task();
253   void OnNat64TaskComplete();
254 
255   void RecordJobHistograms(const HostCache::Entry& results,
256                            std::optional<TaskType> task_type);
257 
258   void MaybeCacheResult(const HostCache::Entry& results,
259                         base::TimeDelta ttl,
260                         bool secure);
261 
262   // Performs Job's last rites. Completes all Requests. Deletes this.
263   //
264   // If not |allow_cache|, result will not be stored in the host cache, even if
265   // result would otherwise allow doing so. Update the key to reflect |secure|,
266   // which indicates whether or not the result was obtained securely.
267   void CompleteRequests(const HostCache::Entry& results,
268                         base::TimeDelta ttl,
269                         bool allow_cache,
270                         bool secure,
271                         std::optional<TaskType> task_type);
272 
273   void CompleteRequestsWithoutCache(
274       const HostCache::Entry& results,
275       std::optional<HostCache::EntryStaleness> stale_info,
276       TaskType task_type);
277 
278   // Convenience wrapper for CompleteRequests in case of failure.
279   void CompleteRequestsWithError(int net_error,
280                                  std::optional<TaskType> task_type);
281 
282   RequestPriority priority() const override;
283 
284   // Number of non-canceled requests in |requests_|.
num_active_requests()285   size_t num_active_requests() const { return priority_tracker_.total_count(); }
286 
287   base::WeakPtr<HostResolverManager> resolver_;
288 
289   const JobKey key_;
290   const ResolveHostParameters::CacheUsage cache_usage_;
291   // TODO(crbug.com/969847): Consider allowing requests within a single Job to
292   // have different HostCaches.
293   const raw_ptr<HostCache> host_cache_;
294 
295   struct CompletionResult {
296     const HostCache::Entry entry;
297     base::TimeDelta ttl;
298     bool secure;
299   };
300 
301   // Results to use in last-ditch attempt to complete request.
302   std::vector<CompletionResult> completion_results_;
303 
304   // The sequence of tasks to run in this Job. Tasks may be aborted and removed
305   // from the sequence, but otherwise the tasks will run in order until a
306   // successful result is found.
307   std::deque<TaskType> tasks_;
308 
309   // Whether the job is running.
310   bool job_running_ = false;
311 
312   // Tracks the highest priority across |requests_|.
313   PriorityTracker priority_tracker_;
314 
315   bool had_non_speculative_request_ = false;
316 
317   // Number of slots occupied by this Job in |dispatcher_|. Should be 0 when
318   // the job is not registered with any dispatcher.
319   int num_occupied_job_slots_ = 0;
320 
321   // True once this Job has been sent to `resolver_->dispatcher_`.
322   bool dispatched_ = false;
323 
324   // Result of DnsTask.
325   int dns_task_error_ = OK;
326 
327   raw_ptr<const base::TickClock> tick_clock_;
328   base::TimeTicks start_time_;
329 
330   HostResolver::HttpsSvcbOptions https_svcb_options_;
331 
332   NetLogWithSource net_log_;
333 
334   // Resolves the host using the system DNS resolver, which can be overridden
335   // for tests.
336   std::unique_ptr<HostResolverSystemTask> system_task_;
337 
338   // Resolves the host using a DnsTransaction.
339   std::unique_ptr<HostResolverDnsTask> dns_task_;
340 
341   // Resolves the host using MDnsClient.
342   std::unique_ptr<HostResolverMdnsTask> mdns_task_;
343 
344   // Perform NAT64 address synthesis to a given IPv4 literal.
345   std::unique_ptr<HostResolverNat64Task> nat64_task_;
346 
347   // All Requests waiting for the result of this Job. Some can be canceled.
348   base::LinkedList<RequestImpl> requests_;
349 
350   // All ServiceEndpointRequests waiting for the result of this Job. Some can
351   // be canceled.
352   base::LinkedList<ServiceEndpointRequestImpl> service_endpoint_requests_;
353 
354   // Builds and updates intermediate service endpoints while executing
355   // a DnsTransaction.
356   std::unique_ptr<DnsTaskResultsManager> dns_task_results_manager_;
357 
358   // A handle used for |dispatcher_|.
359   PrioritizedDispatcher::Handle handle_;
360 
361   // Iterator to |this| in the JobMap. |nullopt| if not owned by the JobMap.
362   std::optional<JobMap::iterator> self_iterator_;
363 
364   base::TimeDelta total_transaction_time_queued_;
365 
366   base::WeakPtrFactory<Job> weak_ptr_factory_{this};
367 };
368 
369 }  // namespace net
370 
371 #endif  // NET_DNS_HOST_RESOLVER_MANAGER_JOB_H_
372