blob: 7a15b3c7e7f055229cd5491d9a4a7ce04004550e [file] [log] [blame]
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/connectivity/network/mdns/service/agents/service_instance_resolver.h"
#include <lib/zx/time.h>
#include <gtest/gtest.h>
#include "src/connectivity/network/mdns/service/common/mdns_names.h"
#include "src/connectivity/network/mdns/service/common/service_instance.h"
#include "src/connectivity/network/mdns/service/common/type_converters.h"
#include "src/connectivity/network/mdns/service/test/agent_test.h"
namespace fuchsia::net {
bool operator==(const fuchsia::net::SocketAddress& lhs, const fuchsia::net::SocketAddress& rhs) {
if (lhs.Which() != rhs.Which()) {
return false;
}
if (lhs.is_ipv4()) {
return lhs.ipv4().address.addr == rhs.ipv4().address.addr && lhs.ipv4().port == rhs.ipv4().port;
} else {
return lhs.ipv6().address.addr == rhs.ipv6().address.addr &&
lhs.ipv6().port == rhs.ipv6().port && lhs.ipv6().zone_index == rhs.ipv6().zone_index;
}
}
} // namespace fuchsia::net
namespace mdns {
namespace test {
class InstanceResolverTest : public AgentTest {
public:
InstanceResolverTest() = default;
protected:
void ReceivePublication(ServiceInstanceResolver& under_test, const std::string& host_full_name,
const std::string& service_name, const std::string& instance_name,
inet::IpPort port, const std::vector<std::vector<uint8_t>>& text,
ReplyAddress sender_address) {
auto service_full_name = MdnsNames::ServiceFullName(service_name);
auto instance_full_name = MdnsNames::InstanceFullName(instance_name, service_name);
DnsResource ptr_resource(service_full_name, DnsType::kPtr);
ptr_resource.ptr_.pointer_domain_name_ = DnsName(instance_full_name);
under_test.ReceiveResource(ptr_resource, MdnsResourceSection::kAnswer, sender_address);
DnsResource srv_resource(instance_full_name, DnsType::kSrv);
srv_resource.srv_.port_ = port;
srv_resource.srv_.target_ = DnsName(host_full_name);
under_test.ReceiveResource(srv_resource, MdnsResourceSection::kAnswer, sender_address);
DnsResource txt_resource(instance_full_name, DnsType::kTxt);
txt_resource.txt_.strings_ = text;
under_test.ReceiveResource(txt_resource, MdnsResourceSection::kAnswer, sender_address);
DnsResource a_resource(host_full_name, sender_address.socket_address().address());
under_test.ReceiveResource(a_resource, MdnsResourceSection::kAnswer, sender_address);
under_test.EndOfMessage();
}
};
constexpr char kHostName[] = "test2host";
constexpr char kServiceName[] = "_testservice._tcp.";
constexpr char kInstanceName[] = "testinstance";
constexpr char kInstanceFullName[] = "testinstance._testservice._tcp.local.";
const inet::IpPort kPort = inet::IpPort::From_uint16_t(1234);
const std::vector<std::vector<uint8_t>> kText = fidl::To<std::vector<std::vector<uint8_t>>>(
std::vector<std::string>{"color=red", "shape=round"});
constexpr bool kIncludeLocal = true;
constexpr bool kExcludeLocal = false;
constexpr bool kIncludeLocalProxies = true;
constexpr bool kExcludeLocalProxies = false;
constexpr bool kFromLocalProxyHost = true;
constexpr bool kFromLocalHost = false;
const std::vector<HostAddress> kHostAddresses{
HostAddress(inet::IpAddress(192, 168, 1, 200), 1, zx::sec(450)),
HostAddress(inet::IpAddress(0xfe80, 200), 1, zx::sec(450))};
const std::vector<inet::SocketAddress> kSocketAddresses{
inet::SocketAddress(inet::IpAddress(192, 168, 1, 200), kPort, 1),
inet::SocketAddress(inet::IpAddress(0xfe80, 200), kPort, 1)};
// Tests the behavior of the resolver when configured to discover services on the local host.
TEST_F(InstanceResolverTest, LocalInstance) {
fuchsia::net::mdns::ServiceInstance instance_from_callback;
bool callback_called = false;
ServiceInstanceResolver under_test(
this, kServiceName, kInstanceName, now(), Media::kBoth, IpVersions::kBoth, kIncludeLocal,
kExcludeLocalProxies,
[&instance_from_callback, &callback_called](fuchsia::net::mdns::ServiceInstance instance) {
instance_from_callback = std::move(instance);
callback_called = true;
});
SetAgent(under_test);
SetLocalHostAddresses(kHostAddresses);
under_test.Start(kLocalHostFullName);
// Expect a PTR question on start.
auto message = ExpectOutboundMessage(ReplyAddress::Multicast(Media::kBoth, IpVersions::kBoth));
ExpectQuestion(message.get(), kInstanceFullName, DnsType::kSrv);
ExpectNoOtherQuestionOrResource(message.get());
ExpectPostTaskForTime(zx::sec(0), zx::sec(0));
ExpectNoOther();
under_test.OnAddLocalServiceInstance(
ServiceInstance(kServiceName, kInstanceName, kLocalHostName, kSocketAddresses, kText),
kFromLocalHost);
EXPECT_TRUE(callback_called);
EXPECT_EQ(kServiceName, instance_from_callback.service());
EXPECT_EQ(kInstanceName, instance_from_callback.instance());
EXPECT_EQ(kLocalHostName, instance_from_callback.target());
EXPECT_EQ(0, instance_from_callback.srv_priority());
EXPECT_EQ(0, instance_from_callback.srv_weight());
EXPECT_EQ(fidl::To<std::vector<fuchsia::net::SocketAddress>>(kSocketAddresses),
instance_from_callback.addresses());
EXPECT_EQ(kText, instance_from_callback.text_strings());
}
// Tests the behavior of the resolver when configured to discover services on a local proxy host.
TEST_F(InstanceResolverTest, LocalProxyInstance) {
fuchsia::net::mdns::ServiceInstance instance_from_callback;
bool callback_called = false;
ServiceInstanceResolver under_test(
this, kServiceName, kInstanceName, now(), Media::kBoth, IpVersions::kBoth, kExcludeLocal,
kIncludeLocalProxies,
[&instance_from_callback, &callback_called](fuchsia::net::mdns::ServiceInstance instance) {
instance_from_callback = std::move(instance);
callback_called = true;
});
SetAgent(under_test);
under_test.Start(kLocalHostFullName);
// Expect a PTR question on start.
auto message = ExpectOutboundMessage(ReplyAddress::Multicast(Media::kBoth, IpVersions::kBoth));
ExpectQuestion(message.get(), kInstanceFullName, DnsType::kSrv);
ExpectNoOtherQuestionOrResource(message.get());
ExpectPostTaskForTime(zx::sec(0), zx::sec(0));
ExpectNoOther();
under_test.OnAddLocalServiceInstance(
ServiceInstance(kServiceName, kInstanceName, kHostName, kSocketAddresses, kText),
kFromLocalProxyHost);
EXPECT_TRUE(callback_called);
EXPECT_EQ(kServiceName, instance_from_callback.service());
EXPECT_EQ(kInstanceName, instance_from_callback.instance());
EXPECT_EQ(kHostName, instance_from_callback.target());
EXPECT_EQ(0, instance_from_callback.srv_priority());
EXPECT_EQ(0, instance_from_callback.srv_weight());
EXPECT_EQ(fidl::To<std::vector<fuchsia::net::SocketAddress>>(kSocketAddresses),
instance_from_callback.addresses());
EXPECT_EQ(kText, instance_from_callback.text_strings());
}
} // namespace test
} // namespace mdns