blob: ef1e9f5186f5de950f25a2587358cc7cd78f8912 [file] [log] [blame]
// 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 <optional>
#include <string>
#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<HostResolverProc> 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<HostResolverProc> 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<HostResolverSystemTask> 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<HostResolverSystemTask> 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<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);
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<std::string> 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<HostResolverSystemTask> 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<base::TaskRunner> 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<void(const std::optional<std::string>& 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_