// Copyright 2022 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_SYSTEM_TASK_H_ #define NET_DNS_HOST_RESOLVER_SYSTEM_TASK_H_ #include #include #include "base/functional/callback.h" #include "base/functional/callback_helpers.h" #include "base/task/task_runner.h" #include "net/base/address_list.h" #include "net/base/net_export.h" #include "net/base/network_handle.h" #include "net/dns/host_resolver_proc.h" #include "net/log/net_log_with_source.h" namespace net { using SystemDnsResultsCallback = base::OnceCallback< void(const AddressList& addr_list, int os_error, int net_error)>; // Calls SystemHostResolverCall() (or in some tests, HostResolverProc::Resolve) // in ThreadPool. So EnsureSystemHostResolverCallReady() must be called before // using this class. // // Performs retries if specified by HostResolverSystemTask::Params. // // Whenever we try to resolve the host, we post a delayed task to check if host // resolution (OnLookupComplete) is completed or not. If the original attempt // hasn't completed, then we start another attempt for host resolution. We take // the results from the first attempt that finishes and ignore the results from // all other attempts. // // This class is designed to be used not just by HostResolverManager, but by // general consumers. // // It should only be used on the main thread to ensure that hooks (see // SetSystemHostResolverOverride()) only ever run on the main thread. class NET_EXPORT HostResolverSystemTask { public: // Parameters for customizing HostResolverSystemTask behavior. // // |resolver_proc| is used to override resolution in tests; it must be // thread-safe since it may be run from multiple worker threads. If // |resolver_proc| is NULL then the default host resolver procedure is // to call SystemHostResolverCall(). // // For each attempt, we could start another attempt if host is not resolved // within |unresponsive_delay| time. We keep attempting to resolve the host // for |max_retry_attempts|. For every retry attempt, we grow the // |unresponsive_delay| by the |retry_factor| amount (that is retry interval // is multiplied by the retry factor each time). Once we have retried // |max_retry_attempts|, we give up on additional attempts. struct NET_EXPORT_PRIVATE Params { // Default delay between calls to the system resolver for the same hostname. // (Can be overridden by field trial.) static constexpr base::TimeDelta kDnsDefaultUnresponsiveDelay = base::Seconds(6); // Set |max_system_retry_attempts| to this to select a default retry value. static constexpr size_t kDefaultRetryAttempts = -1; // Sets up defaults. Params(scoped_refptr resolver_proc, size_t max_retry_attempts); Params(const Params& other); ~Params(); // The procedure to use for resolving host names. This will be NULL, except // in the case of some-tests which inject custom host resolving behaviors. scoped_refptr resolver_proc; // Maximum number retry attempts to resolve the hostname. // Pass HostResolver::Options::kDefaultRetryAttempts to choose a default // value. size_t max_retry_attempts; // This is the limit after which we make another attempt to resolve the host // if the worker thread has not responded yet. base::TimeDelta unresponsive_delay = kDnsDefaultUnresponsiveDelay; // Factor to grow |unresponsive_delay| when we re-re-try. uint32_t retry_factor = 2; }; static std::unique_ptr Create( std::string hostname, AddressFamily address_family, HostResolverFlags flags, const Params& params = Params(nullptr, 0), const NetLogWithSource& job_net_log = NetLogWithSource(), handles::NetworkHandle network = handles::kInvalidNetworkHandle); // Same as above but resolves the result of GetHostName() (the machine's own // hostname). static std::unique_ptr CreateForOwnHostname( AddressFamily address_family, HostResolverFlags flags, const Params& params = Params(nullptr, 0), const NetLogWithSource& job_net_log = NetLogWithSource(), handles::NetworkHandle network = handles::kInvalidNetworkHandle); // If `hostname` is std::nullopt, resolves the result of GetHostName(). // Prefer using the above 2 static functions for constructing a // HostResolverSystemTask. HostResolverSystemTask( std::optional hostname, AddressFamily address_family, HostResolverFlags flags, const Params& params = Params(nullptr, 0), const NetLogWithSource& job_net_log = NetLogWithSource(), handles::NetworkHandle network = handles::kInvalidNetworkHandle); HostResolverSystemTask(const HostResolverSystemTask&) = delete; HostResolverSystemTask& operator=(const HostResolverSystemTask&) = delete; // Cancels this HostResolverSystemTask. Any outstanding resolve attempts // cannot be cancelled, but they will post back to the current thread before // checking their WeakPtrs to find that this task is cancelled. ~HostResolverSystemTask(); // Starts the resolution task. This can only be called once per // HostResolverSystemTask. `results_cb` will not be invoked synchronously and // can own `this`. void Start(SystemDnsResultsCallback results_cb); bool was_completed() const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return results_cb_.is_null(); } private: void StartLookupAttempt(); // Callback for when DoLookup() completes. void OnLookupComplete(const uint32_t attempt_number, const AddressList& results, const int os_error, int error); // If `hostname_` is std::nullopt, this class should resolve the result of // net::GetHostName() (the machine's own hostname). const std::optional hostname_; const AddressFamily address_family_; const HostResolverFlags flags_; // Holds an owning reference to the HostResolverProc that we are going to use. // This may not be the current resolver procedure by the time we call // ResolveAddrInfo, but that's OK... we'll use it anyways, and the owning // reference ensures that it remains valid until we are done. Params params_; // The listener to the results of this HostResolverSystemTask. SystemDnsResultsCallback results_cb_; // Keeps track of the number of attempts we have made so far to resolve the // host. Whenever we start an attempt to resolve the host, we increase this // number. uint32_t attempt_number_ = 0; NetLogWithSource net_log_; // Network to perform DNS lookups for. const handles::NetworkHandle network_; SEQUENCE_CHECKER(sequence_checker_); // Used to loop back from the blocking lookup attempt tasks as well as from // delayed retry tasks. Invalidate WeakPtrs on completion and cancellation to // cancel handling of such posted tasks. base::WeakPtrFactory weak_ptr_factory_{this}; }; // Ensures any necessary initialization occurs such that // SystemHostResolverCall() can be called on other threads. NET_EXPORT void EnsureSystemHostResolverCallReady(); // Resolves `host` to an address list, using the system's default host resolver. // (i.e. this calls out to getaddrinfo()). If successful returns OK and fills // `addrlist` with a list of socket addresses. Otherwise returns a // network error code, and fills `os_error` with a more specific error if it // was non-NULL. // `network` is an optional parameter, when specified (!= // handles::kInvalidNetworkHandle) the lookup will be performed specifically for // `network`. // // This should NOT be called in a sandboxed process. NET_EXPORT_PRIVATE int SystemHostResolverCall( const std::string& host, AddressFamily address_family, HostResolverFlags host_resolver_flags, AddressList* addrlist, int* os_error, handles::NetworkHandle network = handles::kInvalidNetworkHandle); // Sets the task runner that system DNS resolution will run on, which is mostly // useful for tests and fuzzers that need reproducibilty of failures. NET_EXPORT_PRIVATE void SetSystemDnsResolutionTaskRunnerForTesting( scoped_refptr task_runner); // The following will be used to override the behavior of // HostResolverSystemTask. This override will be called instead of posting // SystemHostResolverCall() to a worker thread. The override will only be // invoked on the main thread. // The override should never invoke `results_cb` synchronously. NET_EXPORT void SetSystemDnsResolverOverride( base::RepeatingCallback& host, AddressFamily address_family, HostResolverFlags host_resolver_flags, SystemDnsResultsCallback results_cb, handles::NetworkHandle network)> dns_override); } // namespace net #endif // NET_DNS_HOST_RESOLVER_SYSTEM_TASK_H_