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