chromium/chrome/browser/ash/net/network_diagnostics/tls_prober.h

// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_ASH_NET_NETWORK_DIAGNOSTICS_TLS_PROBER_H_
#define CHROME_BROWSER_ASH_NET_NETWORK_DIAGNOSTICS_TLS_PROBER_H_

#include <optional>

#include "base/functional/callback.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/task/sequenced_task_runner.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "net/base/completion_once_callback.h"
#include "net/base/host_port_pair.h"
#include "services/network/public/cpp/network_context_getter.h"
#include "services/network/public/mojom/network_context.mojom.h"
#include "services/network/public/mojom/tcp_socket.mojom.h"
#include "services/network/public/mojom/tls_socket.mojom.h"

namespace network {
class SimpleHostResolver;
}  // namespace network

namespace ash::network_diagnostics {

// Uses either a TCP or TLS socket to determine whether a socket connection to a
// host can be established. No read or write functionality is exposed by this
// socket. Used by network diagnostics routines.
class TlsProber {
 public:
  // Lists the ways a prober may end. The callback passed into the prober's
  // constructor is invoked while exiting.
  enum ProbeExitEnum {
    kDnsFailure,
    kTcpConnectionFailure,
    kTlsUpgradeFailure,
    kMojoDisconnectFailure,
    kSuccess,
  };
  using OnConnectCompleteOnUIThreadCallback =
      base::OnceCallback<void(int result,
                              const std::optional<net::IPEndPoint>& peer_addr)>;
  using TlsProbeCompleteCallback =
      base::OnceCallback<void(int result, ProbeExitEnum probe_exit_enum)>;

  // Establishes a TCP connection to |host_port_pair|. If |negotiate_tls| is
  // true, the underlying TCP socket upgrades to include TLS support. Note that
  // the constructor will not invoke |callback|, which is passed into TlsProber
  // during construction. This ensures the TlsProber instance is constructed
  // before |callback| is invoked.  The TlsProber must be created on the UI
  // thread and will invoke |callback| on the UI thread.
  // |network_context_getter| will be invoked on the UI thread.
  TlsProber(network::NetworkContextGetter network_context_getter,
            net::HostPortPair host_port_pair,
            bool negotiate_tls,
            TlsProbeCompleteCallback callback);
  TlsProber(const TlsProber&) = delete;
  TlsProber& operator=(const TlsProber&) = delete;
  virtual ~TlsProber();

  // Processes the results of the DNS resolution done by |host_resolver_|.
  void OnHostResolutionComplete(
      int result,
      const net::ResolveErrorInfo&,
      const std::optional<net::AddressList>& resolved_addresses,
      const std::optional<net::HostResolverEndpointResults>&);

 protected:
  // Test-only constructor.
  TlsProber();

 private:
  // On success, upgrades a TCPConnectedSocket to a TLSClientSocket. On failure,
  // invokes the callback passed into the TlsProber instance with a failure
  // response.
  // Note that |receive_stream| and |send_stream|, created on the TCP
  // connection, are only present to fit the callback signature of
  // network::mojom::NetworkContext::CreateTCPConnectedSocketCallback. As error
  // handling has not been set up, the streams should not be used and fall out
  // of scope when this method completes.
  void OnConnectComplete(int result,
                         const std::optional<net::IPEndPoint>& local_addr,
                         const std::optional<net::IPEndPoint>& peer_addr,
                         mojo::ScopedDataPipeConsumerHandle receive_stream,
                         mojo::ScopedDataPipeProducerHandle send_stream);

  // Processes the results of the TLS upgrade.
  // Note that |receive_stream| and |send_stream| are only present to fit the
  // callback signature of
  // network::mojom::NetworkContext::CreateTCPConnectedSocketCallback. As error
  // handling has not been set up, the streams should not be used.
  void OnTlsUpgrade(int result,
                    mojo::ScopedDataPipeConsumerHandle receive_stream,
                    mojo::ScopedDataPipeProducerHandle send_stream,
                    const std::optional<net::SSLInfo>& ssl_info);

  // Handles disconnects on the TCP connected and TLS client remotes.
  void OnDisconnect();

  // Signals the end of the probe. Manages the clean up and returns a response
  // to the caller.
  void OnDone(int result, ProbeExitEnum probe_exit_enum);

  // Gets the active profile-specific network context.
  const network::NetworkContextGetter network_context_getter_;
  // Contains the hostname and port.
  const net::HostPortPair host_port_pair_;
  // Indicates whether TLS support must be added to the underlying socket.
  const bool negotiate_tls_;
  // Host resolver used for DNS lookup.
  std::unique_ptr<network::SimpleHostResolver> host_resolver_;
  // Holds socket if socket was connected via TCP.
  mojo::Remote<network::mojom::TCPConnectedSocket> tcp_connected_socket_remote_;
  // Holds socket if socket was upgraded to TLS.
  mojo::Remote<network::mojom::TLSClientSocket> tls_client_socket_remote_;
  // Stores the callback invoked once probe is complete or interrupted.
  TlsProbeCompleteCallback callback_;
  // WeakPtr is used when posting tasks to |task_runner_| which might outlive
  // |this|.
  base::WeakPtrFactory<TlsProber> weak_factory_{this};
};

}  // namespace ash::network_diagnostics

#endif  // CHROME_BROWSER_ASH_NET_NETWORK_DIAGNOSTICS_TLS_PROBER_H_