Skip to content

Commit 987a3c9

Browse files
committed
Add sdbus-c++ ConnMan client example
Signed-off-by: JianDe <jiande2020@protonmail.com>
1 parent 7b9a77b commit 987a3c9

5 files changed

Lines changed: 335 additions & 0 deletions

File tree

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ message(STATUS "libudev ................ found (version ${UDEV_VERSION})")
5656

5757
add_subdirectory(src/avahi)
5858
add_subdirectory(src/bluez)
59+
add_subdirectory(src/connman)
5960
add_subdirectory(src/fwupd)
6061
add_subdirectory(src/geoclue2)
6162
add_subdirectory(src/hostname1)

src/connman/CMakeLists.txt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
add_executable(connman_client
2+
main.cc
3+
connman_client.cc
4+
connman_client.h
5+
)
6+
7+
target_link_libraries(connman_client
8+
PUBLIC
9+
utils
10+
sdbus-c++
11+
spdlog::spdlog
12+
)
13+
14+
if (ENABLE_LTO AND IPO_SUPPORT_RESULT)
15+
set_property(TARGET connman_client PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
16+
endif ()
17+
18+
install(TARGETS connman_client
19+
RUNTIME DESTINATION share/sdbus-cpp-examples)

src/connman/connman_client.cc

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
// Copyright (c) 2026 Jian De
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include "connman_client.h"
16+
17+
#include <sstream>
18+
19+
#include "../utils/logging.h"
20+
#include "../utils/utils.h"
21+
22+
//
23+
// ConnmanManagerClient
24+
//
25+
26+
ConnmanManagerClient::ConnmanManagerClient(sdbus::IConnection& connection)
27+
: ProxyInterfaces(connection,
28+
sdbus::ServiceName{SERVICE_NAME},
29+
sdbus::ObjectPath{OBJECT_PATH}) {
30+
registerProxy();
31+
32+
// Load initial technologies
33+
for (const auto& tech : GetTechnologies()) {
34+
onTechnologyAdded(tech.get<0>(), tech.get<1>());
35+
}
36+
37+
// Load initial services
38+
for (const auto& service : GetServices()) {
39+
const auto& path = service.get<0>();
40+
if (services_.find(path) == services_.end()) {
41+
services_[path] = std::make_unique<ConnmanServiceClient>(
42+
getProxy().getConnection(), path);
43+
}
44+
}
45+
}
46+
47+
ConnmanManagerClient::~ConnmanManagerClient() {
48+
unregisterProxy();
49+
}
50+
51+
void ConnmanManagerClient::onPropertyChanged(const std::string& name,
52+
const sdbus::Variant& value) {
53+
std::ostringstream os;
54+
Utils::append_property(value, os);
55+
LOG_INFO("Manager PropertyChanged: {} = {}", name, os.str());
56+
}
57+
58+
void ConnmanManagerClient::onTechnologyAdded(
59+
const sdbus::ObjectPath& path,
60+
const std::map<std::string, sdbus::Variant>& properties) {
61+
LOG_INFO("Technology added: {}", path);
62+
if (technologies_.find(path) == technologies_.end()) {
63+
technologies_[path] = std::make_unique<ConnmanTechnologyClient>(
64+
getProxy().getConnection(), path);
65+
}
66+
}
67+
68+
void ConnmanManagerClient::onTechnologyRemoved(const sdbus::ObjectPath& path) {
69+
LOG_INFO("Technology removed: {}", path);
70+
technologies_.erase(path);
71+
}
72+
73+
void ConnmanManagerClient::onServicesChanged(
74+
const std::vector<sdbus::Struct<sdbus::ObjectPath,
75+
std::map<std::string, sdbus::Variant>>>&
76+
changed,
77+
const std::vector<sdbus::ObjectPath>& removed) {
78+
for (const auto& service : changed) {
79+
const auto& path = service.get<0>();
80+
const auto& props = service.get<1>();
81+
82+
if (services_.find(path) == services_.end()) {
83+
LOG_INFO("Service added: {}", path);
84+
services_[path] = std::make_unique<ConnmanServiceClient>(
85+
getProxy().getConnection(), path);
86+
}
87+
88+
// Log WiFi info only when Type is explicitly "wifi" in this delta
89+
bool is_wifi = false;
90+
if (auto it = props.find("Type");
91+
it != props.end() && it->second.containsValueOfType<std::string>()) {
92+
is_wifi = (it->second.get<std::string>() == "wifi");
93+
}
94+
95+
if (is_wifi) {
96+
std::string ssid = "Unknown";
97+
if (auto it = props.find("Name");
98+
it != props.end() && it->second.containsValueOfType<std::string>()) {
99+
ssid = it->second.get<std::string>();
100+
}
101+
LOG_INFO(" WiFi Update: {} [{}]", ssid, path);
102+
}
103+
}
104+
105+
for (const auto& path : removed) {
106+
LOG_INFO(" Service removed: {}", path);
107+
services_.erase(path);
108+
}
109+
}
110+
111+
void ConnmanManagerClient::onPeersChanged(
112+
const std::vector<sdbus::Struct<sdbus::ObjectPath,
113+
std::map<std::string, sdbus::Variant>>>&,
114+
const std::vector<sdbus::ObjectPath>&) {}
115+
116+
void ConnmanManagerClient::onTetheringClientsChanged(
117+
const std::vector<std::string>&,
118+
const std::vector<std::string>&) {}
119+
120+
//
121+
// ConnmanTechnologyClient
122+
//
123+
124+
ConnmanTechnologyClient::ConnmanTechnologyClient(sdbus::IConnection& connection,
125+
sdbus::ObjectPath path)
126+
: ProxyInterfaces(connection,
127+
sdbus::ServiceName{SERVICE_NAME},
128+
std::move(path)) {
129+
registerProxy();
130+
}
131+
132+
ConnmanTechnologyClient::~ConnmanTechnologyClient() {
133+
unregisterProxy();
134+
}
135+
136+
void ConnmanTechnologyClient::onPropertyChanged(const std::string& name,
137+
const sdbus::Variant& value) {
138+
if (name == "Scanning" && value.containsValueOfType<bool>()) {
139+
bool scanning = value.get<bool>();
140+
LOG_INFO("Technology [{}] WiFi Scan: {}", getProxy().getObjectPath(),
141+
scanning ? "STARTED" : "COMPLETED");
142+
}
143+
144+
std::ostringstream os;
145+
Utils::append_property(value, os);
146+
LOG_INFO("Technology [{}] PropertyChanged: {} = {}",
147+
getProxy().getObjectPath(), name, os.str());
148+
}
149+
150+
//
151+
// ConnmanServiceClient
152+
//
153+
154+
ConnmanServiceClient::ConnmanServiceClient(sdbus::IConnection& connection,
155+
sdbus::ObjectPath path)
156+
: ProxyInterfaces(connection,
157+
sdbus::ServiceName{SERVICE_NAME},
158+
std::move(path)) {
159+
registerProxy();
160+
}
161+
162+
ConnmanServiceClient::~ConnmanServiceClient() {
163+
unregisterProxy();
164+
}
165+
166+
void ConnmanServiceClient::onPropertyChanged(const std::string& name,
167+
const sdbus::Variant& value) {
168+
std::ostringstream os;
169+
Utils::append_property(value, os);
170+
LOG_INFO("Service [{}] PropertyChanged: {} = {}", getProxy().getObjectPath(),
171+
name, os.str());
172+
}

src/connman/connman_client.h

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// Copyright (c) 2026 Jian De
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#ifndef SRC_CONNMAN_CLIENT_H
16+
#define SRC_CONNMAN_CLIENT_H
17+
18+
#include <map>
19+
#include <memory>
20+
#include <string>
21+
#include <vector>
22+
23+
#include "../proxy/net/connman/Manager/manager_proxy.h"
24+
#include "../proxy/net/connman/Service/service_proxy.h"
25+
#include "../proxy/net/connman/Technology/technology_proxy.h"
26+
27+
class ConnmanTechnologyClient;
28+
class ConnmanServiceClient;
29+
30+
class ConnmanManagerClient final
31+
: public sdbus::ProxyInterfaces<net::connman::Manager_proxy> {
32+
public:
33+
static constexpr auto SERVICE_NAME = "net.connman";
34+
static constexpr auto OBJECT_PATH = "/";
35+
36+
explicit ConnmanManagerClient(sdbus::IConnection& connection);
37+
~ConnmanManagerClient();
38+
39+
void onPropertyChanged(const std::string& name,
40+
const sdbus::Variant& value) override;
41+
42+
void onTechnologyAdded(
43+
const sdbus::ObjectPath& path,
44+
const std::map<std::string, sdbus::Variant>& properties) override;
45+
46+
void onTechnologyRemoved(const sdbus::ObjectPath& path) override;
47+
48+
void onServicesChanged(
49+
const std::vector<sdbus::Struct<sdbus::ObjectPath,
50+
std::map<std::string, sdbus::Variant>>>&
51+
changed,
52+
const std::vector<sdbus::ObjectPath>& removed) override;
53+
54+
void onPeersChanged(
55+
const std::vector<sdbus::Struct<sdbus::ObjectPath,
56+
std::map<std::string, sdbus::Variant>>>&
57+
changed,
58+
const std::vector<sdbus::ObjectPath>& removed) override;
59+
60+
void onTetheringClientsChanged(
61+
const std::vector<std::string>& registered,
62+
const std::vector<std::string>& removed) override;
63+
64+
private:
65+
std::map<sdbus::ObjectPath, std::unique_ptr<ConnmanTechnologyClient>>
66+
technologies_;
67+
std::map<sdbus::ObjectPath, std::unique_ptr<ConnmanServiceClient>> services_;
68+
};
69+
70+
class ConnmanTechnologyClient final
71+
: public sdbus::ProxyInterfaces<net::connman::Technology_proxy> {
72+
public:
73+
static constexpr auto SERVICE_NAME = "net.connman";
74+
75+
ConnmanTechnologyClient(sdbus::IConnection& connection,
76+
sdbus::ObjectPath path);
77+
~ConnmanTechnologyClient();
78+
79+
void onPropertyChanged(const std::string& name,
80+
const sdbus::Variant& value) override;
81+
};
82+
83+
class ConnmanServiceClient final
84+
: public sdbus::ProxyInterfaces<net::connman::Service_proxy> {
85+
public:
86+
static constexpr auto SERVICE_NAME = "net.connman";
87+
88+
ConnmanServiceClient(sdbus::IConnection& connection, sdbus::ObjectPath path);
89+
~ConnmanServiceClient();
90+
91+
void onPropertyChanged(const std::string& name,
92+
const sdbus::Variant& value) override;
93+
};
94+
95+
#endif // SRC_CONNMAN_CLIENT_H

src/connman/main.cc

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// Copyright (c) 2026 Jian De
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include "../utils/signal_handler.h"
16+
#include "connman_client.h"
17+
18+
int main() {
19+
try {
20+
logging_config::initializeLogging("connman_client");
21+
installSignalHandlers();
22+
23+
const auto connection = sdbus::createSystemBusConnection();
24+
connection->enterEventLoopAsync();
25+
26+
ConnmanManagerClient client(*connection);
27+
28+
LOG_INFO("ConnMan monitor daemon running - Press Ctrl+C to exit");
29+
30+
auto result = monitorLoop(*connection);
31+
32+
if (result) {
33+
LOG_ERROR("Exiting due to: {}", *result);
34+
} else {
35+
LOG_INFO("Shutting down...");
36+
}
37+
38+
connection->leaveEventLoop();
39+
return result ? 1 : 0;
40+
41+
} catch (const sdbus::Error& e) {
42+
LOG_ERROR("D-Bus error: {} - {}", e.getName(), e.getMessage());
43+
return 1;
44+
} catch (const std::exception& e) {
45+
LOG_ERROR("Exception: {}", e.what());
46+
return 1;
47+
}
48+
}

0 commit comments

Comments
 (0)