From b5210fb87c3aef62481d9d915d7ce871338f934a Mon Sep 17 00:00:00 2001 From: Eduardo Gonzalez Date: Tue, 3 Nov 2026 14:48:19 +0100 Subject: [PATCH 1/5] gservice.hpp: Expose method to get Nameservers.Configuration Expose method for getting Nameservers.Configuration property in the service. Implement part of #50. Signed-off-by: Eduardo Gonzalez --- include/amarula/dbus/connman/gservice.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/amarula/dbus/connman/gservice.hpp b/include/amarula/dbus/connman/gservice.hpp index 1a50a15..6b3faea 100644 --- a/include/amarula/dbus/connman/gservice.hpp +++ b/include/amarula/dbus/connman/gservice.hpp @@ -232,6 +232,9 @@ struct ServProperties { [[nodiscard]] auto getProxy() const { return proxy_; } [[nodiscard]] auto getName() const { return name_; } [[nodiscard]] auto getNameservers() const { return name_servers_; } + [[nodiscard]] auto getNameserversConfiguration() const { + return name_servers_conf_; + } [[nodiscard]] auto getDomains() const { return domains_; } [[nodiscard]] auto getTimeservers() const { return time_servers_; } From 6da6348411d2935ca4a03ea5d5286cd752344e65 Mon Sep 17 00:00:00 2001 From: Eduardo Gonzalez Date: Tue, 3 Nov 2026 14:51:34 +0100 Subject: [PATCH 2/5] connman_service: Parse and expose Timeservers.Configuration Add the setters and getters for the Timeservers.Configuration properties. Implement part of #50. Signed-off-by: Eduardo Gonzalez --- include/amarula/dbus/connman/gservice.hpp | 6 +++ src/dbus/gconnman_private.hpp | 1 + src/dbus/gconnman_service.cpp | 21 ++++++++ tests/gconnman_serv_test.cpp | 60 +++++++++++++++++++++++ 4 files changed, 88 insertions(+) diff --git a/include/amarula/dbus/connman/gservice.hpp b/include/amarula/dbus/connman/gservice.hpp index 6b3faea..6d44fdf 100644 --- a/include/amarula/dbus/connman/gservice.hpp +++ b/include/amarula/dbus/connman/gservice.hpp @@ -237,6 +237,9 @@ struct ServProperties { } [[nodiscard]] auto getDomains() const { return domains_; } [[nodiscard]] auto getTimeservers() const { return time_servers_; } + [[nodiscard]] auto getTimeserversConfiguration() const { + return time_servers_conf_; + } private: State state_{}; @@ -248,6 +251,7 @@ struct ServProperties { std::optional> name_servers_conf_; std::optional> domains_; std::optional> time_servers_; + std::optional> time_servers_conf_; bool autoconnect_{false}; bool mdns_{false}; bool favorite_{false}; @@ -282,6 +286,8 @@ class Service : public DBusProxy { PropertiesSetCallback callback = nullptr); void setNameServers(const std::vector& name_servers, PropertiesSetCallback callback = nullptr); + void setTimeServers(const std::vector& time_servers, + PropertiesSetCallback callback = nullptr); void setIPv4(const IPv4& ipv4_configuration, PropertiesSetCallback callback = nullptr); void setIPv6(const IPv6& ipv6_configuration, diff --git a/src/dbus/gconnman_private.hpp b/src/dbus/gconnman_private.hpp index 015ea06..b2dfe49 100644 --- a/src/dbus/gconnman_private.hpp +++ b/src/dbus/gconnman_private.hpp @@ -62,6 +62,7 @@ constexpr auto REMOVE_STR = "Remove"; constexpr auto INTERFACE_STR = "Interface"; constexpr auto MTU_STR = "MTU"; constexpr auto NAMESERVERS_CONFIGURATION_STR = "Nameservers.Configuration"; +constexpr auto TIMESERVERS_CONFIGURATION_STR = "Timeservers.Configuration"; constexpr auto IPV4_CONFIGURATION_STR = "IPv4.Configuration"; constexpr auto IPV6_CONFIGURATION_STR = "IPv6.Configuration"; diff --git a/src/dbus/gconnman_service.cpp b/src/dbus/gconnman_service.cpp index f1efc4c..120c252 100644 --- a/src/dbus/gconnman_service.cpp +++ b/src/dbus/gconnman_service.cpp @@ -121,6 +121,14 @@ void Service::setNameServers(const std::vector& name_servers, &Service::finishAsyncCall, data.release()); } +void Service::setTimeServers(const std::vector& time_servers, + PropertiesSetCallback callback) { + auto data = prepareCallback(std::move(callback)); + auto variant = vector_to_as(time_servers); + setProperty(TIMESERVERS_CONFIGURATION_STR, variant.get(), nullptr, + &Service::finishAsyncCall, data.release()); +} + IPv4::IPv4(const IPv4::Method method, std::string address, std::string netmask, std::string gateway) : method_(method), @@ -372,6 +380,11 @@ void ServProperties::update(const gchar* key, GVariant* value) { (g_variant_n_children(value) != 0) ? std::optional>(as_to_vector(value)) : std::nullopt; + } else if (g_strcmp0(key, TIMESERVERS_CONFIGURATION_STR) == 0U) { + time_servers_conf_ = + (g_variant_n_children(value) != 0) + ? std::optional>(as_to_vector(value)) + : std::nullopt; } else { LCM_LOG("Unknown or empty property for Service: " << key << '\n'); } @@ -432,6 +445,14 @@ auto operator<<(std::ostream& ost, const ServProperties& obj) -> std::ostream& { ost << '\n'; } + if (obj.time_servers_conf_) { + ost << "TimeServers.Configuration: "; + for (const auto& tserver : obj.time_servers_conf_.value()) { + ost << tserver << ' '; + } + ost << '\n'; + } + if (obj.ipv4_) { ost << obj.ipv4_.value(); } diff --git a/tests/gconnman_serv_test.cpp b/tests/gconnman_serv_test.cpp index f76e27f..6ec04c1 100644 --- a/tests/gconnman_serv_test.cpp +++ b/tests/gconnman_serv_test.cpp @@ -126,6 +126,66 @@ TEST(Connman, setNameServers) { ASSERT_TRUE(called) << "ServicesChanged callback was never called"; } +TEST(Connman, setTimeServers) { + bool called = false; + { + const ThreadBundle thread_bundle; + const Connman connman; + const auto manager = connman.manager(); + + auto do_on_servs = [&called, main_tid = thread_bundle.main_tid, + loop_tid = thread_bundle.loop_tid]( + const auto& services, + const bool check_thread_id = true) { + if (!called) { + called = true; + if (check_thread_id) { + const auto callback_tid = std::this_thread::get_id(); + EXPECT_NE(callback_tid, main_tid); + EXPECT_NE(callback_tid, loop_tid); + } + ASSERT_FALSE(services.empty()); + for (const auto& serv : services) { + const auto props = serv->properties(); + const auto name = props.getName(); + std::cout << props; + serv->onPropertyChanged([](const auto& properties) { + std::cout << "onPropertyChange:\n"; + std::cout << properties; + }); + serv->setTimeServers( + {"pool.ntp.org", "time.google.com"}, + [serv, name, main_tid, loop_tid](auto success) { + const auto callback_tid = + std::this_thread::get_id(); + EXPECT_NE(callback_tid, main_tid); + EXPECT_NE(callback_tid, loop_tid); + EXPECT_TRUE(success) << "Set setTimeServers for " + << name << " did not succeed"; + serv->setTimeServers( + {}, [name, main_tid, loop_tid](auto success) { + const auto callback_tid = + std::this_thread::get_id(); + EXPECT_NE(callback_tid, main_tid); + EXPECT_NE(callback_tid, loop_tid); + EXPECT_TRUE(success) + << "Reset setTimeServers for " << name + << " did not succeed"; + }); + }); + } + } + }; + + if (manager->services().empty()) { + manager->onServicesChanged(do_on_servs); + } else { + do_on_servs(manager->services(), false); + } + } + ASSERT_TRUE(called) << "ServicesChanged callback was never called"; +} + TEST(Connman, setIPv4Configuration) { bool called = false; { From 3359467989ba33ab957bc6d8ac6dd753e5a487ab Mon Sep 17 00:00:00 2001 From: Eduardo Gonzalez Date: Tue, 3 Nov 2026 15:00:25 +0100 Subject: [PATCH 3/5] connman_service: Parse and expose Domains.Configuration Add the setters and getters for the Domains.Configuration properties. Implement part of #50. Signed-off-by: Eduardo Gonzalez --- include/amarula/dbus/connman/gservice.hpp | 6 +++ src/dbus/gconnman_private.hpp | 1 + src/dbus/gconnman_service.cpp | 21 ++++++++ tests/gconnman_serv_test.cpp | 60 +++++++++++++++++++++++ 4 files changed, 88 insertions(+) diff --git a/include/amarula/dbus/connman/gservice.hpp b/include/amarula/dbus/connman/gservice.hpp index 6d44fdf..2a5b576 100644 --- a/include/amarula/dbus/connman/gservice.hpp +++ b/include/amarula/dbus/connman/gservice.hpp @@ -236,6 +236,9 @@ struct ServProperties { return name_servers_conf_; } [[nodiscard]] auto getDomains() const { return domains_; } + [[nodiscard]] auto getDomainsConfiguration() const { + return domains_conf_; + } [[nodiscard]] auto getTimeservers() const { return time_servers_; } [[nodiscard]] auto getTimeserversConfiguration() const { return time_servers_conf_; @@ -250,6 +253,7 @@ struct ServProperties { std::optional> name_servers_; std::optional> name_servers_conf_; std::optional> domains_; + std::optional> domains_conf_; std::optional> time_servers_; std::optional> time_servers_conf_; bool autoconnect_{false}; @@ -288,6 +292,8 @@ class Service : public DBusProxy { PropertiesSetCallback callback = nullptr); void setTimeServers(const std::vector& time_servers, PropertiesSetCallback callback = nullptr); + void setDomains(const std::vector& domains, + PropertiesSetCallback callback = nullptr); void setIPv4(const IPv4& ipv4_configuration, PropertiesSetCallback callback = nullptr); void setIPv6(const IPv6& ipv6_configuration, diff --git a/src/dbus/gconnman_private.hpp b/src/dbus/gconnman_private.hpp index b2dfe49..7a090af 100644 --- a/src/dbus/gconnman_private.hpp +++ b/src/dbus/gconnman_private.hpp @@ -63,6 +63,7 @@ constexpr auto INTERFACE_STR = "Interface"; constexpr auto MTU_STR = "MTU"; constexpr auto NAMESERVERS_CONFIGURATION_STR = "Nameservers.Configuration"; constexpr auto TIMESERVERS_CONFIGURATION_STR = "Timeservers.Configuration"; +constexpr auto DOMAINS_CONFIGURATION_STR = "Domains.Configuration"; constexpr auto IPV4_CONFIGURATION_STR = "IPv4.Configuration"; constexpr auto IPV6_CONFIGURATION_STR = "IPv6.Configuration"; diff --git a/src/dbus/gconnman_service.cpp b/src/dbus/gconnman_service.cpp index 120c252..e0772ef 100644 --- a/src/dbus/gconnman_service.cpp +++ b/src/dbus/gconnman_service.cpp @@ -129,6 +129,14 @@ void Service::setTimeServers(const std::vector& time_servers, &Service::finishAsyncCall, data.release()); } +void Service::setDomains(const std::vector& domains, + PropertiesSetCallback callback) { + auto data = prepareCallback(std::move(callback)); + auto variant = vector_to_as(domains); + setProperty(DOMAINS_CONFIGURATION_STR, variant.get(), nullptr, + &Service::finishAsyncCall, data.release()); +} + IPv4::IPv4(const IPv4::Method method, std::string address, std::string netmask, std::string gateway) : method_(method), @@ -375,6 +383,11 @@ void ServProperties::update(const gchar* key, GVariant* value) { (g_variant_n_children(value) != 0) ? std::optional>(as_to_vector(value)) : std::nullopt; + } else if (g_strcmp0(key, DOMAINS_CONFIGURATION_STR) == 0U) { + domains_conf_ = + (g_variant_n_children(value) != 0) + ? std::optional>(as_to_vector(value)) + : std::nullopt; } else if (g_strcmp0(key, TIMESERVERS_STR) == 0U) { time_servers_ = (g_variant_n_children(value) != 0) @@ -437,6 +450,14 @@ auto operator<<(std::ostream& ost, const ServProperties& obj) -> std::ostream& { ost << '\n'; } + if (obj.domains_conf_) { + ost << "Domains.Configuration: "; + for (const auto& domain : obj.domains_conf_.value()) { + ost << domain << ' '; + } + ost << '\n'; + } + if (obj.time_servers_) { ost << "TimeServers: "; for (const auto& tserver : obj.time_servers_.value()) { diff --git a/tests/gconnman_serv_test.cpp b/tests/gconnman_serv_test.cpp index 6ec04c1..23c83a1 100644 --- a/tests/gconnman_serv_test.cpp +++ b/tests/gconnman_serv_test.cpp @@ -186,6 +186,66 @@ TEST(Connman, setTimeServers) { ASSERT_TRUE(called) << "ServicesChanged callback was never called"; } +TEST(Connman, setDomains) { + bool called = false; + { + const ThreadBundle thread_bundle; + const Connman connman; + const auto manager = connman.manager(); + + auto do_on_servs = [&called, main_tid = thread_bundle.main_tid, + loop_tid = thread_bundle.loop_tid]( + const auto& services, + const bool check_thread_id = true) { + if (!called) { + called = true; + if (check_thread_id) { + const auto callback_tid = std::this_thread::get_id(); + EXPECT_NE(callback_tid, main_tid); + EXPECT_NE(callback_tid, loop_tid); + } + ASSERT_FALSE(services.empty()); + for (const auto& serv : services) { + const auto props = serv->properties(); + const auto name = props.getName(); + std::cout << props; + serv->onPropertyChanged([](const auto& properties) { + std::cout << "onPropertyChange:\n"; + std::cout << properties; + }); + serv->setDomains( + {"example.com", "example.org"}, + [serv, name, main_tid, loop_tid](auto success) { + const auto callback_tid = + std::this_thread::get_id(); + EXPECT_NE(callback_tid, main_tid); + EXPECT_NE(callback_tid, loop_tid); + EXPECT_TRUE(success) << "Set setDomains for " + << name << " did not succeed"; + serv->setDomains( + {}, [name, main_tid, loop_tid](auto success) { + const auto callback_tid = + std::this_thread::get_id(); + EXPECT_NE(callback_tid, main_tid); + EXPECT_NE(callback_tid, loop_tid); + EXPECT_TRUE(success) + << "Reset setDomains for " << name + << " did not succeed"; + }); + }); + } + } + }; + + if (manager->services().empty()) { + manager->onServicesChanged(do_on_servs); + } else { + do_on_servs(manager->services(), false); + } + } + ASSERT_TRUE(called) << "ServicesChanged callback was never called"; +} + TEST(Connman, setIPv4Configuration) { bool called = false; { From 28aa12d8c60d9f18a389e6ef89935996ca00f0ac Mon Sep 17 00:00:00 2001 From: Eduardo Gonzalez Date: Tue, 3 Nov 2026 15:10:57 +0100 Subject: [PATCH 4/5] connman_service: Parse and expose Proxy.Configuration Add the setters and getters for the Proxy.Configuration. Implement part of #50. Signed-off-by: Eduardo Gonzalez --- include/amarula/dbus/connman/gservice.hpp | 13 +++++ src/dbus/gconnman_private.hpp | 3 +- src/dbus/gconnman_service.cpp | 48 +++++++++++++++++ tests/gconnman_serv_test.cpp | 64 +++++++++++++++++++++++ 4 files changed, 127 insertions(+), 1 deletion(-) diff --git a/include/amarula/dbus/connman/gservice.hpp b/include/amarula/dbus/connman/gservice.hpp index 2a5b576..6f0abbf 100644 --- a/include/amarula/dbus/connman/gservice.hpp +++ b/include/amarula/dbus/connman/gservice.hpp @@ -146,6 +146,11 @@ struct Provider : public GVariantParser { struct Proxy : public GVariantParser { public: enum class Method : uint8_t { Direct = 0, Auto, Manual }; + + explicit Proxy(Proxy::Method method, std::string url = "", + std::vector servers = {}, + std::vector excludes = {}); + friend auto operator<<(std::ostream& ostr, const Proxy& object) -> std::ostream&; [[nodiscard]] auto getMethod() const { return method_; } @@ -160,8 +165,10 @@ struct Proxy : public GVariantParser { std::vector excludes_; explicit Proxy(GVariant* variant) { parse(variant); }; void update(const gchar* key, GVariant* value) override; + [[nodiscard]] auto getVariant() const -> VariantPtr override; friend class ServProperties; + friend class Service; }; struct ServProperties { @@ -230,6 +237,9 @@ struct ServProperties { [[nodiscard]] auto getEthernet() const { return ethernet_; } [[nodiscard]] auto getProvider() const { return provider_; } [[nodiscard]] auto getProxy() const { return proxy_; } + [[nodiscard]] auto getProxyConfiguration() const { + return proxy_configuration_; + } [[nodiscard]] auto getName() const { return name_; } [[nodiscard]] auto getNameservers() const { return name_servers_; } [[nodiscard]] auto getNameserversConfiguration() const { @@ -269,6 +279,7 @@ struct ServProperties { std::optional ethernet_{std::nullopt}; std::optional provider_{std::nullopt}; std::optional proxy_{std::nullopt}; + std::optional proxy_configuration_{std::nullopt}; void update(const gchar* key, GVariant* value); @@ -298,6 +309,8 @@ class Service : public DBusProxy { PropertiesSetCallback callback = nullptr); void setIPv6(const IPv6& ipv6_configuration, PropertiesSetCallback callback = nullptr); + void setProxy(const Proxy& proxy_configuration, + PropertiesSetCallback callback = nullptr); friend class Manager; }; diff --git a/src/dbus/gconnman_private.hpp b/src/dbus/gconnman_private.hpp index 7a090af..c59b983 100644 --- a/src/dbus/gconnman_private.hpp +++ b/src/dbus/gconnman_private.hpp @@ -52,7 +52,7 @@ constexpr auto PROVIDER_STR = "Provider"; constexpr auto HOST_STR = "Host"; constexpr auto DOMAIN_STR = "Domain"; constexpr auto PROXY_STR = "Proxy"; -constexpr auto URL_STR = "Url"; +constexpr auto URL_STR = "URL"; constexpr auto SERVERS_STR = "Servers"; constexpr auto EXCLUDES_STR = "Excludes"; constexpr auto SECURITY_STR = "Security"; @@ -66,6 +66,7 @@ constexpr auto TIMESERVERS_CONFIGURATION_STR = "Timeservers.Configuration"; constexpr auto DOMAINS_CONFIGURATION_STR = "Domains.Configuration"; constexpr auto IPV4_CONFIGURATION_STR = "IPv4.Configuration"; constexpr auto IPV6_CONFIGURATION_STR = "IPv6.Configuration"; +constexpr auto PROXY_CONFIGURATION_STR = "Proxy.Configuration"; // Manager interface constexpr auto MANAGER_INTERFACE = "net.connman.Manager"; diff --git a/src/dbus/gconnman_service.cpp b/src/dbus/gconnman_service.cpp index e0772ef..9331266 100644 --- a/src/dbus/gconnman_service.cpp +++ b/src/dbus/gconnman_service.cpp @@ -301,6 +301,21 @@ void Provider::update(const gchar* key, GVariant* value) { } } +Proxy::Proxy(const Proxy::Method method, std::string url, + std::vector servers, + std::vector excludes) + : method_(method), + url_(std::move(url)), + servers_(std::move(servers)), + excludes_(std::move(excludes)) {} + +void Service::setProxy(const Proxy& proxy_configuration, + PropertiesSetCallback callback) { + auto data = prepareCallback(std::move(callback)); + setProperty(PROXY_CONFIGURATION_STR, proxy_configuration.getVariant().get(), + nullptr, &Service::finishAsyncCall, data.release()); +} + void Proxy::update(const gchar* key, GVariant* value) { if (g_strcmp0(key, METHOD_STR) == 0U) { method_ = @@ -316,6 +331,30 @@ void Proxy::update(const gchar* key, GVariant* value) { } } +auto Proxy::getVariant() const -> VariantPtr { + GVariantBuilder builder; + g_variant_builder_init(&builder, G_VARIANT_TYPE("a{sv}")); + g_variant_builder_add( + &builder, "{sv}", METHOD_STR, + g_variant_new_string( + std::string(PROXY_METHOD_MAP.toString(method_)).c_str())); + if (!url_.empty()) { + g_variant_builder_add(&builder, "{sv}", URL_STR, + g_variant_new_string(url_.c_str())); + } + if (!servers_.empty()) { + g_variant_builder_add(&builder, "{sv}", SERVERS_STR, + vector_to_as(servers_).get()); + } + if (!excludes_.empty()) { + g_variant_builder_add(&builder, "{sv}", EXCLUDES_STR, + vector_to_as(excludes_).get()); + } + + return VariantPtr{g_variant_ref_sink(g_variant_builder_end(&builder)), + &g_variant_unref}; +} + void ServProperties::update(const gchar* key, GVariant* value) { if (g_strcmp0(key, NAME_STR) == 0) { name_ = g_variant_get_string(value, nullptr); @@ -363,6 +402,10 @@ void ServProperties::update(const gchar* key, GVariant* value) { proxy_ = (g_variant_n_children(value) != 0) ? std::optional(Proxy(value)) : std::nullopt; + } else if (g_strcmp0(key, PROXY_CONFIGURATION_STR) == 0U) { + proxy_configuration_ = (g_variant_n_children(value) != 0) + ? std::optional(Proxy(value)) + : std::nullopt; } else if (g_strcmp0(key, SECURITY_STR) == 0U) { security_ = (g_variant_n_children(value) != 0) ? std::optional>( @@ -504,6 +547,11 @@ auto operator<<(std::ostream& ost, const ServProperties& obj) -> std::ostream& { ost << obj.proxy_.value(); } + if (obj.proxy_configuration_) { + ost << "Configuration "; + ost << obj.proxy_configuration_.value(); + } + return ost; } diff --git a/tests/gconnman_serv_test.cpp b/tests/gconnman_serv_test.cpp index 23c83a1..b4450ae 100644 --- a/tests/gconnman_serv_test.cpp +++ b/tests/gconnman_serv_test.cpp @@ -17,6 +17,7 @@ using Type = Amarula::DBus::G::Connman::TechProperties::Type; using ServType = Amarula::DBus::G::Connman::ServProperties::Type; using IPv4 = Amarula::DBus::G::Connman::IPv4; using IPv6 = Amarula::DBus::G::Connman::IPv6; +using Proxy = Amarula::DBus::G::Connman::Proxy; TEST(Connman, getServs) { bool called = false; @@ -372,6 +373,69 @@ TEST(Connman, setIPv6Configuration) { ASSERT_TRUE(called) << "ServicesChanged callback was never called"; } +TEST(Connman, setProxyConfiguration) { + bool called = false; + { + const ThreadBundle thread_bundle; + const Connman connman; + const auto manager = connman.manager(); + + auto do_on_servs = [&called, main_tid = thread_bundle.main_tid, + loop_tid = thread_bundle.loop_tid]( + const auto& services, + const bool check_thread_id = true) { + if (!called) { + called = true; + if (check_thread_id) { + const auto callback_tid = std::this_thread::get_id(); + EXPECT_NE(callback_tid, main_tid); + EXPECT_NE(callback_tid, loop_tid); + } + ASSERT_FALSE(services.empty()); + for (const auto& serv : services) { + const auto props = serv->properties(); + const auto name = props.getName(); + std::cout << props; + serv->onPropertyChanged([](const auto& properties) { + std::cout << "onPropertyChange:\n"; + std::cout << properties; + }); + const auto proxy_config = + Proxy(Proxy::Method::Manual, "", + {"proxy.example.com:8080"}, {"localhost"}); + serv->setProxy(proxy_config, [serv, name, main_tid, + loop_tid](auto success) { + const auto callback_tid = std::this_thread::get_id(); + EXPECT_NE(callback_tid, main_tid); + EXPECT_NE(callback_tid, loop_tid); + EXPECT_TRUE(success) + << "Set setProxyConfiguration manual for " << name + << " did not succeed"; + const auto proxy_config = Proxy(Proxy::Method::Direct); + serv->setProxy(proxy_config, [name, main_tid, + loop_tid](auto success) { + const auto callback_tid = + std::this_thread::get_id(); + EXPECT_NE(callback_tid, main_tid); + EXPECT_NE(callback_tid, loop_tid); + EXPECT_TRUE(success) + << "Set setProxyConfiguration direct for " + << name << " did not succeed"; + }); + }); + } + } + }; + + if (manager->services().empty()) { + manager->onServicesChanged(do_on_servs); + } else { + do_on_servs(manager->services(), false); + } + } + ASSERT_TRUE(called) << "ServicesChanged callback was never called"; +} + TEST(Connman, ForgetAndDisconnectService) { bool called = false; From 93618d8e1a2c0c0c1d7ec05fa2cb82ad8c2564a6 Mon Sep 17 00:00:00 2001 From: Eduardo Gonzalez Date: Tue, 3 Nov 2026 15:18:27 +0100 Subject: [PATCH 5/5] connman_service: Parse and expose mDNS.Configuration Add the setters and getters for the mDNS.Configuration. Implement part of #50. Signed-off-by: Eduardo Gonzalez --- include/amarula/dbus/connman/gservice.hpp | 5 ++ src/dbus/gconnman_private.hpp | 1 + src/dbus/gconnman_service.cpp | 10 ++++ tests/gconnman_serv_test.cpp | 57 +++++++++++++++++++++++ 4 files changed, 73 insertions(+) diff --git a/include/amarula/dbus/connman/gservice.hpp b/include/amarula/dbus/connman/gservice.hpp index 6f0abbf..8c89d99 100644 --- a/include/amarula/dbus/connman/gservice.hpp +++ b/include/amarula/dbus/connman/gservice.hpp @@ -223,6 +223,9 @@ struct ServProperties { [[nodiscard]] auto getError() const { return error_; } [[nodiscard]] auto isAutoconnect() const { return autoconnect_; } [[nodiscard]] auto isMDNSEnabled() const { return mdns_; } + [[nodiscard]] auto isMDNSConfigurationEnabled() const { + return mdns_conf_; + } [[nodiscard]] auto isFavorite() const { return favorite_; } [[nodiscard]] auto isImmutable() const { return immutable_; } [[nodiscard]] auto isRoaming() const { return roaming_; } @@ -268,6 +271,7 @@ struct ServProperties { std::optional> time_servers_conf_; bool autoconnect_{false}; bool mdns_{false}; + bool mdns_conf_{false}; bool favorite_{false}; bool immutable_{false}; bool roaming_{false}; @@ -299,6 +303,7 @@ class Service : public DBusProxy { void remove(PropertiesSetCallback callback = nullptr); void setAutoconnect(bool autoconnect, PropertiesSetCallback callback = nullptr); + void setMDNS(bool mdns, PropertiesSetCallback callback = nullptr); void setNameServers(const std::vector& name_servers, PropertiesSetCallback callback = nullptr); void setTimeServers(const std::vector& time_servers, diff --git a/src/dbus/gconnman_private.hpp b/src/dbus/gconnman_private.hpp index c59b983..4b1ead3 100644 --- a/src/dbus/gconnman_private.hpp +++ b/src/dbus/gconnman_private.hpp @@ -67,6 +67,7 @@ constexpr auto DOMAINS_CONFIGURATION_STR = "Domains.Configuration"; constexpr auto IPV4_CONFIGURATION_STR = "IPv4.Configuration"; constexpr auto IPV6_CONFIGURATION_STR = "IPv6.Configuration"; constexpr auto PROXY_CONFIGURATION_STR = "Proxy.Configuration"; +constexpr auto MDNS_CONFIGURATION_STR = "mDNS.Configuration"; // Manager interface constexpr auto MANAGER_INTERFACE = "net.connman.Manager"; diff --git a/src/dbus/gconnman_service.cpp b/src/dbus/gconnman_service.cpp index 9331266..2d083c6 100644 --- a/src/dbus/gconnman_service.cpp +++ b/src/dbus/gconnman_service.cpp @@ -113,6 +113,13 @@ void Service::setAutoconnect(const bool autoconnect, nullptr, &Service::finishAsyncCall, data.release()); } +void Service::setMDNS(const bool mdns, PropertiesSetCallback callback) { + auto data = prepareCallback(std::move(callback)); + setProperty(MDNS_CONFIGURATION_STR, + g_variant_new_boolean(static_cast(mdns)), nullptr, + &Service::finishAsyncCall, data.release()); +} + void Service::setNameServers(const std::vector& name_servers, PropertiesSetCallback callback) { auto data = prepareCallback(std::move(callback)); @@ -372,6 +379,8 @@ void ServProperties::update(const gchar* key, GVariant* value) { autoconnect_ = g_variant_get_boolean(value) == 1U; } else if (g_strcmp0(key, MDNS_STR) == 0U) { mdns_ = g_variant_get_boolean(value) == 1U; + } else if (g_strcmp0(key, MDNS_CONFIGURATION_STR) == 0U) { + mdns_conf_ = g_variant_get_boolean(value) == 1U; } else if (g_strcmp0(key, STRENGTH_STR) == 0U) { strength_ = g_variant_get_byte(value); } else if (g_strcmp0(key, IPV4_STR) == 0U) { @@ -457,6 +466,7 @@ auto operator<<(std::ostream& ost, const ServProperties& obj) -> std::ostream& { ost << "Strength: " << static_cast(obj.strength_) << '\n'; ost << "AutoConnect: " << std::boolalpha << obj.autoconnect_ << '\n'; ost << "mDNS: " << obj.mdns_ << '\n'; + ost << "mDNS.Configuration: " << obj.mdns_conf_ << '\n'; ost << "Favorite: " << obj.favorite_ << '\n'; ost << "Immutable: " << obj.immutable_ << '\n'; ost << "Roaming: " << obj.roaming_ << '\n'; diff --git a/tests/gconnman_serv_test.cpp b/tests/gconnman_serv_test.cpp index b4450ae..909bb93 100644 --- a/tests/gconnman_serv_test.cpp +++ b/tests/gconnman_serv_test.cpp @@ -436,6 +436,63 @@ TEST(Connman, setProxyConfiguration) { ASSERT_TRUE(called) << "ServicesChanged callback was never called"; } +TEST(Connman, setMDNS) { + bool called = false; + { + const ThreadBundle thread_bundle; + const Connman connman; + const auto manager = connman.manager(); + + auto do_on_servs = [&called, main_tid = thread_bundle.main_tid, + loop_tid = thread_bundle.loop_tid]( + const auto& services, + const bool check_thread_id = true) { + if (!called) { + called = true; + if (check_thread_id) { + const auto callback_tid = std::this_thread::get_id(); + EXPECT_NE(callback_tid, main_tid); + EXPECT_NE(callback_tid, loop_tid); + } + ASSERT_FALSE(services.empty()); + for (const auto& serv : services) { + const auto props = serv->properties(); + const auto name = props.getName(); + std::cout << props; + serv->onPropertyChanged([](const auto& properties) { + std::cout << "onPropertyChange:\n"; + std::cout << properties; + }); + serv->setMDNS(true, [serv, name, main_tid, + loop_tid](auto success) { + const auto callback_tid = std::this_thread::get_id(); + EXPECT_NE(callback_tid, main_tid); + EXPECT_NE(callback_tid, loop_tid); + EXPECT_TRUE(success) << "Set setMDNS true for " << name + << " did not succeed"; + serv->setMDNS(false, [name, main_tid, + loop_tid](auto success) { + const auto callback_tid = + std::this_thread::get_id(); + EXPECT_NE(callback_tid, main_tid); + EXPECT_NE(callback_tid, loop_tid); + EXPECT_TRUE(success) << "Set setMDNS false for " + << name << " did not succeed"; + }); + }); + } + } + }; + + if (manager->services().empty()) { + manager->onServicesChanged(do_on_servs); + } else { + do_on_servs(manager->services(), false); + } + } + ASSERT_TRUE(called) << "ServicesChanged callback was never called"; +} + TEST(Connman, ForgetAndDisconnectService) { bool called = false;