123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- // Copyright 2018 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #ifndef NET_SOCKET_TRANSPORT_CONNECT_JOB_H_
- #define NET_SOCKET_TRANSPORT_CONNECT_JOB_H_
- #include <memory>
- #include <set>
- #include <string>
- #include <vector>
- #include "base/containers/flat_set.h"
- #include "base/containers/span.h"
- #include "base/memory/ref_counted.h"
- #include "base/memory/weak_ptr.h"
- #include "base/time/time.h"
- #include "base/timer/timer.h"
- #include "net/base/host_port_pair.h"
- #include "net/base/net_export.h"
- #include "net/base/network_isolation_key.h"
- #include "net/dns/host_resolver.h"
- #include "net/dns/host_resolver_results.h"
- #include "net/dns/public/resolve_error_info.h"
- #include "net/dns/public/secure_dns_policy.h"
- #include "net/socket/connect_job.h"
- #include "net/socket/connection_attempts.h"
- #include "third_party/abseil-cpp/absl/types/optional.h"
- #include "third_party/abseil-cpp/absl/types/variant.h"
- #include "url/scheme_host_port.h"
- namespace net {
- class NetLogWithSource;
- class SocketTag;
- class TransportConnectSubJob;
- class NET_EXPORT_PRIVATE TransportSocketParams
- : public base::RefCounted<TransportSocketParams> {
- public:
- // Representation of the destination endpoint of the transport
- // socket/connection. Unlike ConnectJobFactory::Endpoint, this does not have a
- // `using_ssl` field for schemeless endpoints because that has no meaning for
- // transport parameters.
- using Endpoint = absl::variant<url::SchemeHostPort, HostPortPair>;
- // |host_resolution_callback| will be invoked after the the hostname is
- // resolved. |network_isolation_key| is passed to the HostResolver to prevent
- // cross-NIK leaks. If |host_resolution_callback| does not return OK, then the
- // connection will be aborted with that value. |supported_alpns| specifies
- // ALPN protocols for selecting HTTPS/SVCB records. If empty, addresses from
- // HTTPS/SVCB records will be ignored and only A/AAAA will be used.
- TransportSocketParams(Endpoint destination,
- NetworkIsolationKey network_isolation_key,
- SecureDnsPolicy secure_dns_policy,
- OnHostResolutionCallback host_resolution_callback,
- base::flat_set<std::string> supported_alpns);
- TransportSocketParams(const TransportSocketParams&) = delete;
- TransportSocketParams& operator=(const TransportSocketParams&) = delete;
- const Endpoint& destination() const { return destination_; }
- const NetworkIsolationKey& network_isolation_key() const {
- return network_isolation_key_;
- }
- SecureDnsPolicy secure_dns_policy() const { return secure_dns_policy_; }
- const OnHostResolutionCallback& host_resolution_callback() const {
- return host_resolution_callback_;
- }
- const base::flat_set<std::string>& supported_alpns() const {
- return supported_alpns_;
- }
- private:
- friend class base::RefCounted<TransportSocketParams>;
- ~TransportSocketParams();
- const Endpoint destination_;
- const NetworkIsolationKey network_isolation_key_;
- const SecureDnsPolicy secure_dns_policy_;
- const OnHostResolutionCallback host_resolution_callback_;
- const base::flat_set<std::string> supported_alpns_;
- };
- // TransportConnectJob handles the host resolution necessary for socket creation
- // and the transport (likely TCP) connect. TransportConnectJob also has fallback
- // logic for IPv6 connect() timeouts (which may happen due to networks / routers
- // with broken IPv6 support). Those timeouts take 20s, so rather than make the
- // user wait 20s for the timeout to fire, we use a fallback timer
- // (kIPv6FallbackTime) and start a connect() to a IPv4 address if the timer
- // fires. Then we race the IPv4 connect() against the IPv6 connect() (which has
- // a headstart) and return the one that completes first to the socket pool.
- class NET_EXPORT_PRIVATE TransportConnectJob : public ConnectJob {
- public:
- class NET_EXPORT_PRIVATE Factory {
- public:
- Factory() = default;
- virtual ~Factory() = default;
- virtual std::unique_ptr<TransportConnectJob> Create(
- RequestPriority priority,
- const SocketTag& socket_tag,
- const CommonConnectJobParams* common_connect_job_params,
- const scoped_refptr<TransportSocketParams>& params,
- Delegate* delegate,
- const NetLogWithSource* net_log);
- };
- // In cases where both IPv6 and IPv4 addresses were returned from DNS,
- // TransportConnectJobs will start a second connection attempt to just the
- // IPv4 addresses after this much time. (This is "Happy Eyeballs".)
- //
- // TODO(willchan): Base this off RTT instead of statically setting it. Note we
- // choose a timeout that is different from the backup connect job timer so
- // they don't synchronize.
- static constexpr base::TimeDelta kIPv6FallbackTime = base::Milliseconds(300);
- struct NET_EXPORT_PRIVATE EndpointResultOverride {
- EndpointResultOverride(HostResolverEndpointResult result,
- std::set<std::string> dns_aliases);
- EndpointResultOverride(EndpointResultOverride&&);
- EndpointResultOverride(const EndpointResultOverride&);
- ~EndpointResultOverride();
- EndpointResultOverride& operator=(EndpointResultOverride&&) = default;
- EndpointResultOverride& operator=(const EndpointResultOverride&) = default;
- HostResolverEndpointResult result;
- std::set<std::string> dns_aliases;
- };
- TransportConnectJob(RequestPriority priority,
- const SocketTag& socket_tag,
- const CommonConnectJobParams* common_connect_job_params,
- const scoped_refptr<TransportSocketParams>& params,
- Delegate* delegate,
- const NetLogWithSource* net_log,
- absl::optional<EndpointResultOverride>
- endpoint_result_override = absl::nullopt);
- TransportConnectJob(const TransportConnectJob&) = delete;
- TransportConnectJob& operator=(const TransportConnectJob&) = delete;
- ~TransportConnectJob() override;
- // ConnectJob methods.
- LoadState GetLoadState() const override;
- bool HasEstablishedConnection() const override;
- ConnectionAttempts GetConnectionAttempts() const override;
- ResolveErrorInfo GetResolveErrorInfo() const override;
- absl::optional<HostResolverEndpointResult> GetHostResolverEndpointResult()
- const override;
- static base::TimeDelta ConnectionTimeout();
- private:
- friend class TransportConnectSubJob;
- enum State {
- STATE_RESOLVE_HOST,
- STATE_RESOLVE_HOST_COMPLETE,
- STATE_RESOLVE_HOST_CALLBACK_COMPLETE,
- STATE_TRANSPORT_CONNECT,
- STATE_TRANSPORT_CONNECT_COMPLETE,
- STATE_NONE,
- };
- // Although it is not strictly necessary, it makes the code simpler if each
- // subjob knows what type it is.
- enum SubJobType { SUB_JOB_IPV4, SUB_JOB_IPV6 };
- void OnIOComplete(int result);
- int DoLoop(int result);
- int DoResolveHost();
- int DoResolveHostComplete(int result);
- int DoResolveHostCallbackComplete();
- int DoTransportConnect();
- int DoTransportConnectComplete(int result);
- // Helper method called called when a SubJob completes, synchronously
- // or asynchronously. Returns `ERR_IO_PENDING` if there is more work to
- // do and another error if completed. It's up to the caller to manage
- // advancing `DoLoop` if a value other than `ERR_IO_PENDING` is returned.
- int HandleSubJobComplete(int result, TransportConnectSubJob* job);
- // Called back from a SubJob when it completes. Invokes `OnIOComplete`,
- // re-entering `DoLoop`, if there is no more work to do. Must not
- // be called from within `DoLoop`.
- void OnSubJobComplete(int result, TransportConnectSubJob* job);
- // Called from |fallback_timer_|.
- void StartIPv4JobAsync();
- // Begins the host resolution and the TCP connect. Returns OK on success
- // and ERR_IO_PENDING if it cannot immediately service the request.
- // Otherwise, it returns a net error code.
- int ConnectInternal() override;
- void ChangePriorityInternal(RequestPriority priority) override;
- // Returns whether the client should be SVCB-optional when connecting to
- // `results`.
- bool IsSvcbOptional(
- base::span<const HostResolverEndpointResult> results) const;
- // Returns whether `result` is usable for this connection. If `svcb_optional`
- // is true, the non-HTTPS/SVCB fallback is allowed.
- bool IsEndpointResultUsable(const HostResolverEndpointResult& result,
- bool svcb_optional) const;
- // Returns the `HostResolverEndpointResult` for the current subjobs.
- const HostResolverEndpointResult& GetEndpointResultForCurrentSubJobs() const;
- scoped_refptr<TransportSocketParams> params_;
- std::unique_ptr<HostResolver::ResolveHostRequest> request_;
- std::vector<HostResolverEndpointResult> endpoint_results_;
- size_t current_endpoint_result_ = 0;
- std::set<std::string> dns_aliases_;
- bool has_dns_override_ = false;
- State next_state_ = STATE_NONE;
- // The addresses are divided into IPv4 and IPv6, which are performed partially
- // in parallel. If the list of IPv6 addresses is non-empty, then the IPv6 jobs
- // go first, followed after `kIPv6FallbackTime` by the IPv4 addresses. The
- // first sub-job to establish a connection wins. If one sub-job fails, the
- // other one is launched if needed, and we wait for it to complete.
- std::unique_ptr<TransportConnectSubJob> ipv4_job_;
- std::unique_ptr<TransportConnectSubJob> ipv6_job_;
- base::OneShotTimer fallback_timer_;
- ResolveErrorInfo resolve_error_info_;
- ConnectionAttempts connection_attempts_;
- base::WeakPtrFactory<TransportConnectJob> weak_ptr_factory_{this};
- };
- } // namespace net
- #endif // NET_SOCKET_TRANSPORT_CONNECT_JOB_H_
|