Commit 145cbe82 authored by Kartik Hegde's avatar Kartik Hegde Committed by Commit Bot

network_diagnostics: Make UdpProber class abstract

To facillate testing in classes that use the UdpProber, create an
abstract UdpProber. Tests can derive from this abstract UdpProber class.

BUG=b/172994051
TEST=unit_tests --gtest_filter=UdpProberWithFakeNetworkContextTest.*

Change-Id: Ibdfba9690e996e211f1db85888f66fe15f24c75e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2545047
Commit-Queue: Kartik Hegde <khegde@chromium.org>
Reviewed-by: default avatarSteven Bennetts <stevenjb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#828923}
parent 97e8015a
...@@ -4,24 +4,124 @@ ...@@ -4,24 +4,124 @@
#include "chrome/browser/chromeos/net/network_diagnostics/udp_prober.h" #include "chrome/browser/chromeos/net/network_diagnostics/udp_prober.h"
#include <cstdint>
#include <memory>
#include <utility> #include <utility>
#include "base/callback.h"
#include "base/containers/span.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "chrome/browser/chromeos/net/network_diagnostics/host_resolver.h"
#include "chrome/browser/chromeos/net/network_diagnostics/udp_prober.h"
#include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/profiles/profile_manager.h"
#include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "net/base/address_list.h" #include "net/base/address_list.h"
#include "net/base/host_port_pair.h" #include "net/base/host_port_pair.h"
#include "net/base/ip_endpoint.h"
#include "net/base/net_errors.h" #include "net/base/net_errors.h"
#include "net/dns/public/resolve_error_info.h" #include "net/dns/public/resolve_error_info.h"
#include "net/traffic_annotation/network_traffic_annotation.h" #include "net/traffic_annotation/network_traffic_annotation.h"
#include "services/network/public/mojom/network_context.mojom.h"
#include "services/network/public/mojom/udp_socket.mojom.h"
#include "url/gurl.h"
namespace chromeos { namespace chromeos {
namespace network_diagnostics { namespace network_diagnostics {
UdpProber::UdpProber(NetworkContextGetter network_context_getter, // Implements the UdpProber class.
class UdpProberImpl final : public network::mojom::UDPSocketListener,
public UdpProber {
public:
using ConnectCallback = base::OnceCallback<
void(int result, const base::Optional<net::IPEndPoint>& local_addr_out)>;
using SendCallback = base::OnceCallback<void(int result)>;
// Establishes a UDP connection and sends |data| to |host_port_pair|. The
// traffic sent by the prober is described by |tag|. Since there is no
// guarantee the host specified by |host_port_pair| will respond to a UDP
// request, the prober will timeout with a failure after
// |timeout_after_host_resolution|. As such, the prober will run no longer
// than the time it takes to perform host resolution +
// |timeout_after_host_resolution|. Note that the constructor will not invoke
// |callback|, which is passed into UdpProberImpl during construction. This
// ensures the UdpProberImpl instance is constructed before |callback| is
// invoked. The UdpProberImpl 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.
UdpProberImpl(NetworkContextGetter network_context_getter,
net::HostPortPair host_port_pair,
base::span<const uint8_t> data,
net::NetworkTrafficAnnotationTag tag,
base::TimeDelta timeout_after_host_resolution,
UdpProbeCompleteCallback callback);
UdpProberImpl(const UdpProberImpl&) = delete;
UdpProberImpl& operator=(const UdpProberImpl&) = delete;
~UdpProberImpl() override;
private:
// Processes the results of the DNS resolution done by |host_resolver_|.
void OnHostResolutionComplete(
HostResolver::ResolutionResult& resolution_result);
// On success, the UDP socket is connected to the destination and is ready to
// send data. On failure, the UdpProberImpl exits with a failure.
void OnConnectComplete(int result,
const base::Optional<net::IPEndPoint>& local_addr_out);
// On success, the UDP socket is ready to receive data. So long as the
// received data is not empty, it is considered valid. The content itself is
// not verified.
void OnSendComplete(int result);
// network::mojom::UDPSocketListener:
void OnReceived(int32_t result,
const base::Optional<net::IPEndPoint>& src_ip,
base::Optional<base::span<const uint8_t>> data) override;
// 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);
// Handles disconnects on the UDPSocket remote and UDPSocketListener receiver.
void OnDisconnect();
// Gets the active profile-specific network context.
NetworkContextGetter network_context_getter_;
// Contains the hostname and port.
net::HostPortPair host_port_pair_;
// Data to be sent to the destination.
base::span<const uint8_t> data_;
// Network annotation tag describing the socket traffic.
net::NetworkTrafficAnnotationTag tag_;
// Represents the time after host resolution.
base::TimeDelta timeout_after_host_resolution_;
// Times the prober.
base::OneShotTimer timer_;
// Host resolver used for DNS lookup.
std::unique_ptr<HostResolver> host_resolver_;
// Stores the callback invoked once probe is complete or interrupted.
UdpProbeCompleteCallback callback_;
// Holds the UDPSocket remote.
mojo::Remote<network::mojom::UDPSocket> udp_socket_remote_;
// Listens to the response from hostname specified by |url_|.
mojo::Receiver<network::mojom::UDPSocketListener>
udp_socket_listener_receiver_{this};
// Must be the last member so that any callbacks taking a weak pointer to this
// instance are invalidated first during object destruction.
base::WeakPtrFactory<UdpProberImpl> weak_factory_{this};
};
UdpProberImpl::UdpProberImpl(NetworkContextGetter network_context_getter,
net::HostPortPair host_port_pair, net::HostPortPair host_port_pair,
base::span<const uint8_t> data, base::span<const uint8_t> data,
net::NetworkTrafficAnnotationTag tag, net::NetworkTrafficAnnotationTag tag,
...@@ -44,13 +144,13 @@ UdpProber::UdpProber(NetworkContextGetter network_context_getter, ...@@ -44,13 +144,13 @@ UdpProber::UdpProber(NetworkContextGetter network_context_getter,
host_resolver_ = std::make_unique<HostResolver>( host_resolver_ = std::make_unique<HostResolver>(
host_port_pair_, network_context, host_port_pair_, network_context,
base::BindOnce(&UdpProber::OnHostResolutionComplete, base::BindOnce(&UdpProberImpl::OnHostResolutionComplete,
weak_factory_.GetWeakPtr())); weak_factory_.GetWeakPtr()));
} }
UdpProber::~UdpProber() = default; UdpProberImpl::~UdpProberImpl() = default;
void UdpProber::OnHostResolutionComplete( void UdpProberImpl::OnHostResolutionComplete(
HostResolver::ResolutionResult& resolution_result) { HostResolver::ResolutionResult& resolution_result) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
...@@ -68,26 +168,27 @@ void UdpProber::OnHostResolutionComplete( ...@@ -68,26 +168,27 @@ void UdpProber::OnHostResolutionComplete(
auto pending_receiver = udp_socket_remote_.BindNewPipeAndPassReceiver(); auto pending_receiver = udp_socket_remote_.BindNewPipeAndPassReceiver();
udp_socket_remote_.set_disconnect_handler( udp_socket_remote_.set_disconnect_handler(
base::BindOnce(&UdpProber::OnDisconnect, weak_factory_.GetWeakPtr())); base::BindOnce(&UdpProberImpl::OnDisconnect, weak_factory_.GetWeakPtr()));
DCHECK(udp_socket_remote_.is_bound()); DCHECK(udp_socket_remote_.is_bound());
auto pending_remote = auto pending_remote =
udp_socket_listener_receiver_.BindNewPipeAndPassRemote(); udp_socket_listener_receiver_.BindNewPipeAndPassRemote();
udp_socket_listener_receiver_.set_disconnect_handler( udp_socket_listener_receiver_.set_disconnect_handler(
base::BindOnce(&UdpProber::OnDisconnect, weak_factory_.GetWeakPtr())); base::BindOnce(&UdpProberImpl::OnDisconnect, weak_factory_.GetWeakPtr()));
network_context->CreateUDPSocket(std::move(pending_receiver), network_context->CreateUDPSocket(std::move(pending_receiver),
std::move(pending_remote)); std::move(pending_remote));
timer_.Start(FROM_HERE, timeout_after_host_resolution_, timer_.Start(
base::BindOnce(&UdpProber::OnDone, weak_factory_.GetWeakPtr(), FROM_HERE, timeout_after_host_resolution_,
base::BindOnce(&UdpProberImpl::OnDone, weak_factory_.GetWeakPtr(),
net::ERR_TIMED_OUT, ProbeExitEnum::kTimeout)); net::ERR_TIMED_OUT, ProbeExitEnum::kTimeout));
udp_socket_remote_->Connect( udp_socket_remote_->Connect(
resolution_result.resolved_addresses.value().front(), nullptr, resolution_result.resolved_addresses.value().front(), nullptr,
base::BindOnce(&UdpProber::OnConnectComplete, base::BindOnce(&UdpProberImpl::OnConnectComplete,
weak_factory_.GetWeakPtr())); weak_factory_.GetWeakPtr()));
} }
void UdpProber::OnConnectComplete( void UdpProberImpl::OnConnectComplete(
int result, int result,
const base::Optional<net::IPEndPoint>& local_addr_out) { const base::Optional<net::IPEndPoint>& local_addr_out) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
...@@ -95,12 +196,13 @@ void UdpProber::OnConnectComplete( ...@@ -95,12 +196,13 @@ void UdpProber::OnConnectComplete(
OnDone(result, ProbeExitEnum::kConnectFailure); OnDone(result, ProbeExitEnum::kConnectFailure);
return; return;
} }
udp_socket_remote_->Send( udp_socket_remote_->Send(std::move(data_),
std::move(data_), net::MutableNetworkTrafficAnnotationTag(tag_), net::MutableNetworkTrafficAnnotationTag(tag_),
base::BindOnce(&UdpProber::OnSendComplete, weak_factory_.GetWeakPtr())); base::BindOnce(&UdpProberImpl::OnSendComplete,
weak_factory_.GetWeakPtr()));
} }
void UdpProber::OnSendComplete(int result) { void UdpProberImpl::OnSendComplete(int result) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (result != net::OK) { if (result != net::OK) {
...@@ -110,7 +212,7 @@ void UdpProber::OnSendComplete(int result) { ...@@ -110,7 +212,7 @@ void UdpProber::OnSendComplete(int result) {
udp_socket_remote_->ReceiveMore(/*num_additional_datagrams=*/1); udp_socket_remote_->ReceiveMore(/*num_additional_datagrams=*/1);
} }
void UdpProber::OnReceived(int32_t result, void UdpProberImpl::OnReceived(int32_t result,
const base::Optional<net::IPEndPoint>& src_ip, const base::Optional<net::IPEndPoint>& src_ip,
base::Optional<base::span<const uint8_t>> data) { base::Optional<base::span<const uint8_t>> data) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
...@@ -120,7 +222,7 @@ void UdpProber::OnReceived(int32_t result, ...@@ -120,7 +222,7 @@ void UdpProber::OnReceived(int32_t result,
return; return;
} }
// The UdpProber instance is only interested in validating whether // The UdpProberImpl instance is only interested in validating whether
// data can be received from the destination host. // data can be received from the destination host.
if (!data.has_value() || data.value().empty()) { if (!data.has_value() || data.value().empty()) {
// Note that net::ERR_FAILED is reported even if |result| is net::OK // Note that net::ERR_FAILED is reported even if |result| is net::OK
...@@ -131,7 +233,7 @@ void UdpProber::OnReceived(int32_t result, ...@@ -131,7 +233,7 @@ void UdpProber::OnReceived(int32_t result,
OnDone(net::OK, ProbeExitEnum::kSuccess); OnDone(net::OK, ProbeExitEnum::kSuccess);
} }
void UdpProber::OnDone(int result, ProbeExitEnum probe_exit_enum) { void UdpProberImpl::OnDone(int result, ProbeExitEnum probe_exit_enum) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
// Invalidate pending callbacks. // Invalidate pending callbacks.
...@@ -145,11 +247,24 @@ void UdpProber::OnDone(int result, ProbeExitEnum probe_exit_enum) { ...@@ -145,11 +247,24 @@ void UdpProber::OnDone(int result, ProbeExitEnum probe_exit_enum) {
std::move(callback_).Run(result, probe_exit_enum); std::move(callback_).Run(result, probe_exit_enum);
} }
void UdpProber::OnDisconnect() { void UdpProberImpl::OnDisconnect() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
OnDone(net::ERR_FAILED, ProbeExitEnum::kMojoDisconnectFailure); OnDone(net::ERR_FAILED, ProbeExitEnum::kMojoDisconnectFailure);
} }
// static
std::unique_ptr<UdpProber> UdpProber::Start(
NetworkContextGetter network_context_getter,
net::HostPortPair host_port_pair,
base::span<const uint8_t> data,
net::NetworkTrafficAnnotationTag tag,
base::TimeDelta timeout_after_host_resolution,
UdpProbeCompleteCallback callback) {
return std::make_unique<UdpProberImpl>(
std::move(network_context_getter), host_port_pair, std::move(data), tag,
timeout_after_host_resolution, std::move(callback));
}
} // namespace network_diagnostics } // namespace network_diagnostics
} // namespace chromeos } // namespace chromeos
...@@ -6,23 +6,14 @@ ...@@ -6,23 +6,14 @@
#define CHROME_BROWSER_CHROMEOS_NET_NETWORK_DIAGNOSTICS_UDP_PROBER_H_ #define CHROME_BROWSER_CHROMEOS_NET_NETWORK_DIAGNOSTICS_UDP_PROBER_H_
#include <cstdint> #include <cstdint>
#include <memory>
#include "base/callback.h" #include "base/callback.h"
#include "base/containers/span.h" #include "base/containers/span.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "base/timer/timer.h" #include "net/base/host_port_pair.h"
#include "chrome/browser/chromeos/net/network_diagnostics/host_resolver.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "net/base/address_list.h"
#include "net/base/ip_endpoint.h"
#include "net/dns/public/resolve_error_info.h"
#include "net/traffic_annotation/network_traffic_annotation.h" #include "net/traffic_annotation/network_traffic_annotation.h"
#include "services/network/public/mojom/network_context.mojom.h" #include "services/network/public/mojom/network_context.mojom.h"
#include "services/network/public/mojom/udp_socket.mojom.h"
#include "url/gurl.h"
namespace chromeos { namespace chromeos {
namespace network_diagnostics { namespace network_diagnostics {
...@@ -31,7 +22,7 @@ namespace network_diagnostics { ...@@ -31,7 +22,7 @@ namespace network_diagnostics {
// the prober listens for received data. It confirms that data was received but // the prober listens for received data. It confirms that data was received but
// does not validate the content, hence no data is parsed. Used by network // does not validate the content, hence no data is parsed. Used by network
// diagnostic routines. // diagnostic routines.
class UdpProber : public network::mojom::UDPSocketListener { class UdpProber {
public: public:
// Lists the ways a prober may end. The callback passed into the prober's // Lists the ways a prober may end. The callback passed into the prober's
// constructor is invoked while exiting. // constructor is invoked while exiting.
...@@ -48,86 +39,20 @@ class UdpProber : public network::mojom::UDPSocketListener { ...@@ -48,86 +39,20 @@ class UdpProber : public network::mojom::UDPSocketListener {
using NetworkContextGetter = using NetworkContextGetter =
base::RepeatingCallback<network::mojom::NetworkContext*()>; base::RepeatingCallback<network::mojom::NetworkContext*()>;
using ConnectCallback = base::OnceCallback<
void(int result, const base::Optional<net::IPEndPoint>& local_addr_out)>;
using SendCallback = base::OnceCallback<void(int result)>;
using UdpProbeCompleteCallback = using UdpProbeCompleteCallback =
base::OnceCallback<void(int result, ProbeExitEnum probe_exit_enum)>; base::OnceCallback<void(int result, ProbeExitEnum probe_exit_enum)>;
// Establishes a UDP connection and sends |data| to |host_port_pair|. The virtual ~UdpProber() = default;
// traffic sent by the prober is described by |tag|. Since there is no
// guarantee the host specified by |host_port_pair| will respond to a UDP // Creates a UdpProber instance which resolves |host_port_pair| and starts the
// request, the prober will timeout with a failure after // UDP probe. See implementation for more details.
// |timeout_after_host_resolution|. As such, the prober will run no longer static std::unique_ptr<UdpProber> Start(
// than the time it takes to perform host resolution + NetworkContextGetter network_context_getter,
// |timeout_after_host_resolution|. Note that the constructor will not invoke
// |callback|, which is passed into UdpProber during construction. This
// ensures the UdpProber instance is constructed before |callback| is invoked.
// The UdpProber 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.
UdpProber(NetworkContextGetter network_context_getter,
net::HostPortPair host_port_pair, net::HostPortPair host_port_pair,
base::span<const uint8_t> data, base::span<const uint8_t> data,
net::NetworkTrafficAnnotationTag tag, net::NetworkTrafficAnnotationTag tag,
base::TimeDelta timeout_after_host_resolution, base::TimeDelta timeout_after_host_resolution,
UdpProbeCompleteCallback callback); UdpProbeCompleteCallback callback);
UdpProber(const UdpProber&) = delete;
UdpProber& operator=(const UdpProber&) = delete;
~UdpProber() override;
private:
// Processes the results of the DNS resolution done by |host_resolver_|.
void OnHostResolutionComplete(
HostResolver::ResolutionResult& resolution_result);
// On success, the UDP socket is connected to the destination and is ready to
// send data. On failure, the UdpProber exits with a failure.
void OnConnectComplete(int result,
const base::Optional<net::IPEndPoint>& local_addr_out);
// On success, the UDP socket is ready to receive data. So long as the
// received data is not empty, it is considered valid. The content itself is
// not verified.
void OnSendComplete(int result);
// network::mojom::UDPSocketListener:
void OnReceived(int32_t result,
const base::Optional<net::IPEndPoint>& src_ip,
base::Optional<base::span<const uint8_t>> data) override;
// 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);
// Handles disconnects on the UDPSocket remote and UDPSocketListener receiver.
void OnDisconnect();
// Gets the active profile-specific network context.
NetworkContextGetter network_context_getter_;
// Contains the hostname and port.
net::HostPortPair host_port_pair_;
// Data to be sent to the destination.
base::span<const uint8_t> data_;
// Network annotation tag describing the socket traffic.
net::NetworkTrafficAnnotationTag tag_;
// Represents the time after host resolution.
base::TimeDelta timeout_after_host_resolution_;
// Times the prober.
base::OneShotTimer timer_;
// Host resolver used for DNS lookup.
std::unique_ptr<HostResolver> host_resolver_;
// Stores the callback invoked once probe is complete or interrupted.
UdpProbeCompleteCallback callback_;
// Holds the UDPSocket remote.
mojo::Remote<network::mojom::UDPSocket> udp_socket_remote_;
// Listens to the response from hostname specified by |url_|.
mojo::Receiver<network::mojom::UDPSocketListener>
udp_socket_listener_receiver_{this};
// Must be the last member so that any callbacks taking a weak pointer to this
// instance are invalidated first during object destruction.
base::WeakPtrFactory<UdpProber> weak_factory_{this};
}; };
} // namespace network_diagnostics } // namespace network_diagnostics
......
...@@ -89,7 +89,7 @@ class UdpProberWithFakeNetworkContextTest : public ::testing::Test { ...@@ -89,7 +89,7 @@ class UdpProberWithFakeNetworkContextTest : public ::testing::Test {
void CreateAndExecuteUdpProber(base::span<const uint8_t> data, void CreateAndExecuteUdpProber(base::span<const uint8_t> data,
UdpProber::UdpProbeCompleteCallback callback) { UdpProber::UdpProbeCompleteCallback callback) {
ASSERT_TRUE(fake_network_context_); ASSERT_TRUE(fake_network_context_);
udp_prober_ = std::make_unique<UdpProber>( udp_prober_ = UdpProber::Start(
base::BindRepeating( base::BindRepeating(
[](network::mojom::NetworkContext* network_context) { [](network::mojom::NetworkContext* network_context) {
return network_context; return network_context;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment