chromium/chrome/browser/ash/net/network_diagnostics/fake_network_context.cc

// 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.

#include "chrome/browser/ash/net/network_diagnostics/fake_network_context.h"

#include <utility>

#include "base/logging.h"
#include "base/notreached.h"
#include "services/network/public/mojom/host_resolver.mojom.h"

namespace ash::network_diagnostics {

namespace {

// Represents a fake port number of a fake IP address.
const int kFakePortNumber = 1234;

// Returns a fake IP address.
net::IPEndPoint FakeIPAddress() {
  return net::IPEndPoint(net::IPAddress::IPv4Localhost(), kFakePortNumber);
}

}  // namespace

FakeNetworkContext::DnsResult::DnsResult(
    int32_t result,
    net::ResolveErrorInfo resolve_error_info,
    std::optional<net::AddressList> resolved_addresses,
    std::optional<net::HostResolverEndpointResults>
        endpoint_results_with_metadata)
    : result_(result),
      resolve_error_info_(resolve_error_info),
      resolved_addresses_(resolved_addresses),
      endpoint_results_with_metadata_(endpoint_results_with_metadata) {}

FakeNetworkContext::DnsResult::~DnsResult() = default;

FakeNetworkContext::FakeNetworkContext() = default;

FakeNetworkContext::~FakeNetworkContext() = default;

void FakeNetworkContext::ResolveHost(
    network::mojom::HostResolverHostPtr host,
    const net::NetworkAnonymizationKey& network_anonymization_key,
    network::mojom::ResolveHostParametersPtr optional_parameters,
    mojo::PendingRemote<network::mojom::ResolveHostClient> response_client) {
  if (host_resolution_disconnect_) {
    response_client.reset();
    return;
  }
  mojo::Remote<network::mojom::ResolveHostClient> rpc(
      std::move(response_client));
  if (fake_dns_result_) {
    rpc->OnComplete(fake_dns_result_->result_,
                    fake_dns_result_->resolve_error_info_,
                    fake_dns_result_->resolved_addresses_,
                    fake_dns_result_->endpoint_results_with_metadata_);
  } else {
    CHECK(!fake_dns_results_.empty());
    auto dns_result = std::move(fake_dns_results_.front());
    fake_dns_results_.pop_front();
    rpc->OnComplete(dns_result->result_, dns_result->resolve_error_info_,
                    dns_result->resolved_addresses_,
                    dns_result->endpoint_results_with_metadata_);
  }
  rpc.reset();
}

void FakeNetworkContext::CreateTCPConnectedSocket(
    const std::optional<net::IPEndPoint>& local_addr,
    const net::AddressList& remote_addr_list,
    network::mojom::TCPConnectedSocketOptionsPtr tcp_connected_socket_options,
    const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
    mojo::PendingReceiver<network::mojom::TCPConnectedSocket> socket,
    mojo::PendingRemote<network::mojom::SocketObserver> observer,
    CreateTCPConnectedSocketCallback callback) {
  if (tcp_connection_attempt_disconnect_) {
    socket.reset();
    return;
  }

  // Only bind the receiver if TCP connection is successful.
  if (tcp_connect_code_ == net::OK) {
    DCHECK(fake_tcp_connected_socket_);
    fake_tcp_connected_socket_->BindReceiver(std::move(socket));
    fake_tcp_connected_socket_->set_disconnect_during_tls_upgrade_attempt(
        tls_upgrade_attempt_disconnect_);
  }
  std::move(callback).Run(tcp_connect_code_, FakeIPAddress(), FakeIPAddress(),
                          mojo::ScopedDataPipeConsumerHandle(),
                          mojo::ScopedDataPipeProducerHandle());
}

void FakeNetworkContext::CreateUDPSocket(
    mojo::PendingReceiver<network::mojom::UDPSocket> receiver,
    mojo::PendingRemote<network::mojom::UDPSocketListener> listener) {
  if (udp_connection_attempt_disconnect_) {
    receiver.reset();
    listener.reset();
    return;
  }

  // Bind the receiver if UDP connection is successful.
  if (udp_connect_code_ == net::OK) {
    DCHECK(fake_udp_socket_);

    fake_udp_socket_->BindReceiver(std::move(receiver));
    fake_udp_socket_->BindRemote(std::move(listener));
  }
}

void FakeNetworkContext::SetTCPConnectCode(
    std::optional<net::Error>& tcp_connect_code) {
  if (tcp_connect_code.has_value()) {
    tcp_connect_code_ = tcp_connect_code.value();
    fake_tcp_connected_socket_ = std::make_unique<FakeTCPConnectedSocket>();
  }
}

void FakeNetworkContext::SetTLSUpgradeCode(
    std::optional<net::Error>& tls_upgrade_code) {
  if (tls_upgrade_code.has_value()) {
    DCHECK(fake_tcp_connected_socket_);

    fake_tcp_connected_socket_->set_tls_upgrade_code(tls_upgrade_code.value());
  }
}

void FakeNetworkContext::SetUdpConnectCode(net::Error udp_connect_code) {
  fake_udp_socket_ = std::make_unique<FakeUdpSocket>();
  fake_udp_socket_->set_udp_connect_code(udp_connect_code);
}

void FakeNetworkContext::SetUdpSendCode(net::Error udp_send_code) {
  DCHECK(fake_udp_socket_);

  fake_udp_socket_->set_udp_send_code(udp_send_code);
}

void FakeNetworkContext::SetDisconnectDuringUdpSendAttempt(bool disconnect) {
  DCHECK(fake_udp_socket_);

  fake_udp_socket_->set_disconnect_during_udp_send_attempt(disconnect);
}

void FakeNetworkContext::SetUdpOnReceivedCode(net::Error udp_on_received_code) {
  DCHECK(fake_udp_socket_);

  fake_udp_socket_->set_udp_on_received_code(udp_on_received_code);
}

void FakeNetworkContext::SetUdpOnReceivedData(
    base::span<const uint8_t> udp_on_received_data) {
  DCHECK(fake_udp_socket_);

  fake_udp_socket_->set_udp_on_received_data(std::move(udp_on_received_data));
}

void FakeNetworkContext::SetDisconnectDuringUdpReceiveAttempt(bool disconnect) {
  DCHECK(fake_udp_socket_);

  fake_udp_socket_->set_disconnect_during_udp_receive_attempt(disconnect);
}

void FakeNetworkContext::SetTaskEnvironmentForTesting(
    content::BrowserTaskEnvironment* task_environment) {
  fake_udp_socket_->set_task_environment_for_testing(task_environment);
}

void FakeNetworkContext::SetUdpConnectionDelay(
    base::TimeDelta connection_delay) {
  fake_udp_socket_->set_udp_connection_delay(connection_delay);
}

void FakeNetworkContext::SetUdpSendDelay(base::TimeDelta send_delay) {
  fake_udp_socket_->set_udp_send_delay(send_delay);
}

void FakeNetworkContext::SetUdpReceiveDelay(base::TimeDelta receive_delay) {
  fake_udp_socket_->set_udp_receive_delay(receive_delay);
}

}  // namespace ash::network_diagnostics