From: Pieter Lexis Date: Wed, 7 Jan 2026 10:17:59 +0000 (+0100) Subject: chore(SVCB): Add comparison operators X-Git-Tag: rec-5.4.0-beta1~7^2~4 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9f5e17d9e0fc4fea9a0e7a1949d181a0c7016624;p=thirdparty%2Fpdns.git chore(SVCB): Add comparison operators --- diff --git a/pdns/svc-records.cc b/pdns/svc-records.cc index 12819860f7..d2127bca34 100644 --- a/pdns/svc-records.cc +++ b/pdns/svc-records.cc @@ -153,6 +153,38 @@ bool SvcParam::operator<(const SvcParam& other) const { return this->d_key < other.getKey(); } +bool SvcParam::operator==(const SvcParam& other) const { + if (this->getKey() != other.getKey()) { + return false; + } + switch (this->d_key) { + case SvcParamKey::mandatory: + return this->getMandatory() == other.getMandatory(); + case SvcParamKey::alpn: + return this->getALPN() == other.getALPN(); + case SvcParamKey::no_default_alpn: /* fallthrough */ + case SvcParamKey::ohttp: + return true; + case SvcParamKey::port: + return this->getPort() == other.getPort(); + case SvcParamKey::ipv4hint: /* fallthrough */ + case SvcParamKey::ipv6hint: + return (this->getIPHints() == other.getIPHints() && this->getAutoHint() == other.getAutoHint()); + case SvcParamKey::ech: + return this->getECH() == other.getECH(); + case SvcParamKey::dohpath: + return this->getValue() == other.getValue(); + case SvcParamKey::tls_supported_groups: + return this->getTLSSupportedGroups() == other.getTLSSupportedGroups(); + default: + return this->getValue() == other.getValue(); + } +} + +bool SvcParam::operator!=(const SvcParam& other) const { + return !(*this == other); +} + const std::vector& SvcParam::getIPHints() const { if (d_key != SvcParamKey::ipv6hint && d_key != SvcParamKey::ipv4hint) { throw std::invalid_argument("getIPHints called for non-IP address key '" + keyToString(d_key) + "'"); diff --git a/pdns/svc-records.hh b/pdns/svc-records.hh index a46547ccfa..15ea26e55d 100644 --- a/pdns/svc-records.hh +++ b/pdns/svc-records.hh @@ -82,6 +82,10 @@ class SvcParam { bool operator< (const SvcParam &other) const; + bool operator==(const SvcParam &other) const; + + bool operator!=(const SvcParam &other) const; + bool operator==(const SvcParamKey& key) const { return key == d_key; diff --git a/pdns/test-svc_records_cc.cc b/pdns/test-svc_records_cc.cc index a7440f1a4a..815b658110 100644 --- a/pdns/test-svc_records_cc.cc +++ b/pdns/test-svc_records_cc.cc @@ -8,9 +8,9 @@ #include "config.h" #endif #include -#include #include "svc-records.hh" #include "base64.hh" +#include "iputils.hh" using namespace boost; @@ -285,4 +285,147 @@ BOOST_AUTO_TEST_CASE(test_SvcParam_ctor_vector_uint16_value) { BOOST_CHECK_THROW(param.getValue(), std::invalid_argument); } +BOOST_AUTO_TEST_CASE(test_SvcParam_comparison) { + // Test the SvcParam::operator== and operator!= behaviour + + { + std::set set1{SvcParam::ech}; + std::set same_as_set1 = set1; + std::set set2{SvcParam::alpn}; + + SvcParam mandatory(SvcParam::SvcParamKey::mandatory, std::move(set1)); + SvcParam mandatory2(SvcParam::SvcParamKey::mandatory, std::move(same_as_set1)); + SvcParam mandatory3(SvcParam::SvcParamKey::mandatory, std::move(set2)); + + BOOST_CHECK(mandatory == mandatory2); + BOOST_CHECK(mandatory != mandatory3); + BOOST_CHECK(mandatory2 != mandatory3); + } + + { + std::vector first{"h2", "h3"}; + std::vector same_as_first = first; + std::vector different{"h3", "h2"}; + + SvcParam alpn(SvcParam::SvcParamKey::alpn, std::move(first)); + SvcParam alpn2(SvcParam::SvcParamKey::alpn, std::move(same_as_first)); + SvcParam alpn3(SvcParam::SvcParamKey::alpn, std::move(different)); + + BOOST_CHECK(alpn == alpn2); + BOOST_CHECK(alpn != alpn3); + BOOST_CHECK(alpn2 != alpn3); + } + + { + // ohttps uses the same logic + SvcParam nda(SvcParam::SvcParamKey::no_default_alpn); + SvcParam nda2(SvcParam::SvcParamKey::no_default_alpn); + + BOOST_CHECK(nda == nda2); + } + + { + uint16_t port = 1337; + uint16_t other_port = 1338; + SvcParam param1(SvcParam::SvcParamKey::port, port); + SvcParam param2(SvcParam::SvcParamKey::port, port); + SvcParam param3(SvcParam::SvcParamKey::port, other_port); + + BOOST_CHECK(param1 == param1); + BOOST_CHECK(param1 != param3); + BOOST_CHECK(param2 != param3); + } + + { + // Uses the same logic as ipv6hint + ComboAddress ca1{"192.0.2.1"}; + ComboAddress ca2{"192.0.2.2"}; + ComboAddress ca3{"192.0.2.3"}; + + std::vector first{ca1}; + auto same_as_first = first; + + std::vector different_order{ca1, ca2}; + std::vector different_order2{ca2, ca1}; + + std::vector all{ca1, ca2, ca3}; + + SvcParam param1(SvcParam::SvcParamKey::ipv4hint, std::move(first)); + SvcParam param2(SvcParam::SvcParamKey::ipv4hint, std::move(same_as_first)); + + SvcParam param3(SvcParam::SvcParamKey::ipv4hint, std::move(different_order)); + SvcParam param4(SvcParam::SvcParamKey::ipv4hint, std::move(different_order2)); + + SvcParam param5(SvcParam::SvcParamKey::ipv4hint, std::move(all)); + + BOOST_CHECK(param1 == param2); + + BOOST_CHECK(param2 != param3); + BOOST_CHECK(param2 != param4); + BOOST_CHECK(param2 != param5); + + BOOST_CHECK(param3 != param4); + BOOST_CHECK(param3 != param5); + + BOOST_CHECK(param4 != param5); + } + + { + std::string first{"somefakeechvalue"}; + std::string same_as_first = first; + std::string different{"someotherfakeechvalue"}; + + SvcParam ech(SvcParam::SvcParamKey::ech, std::move(first)); + SvcParam ech2(SvcParam::SvcParamKey::ech, std::move(same_as_first)); + SvcParam ech3(SvcParam::SvcParamKey::ech, std::move(different)); + + BOOST_CHECK(ech == ech2); + BOOST_CHECK(ech != ech3); + BOOST_CHECK(ech2 != ech3); + } + + { + std::string first{"/foo"}; + std::string same_as_first = first; + std::string different{"/bar"}; + + SvcParam dohpath(SvcParam::SvcParamKey::dohpath, std::move(first)); + SvcParam dohpath2(SvcParam::SvcParamKey::dohpath, std::move(same_as_first)); + SvcParam dohpath3(SvcParam::SvcParamKey::dohpath, std::move(different)); + + BOOST_CHECK(dohpath == dohpath2); + BOOST_CHECK(dohpath != dohpath3); + BOOST_CHECK(dohpath2 != dohpath3); + } + + { + std::vector first{0, 1, 2}; + std::vector same_as_first = first; + std::vector different{2, 3}; + + SvcParam tls_supported_groups(SvcParam::SvcParamKey::tls_supported_groups, std::move(first)); + SvcParam tls_supported_groups2(SvcParam::SvcParamKey::tls_supported_groups, std::move(same_as_first)); + SvcParam tls_supported_groups3(SvcParam::SvcParamKey::tls_supported_groups, std::move(different)); + + BOOST_CHECK(tls_supported_groups == tls_supported_groups2); + BOOST_CHECK(tls_supported_groups != tls_supported_groups3); + BOOST_CHECK(tls_supported_groups2 != tls_supported_groups3); + } + + { + std::string first{"somegenericvalue"}; + std::string same_as_first = first; + std::string different{"anothergenericvalue"}; + auto key = "key6666"; + + SvcParam generic(SvcParam::keyFromString(key), std::move(first)); + SvcParam generic2(SvcParam::keyFromString(key), std::move(same_as_first)); + SvcParam generic3(SvcParam::keyFromString(key), std::move(different)); + + BOOST_CHECK(generic == generic2); + BOOST_CHECK(generic != generic3); + BOOST_CHECK(generic2 != generic3); + } +} + BOOST_AUTO_TEST_SUITE_END()