Version: 1.0.0 (shared-library ABI version 1; initial compatibility baseline).
Public headers include <qdbus-sys-version.h> with QDBUS_SYS_VERSION,
QDBUS_SYS_VERSION_CHECK(major, minor, patch), numeric component macros, and
QDBUS_SYS_VERSION_STR. Use #if guards when supporting multiple API versions.
Patch/minor releases preserve source and binary compatibility; incompatible
changes require a new major version. See VERSIONING.md for the
policy, private implementation rules, installed-consumer test, and release ABI
comparison command.
Provides QObject/QML interfaces to system D-Bus services for direct use from QML.
qdbus-sys is free software: you can redistribute it and/or modify it under the
terms of the GNU Lesser General Public License, version 2.1 only
(SPDX-License-Identifier: LGPL-2.1-only). See LICENSE for the full text.
This library is distributed without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose.
Anyone subject to yocto and the general "embedded" Linux landscape will be familiar with the dependency graph of NetworkManager, or the pace of development of Connman and the associated Qt wrappers often used to comprise a QML interfaced app.
IWD (connman dos) looks like a suitable replacement for both these options. What is required is the layer between D-Bus services and QML; iwd is a good motivator, but the project scope extends to other system services such as systemd-networkd, logind, resolved, and Shaper product daemons.
When applying a thin wrapper to a service such as iwd, I think it is fairly crucial that learning the wrapper teaches you the underlying daemon, since you will probably need to debug issues/quirks at both levels. With this in mind, one design decision is: the impl should map the underlying impl except when there is clear merit to deviation.
The public C++ APIs live in the QDBusSys namespace. Each QML module exposes
the corresponding short type names:
| C++ type | QML module | QML type |
|---|---|---|
QDBusSys::IWD |
DBusSysIWD |
IWD |
QDBusSys::IWDNetworkModel |
DBusSysIWD |
IWDNetworkModel (through iwd.networks) |
QDBusSys::SystemdNetworkd |
DBusSysSystemdNetworkd |
SystemdNetworkd |
QDBusSys::Connectivityd |
DBusSysConnectivityd |
Connectivityd |
The module directories are iwd, qsystemd-networkd, and
qdbus-sys-connectivityd. Current scope, known gaps, and long-term goals are
captured in TECHNICAL_REQUIREMENTS.md.
The DBusSysIWD QML module provides an IWD client for the shared qdbus-sys-iwd daemon.
The daemon tracks IWD, owns its agents, and coordinates operations for all client
applications. Each client's read-only networks property owns its local list
model, updated from the shared state:
import QtQuick
import DBusSysIWD
Item {
IWD { id: iwd }
ListView {
anchors.fill: parent
model: iwd.networks
delegate: Text {
required property string ssid
required property string networkId
text: ssid
MouseArea {
anchors.fill: parent
onClicked: iwd.connectNetwork(parent.networkId)
}
}
}
}State such as iwd.scanning, iwd.connected, and iwd.connectedNetworkData,
and operations such as iwd.scan(), belong to IWD. Network roles and
the length property belong to iwd.networks. C++ users include iwd.h and access the model
through QDBusSys::IWD::networks().
selectedDevice chooses an IWD device path for this client only; an empty value
automatically selects an available device. devices lists the choices.
available reports whether the broker can currently observe IWD. Clients clear
their cached state when either daemon disappears and reload when it returns.
IWD permits one signal-level agent per station. qdbus-sys-iwd owns that agent for all
clients. If an independent application owns
that agent, signalStrengthLevel falls back to the connected network's latest
scanned RSSI, using the same thresholds. Scans refresh this fallback value;
live threshold notifications require ownership of the agent.
Levels follow IWD: 0 is the strongest signal (-30 dBm or more) and 7 the weakest
(below -90 dBm). signalStrengthLevel is 7 while no network is connected.
knownNetworks lists IWD's saved networks, including those out of range, as maps
with networkId, ssid, type, autoconnect, hidden and lastTimeConnected.
forgetNetwork() and setAutoConnectNetwork() accept these IDs too.
Operations are queued per device; overlapping scan requests share one scan.
scan(), connectNetwork(), disconnectNetwork(), forgetNetwork(), and
setAutoConnectNetwork() return an operation ID. Observe
operationFinished(id, success, errorName, message) for the result. Existing
callers can continue ignoring the return value. As with IWD's Station.Scan(),
a successful scan operation means the scan was started; scanning reports its
progress and networks updates when it completes. Failures also emit
error(): SetAutoConnectFailed for setAutoConnectNetwork(),
RegisterAuthAgentFailed when no credential agent could be registered, and
OperationFailed otherwise when no specific code applies. For diagnostics,
enable the daemon's qdbus.iwd.* logging categories.
preparePassword(networkId, password) supplies a passphrase for this client's
next connection to that network. Otherwise, when IWD requests a passphrase,
only the initiating client receives credentialsRequested(id, networkId).
Respond with provideCredentials(id, password) or cancelOperation(id).
Closing the client cancels its outstanding connection attempt. Credentials
are excluded from shared snapshots. Enterprise authentication is not supported.
Installation includes libexec/qdbus-sys-iwd, qdbus-sys-iwd.service, and system
D-Bus activation and policy files. Reload systemd and D-Bus after installation using the commands
below. Constructing IWD asynchronously activates com.shapertools.qdbussys.iwd.
Its API interface is com.shapertools.qdbussys.iwd1, at object path
/com/shapertools/qdbussys/iwd.
The service supports D-Bus activation only; its unit has no [Install] section
and is not intended for systemctl enable. Deploy the client library and
daemon together. The broker's control methods permit root and members of
netdev; adjust the supplied policy to your system's intended network operators.
Other users can read state. The broker registers IWD's credential and
signal-level agents; clients never do.
The versioned D-Bus interface is documented in
qiwd.xml and described in the
broker protocol notes. Clients read one full
snapshot, then apply SnapshotDelta signals that carry only the changed keys,
tagged with an instance epoch and monotonic revision. A missed revision makes
the client fetch the full snapshot again. Operation results and credential prompts are
sent only to the requesting D-Bus connection and client instance. Commands
already sent are failed, rather than replayed, after broker loss because their
outcome may be unknown.
iwd uses adapter, Qt uses adaptor. I have a prejudice in favour of British spelling and Qt, but I believe in playing cricket (a game I hate, I might add) and cricket is nominally people from all walks write apis in American english, so you dont end up with Symbian. So Adapter is in use throughout as a shoutout to all my ESL homies making me look bad with their multitude of languages.
- https://stackoverflow.com/questions/22253458/qdbusxml2cpp-unknown-type
- https://blog.mafr.de/2006/12/19/using-dbus-introspection/
- https://iwd.wiki.kernel.org/interface_lifecycle
scripts/dump-iwd-dbus-introspectable-interface.sh
cmake -S . -B build -DCMAKE_INSTALL_PREFIX=/usr
cmake --build build
sudo cmake --install buildPass -DQDBUS_SYS_USE_LLD=ON to link with lld when building with Clang.
The default prefix is /usr. Libraries use the platform library directory
(lib, lib64, or a multiarch directory), headers use /usr/include, and
daemons use /usr/libexec. System configuration stays in /etc. For package
staging, use DESTDIR=/path/to/staging cmake --install build.
./scripts/deploy-to-sdk.shdeploy-to-sdk.sh uses CMake for configure/build/install and syncs the staged /usr tree into your active SDK sysroot.
QDBusSys::SystemdNetworkd exposes scoped OperationalState, CarrierState,
AddressState, and OnlineState enums, registered with Q_ENUM for QML.
The values are those of org.freedesktop.network1.Manager, which aggregates
links according to their RequiredForOnline settings. All default to Unknown;
unavailable, empty, or unrecognized D-Bus state strings map to Unknown as well,
and every state returns to Unknown while networkd is not running. The wrapper
never starts networkd. State properties are read-only, and change signals are
emitted only when a value changes.
if (networkd->onlineState == QDBusSys::SystemdNetworkd::OnlineState::Online) {
// All required links are online.
}In QML, import DBusSysSystemdNetworkd and compare against
SystemdNetworkd.OnlineState.Online.
qdbus-sys-connectivityd supports D-Bus activation. Constructing a
QDBusSys::Connectivityd client reads a running daemon's state immediately, so
it can be checked without waiting for a change signal, and requests startup
asynchronously when the daemon is absent. A checkConnectivity() request made during startup is sent once
the daemon is ready; repeated requests during that startup are coalesced.
The service supports D-Bus activation only and starts on first client use.
Its unit has no [Install] section and is not intended for systemctl enable.
Its executable is libexec/qdbus-sys-connectivityd, its launcher is
libexec/qdbus-sys-connectivityd.sh, and its systemd unit is
qdbus-sys-connectivityd.service.
The connectivity service is named com.shapertools.qdbussys.connectivityd;
its API interface is com.shapertools.qdbussys.connectivityd1, at object path
/com/shapertools/qdbussys/connectivityd. C++ clients include
qdbus-sys-connectivityd.h; QML clients import DBusSysConnectivityd and create
Connectivityd objects. Deploy the client library, QML module,
daemon, and D-Bus activation and policy files together.
Installation supplies the D-Bus activation file, systemd unit, and system-bus policy. After installing on a running system, run:
sudo systemctl daemon-reload
sudo busctl --system call org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus ReloadConfigqdbus-sys-connectivityd reads /etc/qdbus-sys/connectivityd.conf using QSettings
in INI format. Installation supplies /etc/qdbus-sys/connectivityd.conf.example
with the default endpoint and DNS test domains. Copy it to the active settings
path before a client activates the daemon:
sudo cp /etc/qdbus-sys/connectivityd.conf.example /etc/qdbus-sys/connectivityd.confThe example contains:
[General]
verboseDebugging=false
[Connectivity]
endpointUrl=https://connectivitycheck.gstatic.com/generate_204
expectedStatusCode=204
expectedResponse=""
dnsTestDomains=google.com, baidu.com, cloudflare.com, shapertools.com
recheckIntervalSec=60Set endpointUrl to your HTTP(S) health endpoint and dnsTestDomains to a
comma-separated list of hostnames. Restart the daemon after editing the file.
Optionally set expectedStatusCode to require a particular HTTP status. Set
expectedResponse to require an exact UTF-8 response body, including whitespace
and letter case. For example, expectedResponse="OK" accepts only OK, while
expectedResponse="" requires an empty body. Quote text containing commas and
use INI escapes such as \n for a newline. Omit either key to skip that check;
without either key, any reply without a Qt network error passes. Network errors
always fail the endpoint check. An invalid expectedStatusCode (not an integer
from 100 to 599) logs a warning and skips status validation. A status or body
mismatch follows the same retry and DNS fallback path as a failed HTTP request.
Once a check settles, the daemon revalidates it every recheckIntervalSec
seconds (default 60; 0 disables), so an upstream outage or recovery is noticed
without a local address change. Revalidation publishes only a changed result;
checkingConnectivity reports checks triggered by network changes or clients.
DNS checks bypass Qt's host lookup cache.
The daemon reads this file without writing settings back to it. If it cannot
read or parse the file, it logs a warning with the path and error. An unconfigured
probe assumes success: an empty endpointUrl skips the HTTP check, and an empty
dnsTestDomains skips DNS checks. An invalid endpoint URL logs a warning and
also skips the HTTP check. Configured probes still run; DNS checks run when the
endpoint is absent or its check fails. If neither probe is configured, a routable
interface is reported as QDBusSys::Connectivityd::EndpointAccessible (connected). An
interface without a routable address is still reported as disconnected.
The daemon's properties are read-only on the bus and change with standard
org.freedesktop.DBus.Properties.PropertiesChanged signals carrying the new
values. Any local user may read state and call checkConnectivity(); calls
less than two seconds apart are coalesced into one deferred check.
The QDBusSys::Connectivityd::Level enum is declared in
qdbus-sys-connectivityd.h. QML clients use Connectivityd.EndpointAccessible
from the DBusSysConnectivityd module. EndpointAccessible means
the configured checks passed or were skipped because they were unconfigured;
it does not imply that a particular vendor's services are reachable.
To exercise failures, configure
an endpoint such as https://health.invalid/ping and DNS domains such as
dns.invalid in this file.