FlightGear next
dbusconnection.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: (C) 2019-2022 swift Project Community / Contributors (https://swift-project.org/)
3 * SPDX-FileCopyrightText: (C) 2019-2022 Lars Toenning <dev@ltoenning.de>
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7#include "dbusconnection.h"
8#include "dbusobject.h"
9
10#include <cassert>
11
12namespace flightgear::swift {
13
15{
16 dbus_threads_init_default();
17}
18
19CDBusConnection::CDBusConnection(DBusConnection* connection)
20{
21 m_connection.reset(connection);
22 dbus_connection_ref(connection);
23 // Don't exit application, if the connection is disconnected
24 dbus_connection_set_exit_on_disconnect(connection, false);
25 dbus_connection_add_filter(connection, filterDisconnectedFunction, this, nullptr);
26}
27
29{
30 close();
31 if (m_connection) { dispatch(); } // dispatch is virtual, but safe to call in dtor, as it's declared final
32 if (m_dispatcher) { m_dispatcher->remove(this); }
33}
34
36{
37 assert(type == SessionBus);
38 DBusError error;
39 dbus_error_init(&error);
40
41 DBusBusType dbusBusType;
42 switch (type) {
43 case SessionBus: dbusBusType = DBUS_BUS_SESSION; break;
44 }
45
46 m_connection.reset(dbus_bus_get_private(dbusBusType, &error));
47 if (dbus_error_is_set(&error)) {
48 m_lastError = CDBusError(&error);
49 return false;
50 }
51
52 // Don't exit application, if the connection is disconnected
53 dbus_connection_set_exit_on_disconnect(m_connection.get(), false);
54 return true;
55}
56
57void CDBusConnection::setDispatcher(CDBusDispatcher* dispatcher)
58{
59 assert(dispatcher);
60
61 m_dispatcher = dispatcher;
62
63 m_dispatcher->add(this);
64
65 dbus_connection_set_watch_functions(
66 m_connection.get(),
67 dispatcher->m_watchCallbacks.add,
68 dispatcher->m_watchCallbacks.remove,
69 dispatcher->m_watchCallbacks.toggled,
70 &dispatcher->m_watchCallbacks, nullptr);
71
72 dbus_connection_set_timeout_functions(
73 m_connection.get(),
74 dispatcher->m_timeoutCallbacks.add,
75 dispatcher->m_timeoutCallbacks.remove,
76 dispatcher->m_timeoutCallbacks.toggled,
77 &dispatcher->m_timeoutCallbacks, nullptr);
78}
79
80void CDBusConnection::requestName(const std::string& name)
81{
82 DBusError error;
83 dbus_error_init(&error);
84 dbus_bus_request_name(m_connection.get(), name.c_str(), 0, &error);
85}
86
88{
89 return m_connection && dbus_connection_get_is_connected(m_connection.get());
90}
91
93{
94 m_disconnectedCallbacks[obj] = func;
95}
96
98{
99 auto it = m_disconnectedCallbacks.find(obj);
100 if (it == m_disconnectedCallbacks.end()) { return; }
101 m_disconnectedCallbacks.erase(it);
102}
103
104void CDBusConnection::registerObjectPath(CDBusObject* object, const std::string& interfaceName, const std::string& objectPath, const DBusObjectPathVTable& dbusObjectPathVTable)
105{
106 (void)interfaceName;
107 if (!m_connection) { return; }
108
109 dbus_connection_try_register_object_path(m_connection.get(), objectPath.c_str(), &dbusObjectPathVTable, object, nullptr);
110}
111
113{
114 if (!isConnected()) { return; }
115 dbus_uint32_t serial = message.getSerial();
116 dbus_connection_send(m_connection.get(), message.m_message, &serial);
117}
118
120{
121 if (m_connection) { dbus_connection_close(m_connection.get()); }
122}
123
125{
126 dbus_connection_ref(m_connection.get());
127 if (dbus_connection_get_dispatch_status(m_connection.get()) == DBUS_DISPATCH_DATA_REMAINS) {
128 while (dbus_connection_dispatch(m_connection.get()) == DBUS_DISPATCH_DATA_REMAINS)
129 ;
130 }
131 dbus_connection_unref(m_connection.get());
132}
133
134void CDBusConnection::setDispatchStatus(DBusConnection* connection, DBusDispatchStatus status)
135{
136 if (dbus_connection_get_is_connected(connection) == FALSE) { return; }
137
138 switch (status) {
139 case DBUS_DISPATCH_DATA_REMAINS:
140 //m_dispatcher->add(this);
141 break;
142 case DBUS_DISPATCH_COMPLETE:
143 case DBUS_DISPATCH_NEED_MEMORY:
144 break;
145 }
146}
147
148void CDBusConnection::setDispatchStatus(DBusConnection* connection, DBusDispatchStatus status, void* data)
149{
150 auto* obj = static_cast<CDBusConnection*>(data);
151 obj->setDispatchStatus(connection, status);
152}
153
154DBusHandlerResult CDBusConnection::filterDisconnectedFunction(DBusConnection* connection, DBusMessage* message, void* data)
155{
156 (void)connection; // unused
157
158 auto* obj = static_cast<CDBusConnection*>(data);
159
160 DBusError err;
161 dbus_error_init(&err);
162
163 if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
164 for (auto it = obj->m_disconnectedCallbacks.begin(); it != obj->m_disconnectedCallbacks.end(); ++it) {
165 it->second();
166 }
167 return DBUS_HANDLER_RESULT_HANDLED;
168 }
169 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
170}
171
172} // namespace flightgear::swift
void unregisterDisconnectedCallback(CDBusObject *obj)
Register a disconnected callback.
void requestName(const std::string &name)
Request name to the bus.
void registerObjectPath(CDBusObject *object, const std::string &interfaceName, const std::string &objectPath, const DBusObjectPathVTable &dbusObjectPathVTable)
Register DBus object with interfaceName and objectPath.
void setDispatcher(CDBusDispatcher *dispatcher)
Set dispatcher.
std::function< void()> DisconnectedCallback
Disconnect Callback.
bool connect(BusType type)
Connect to bus.
CDBusConnection()
Default constructor.
void registerDisconnectedCallback(CDBusObject *obj, DisconnectedCallback func)
Register a disconnected callback.
void sendMessage(const CDBusMessage &message)
Send message to bus.
bool isConnected() const
Is connected?
void dispatch() override
Dispatch execution method.
~CDBusConnection() override
Destructor.
void add(IDispatchable *dispatchable)
Add dispatchable object.
dbus_uint32_t getSerial() const
Get the message serial. This is usally required for reply message.
static dbus_bool_t add(T *watch, void *refcon)
static void toggled(T *watch, void *refcon)
static void remove(T *watch, void *refcon)
static int status
const char * name
naCFunction func