Line data Source code
1 : /**
2 : Copyright (c) 2023-2024 Stappler LLC <admin@stappler.dev>
3 :
4 : Permission is hereby granted, free of charge, to any person obtaining a copy
5 : of this software and associated documentation files (the "Software"), to deal
6 : in the Software without restriction, including without limitation the rights
7 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 : copies of the Software, and to permit persons to whom the Software is
9 : furnished to do so, subject to the following conditions:
10 :
11 : The above copyright notice and this permission notice shall be included in
12 : all copies or substantial portions of the Software.
13 :
14 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 : THE SOFTWARE.
21 : **/
22 :
23 : #include "XLPlatformLinuxDbus.h"
24 : #include "SPPlatformUnistd.h"
25 : #include "SPThread.h"
26 : #include "SPDso.h"
27 :
28 : #include <sys/eventfd.h>
29 : #include <sys/epoll.h>
30 : #include <sys/timerfd.h>
31 :
32 : #define NM_DBUS_INTERFACE_NAME "org.freedesktop.NetworkManager"
33 : #define NM_DBUS_SIGNAL_STATE_CHANGED "StateChanged"
34 :
35 : typedef enum
36 : {
37 : DBUS_BUS_SESSION, /**< The login session bus */
38 : DBUS_BUS_SYSTEM, /**< The systemwide bus */
39 : DBUS_BUS_STARTER /**< The bus that started us, if any */
40 : } DBusBusType;
41 :
42 : typedef enum
43 : {
44 : DBUS_HANDLER_RESULT_HANDLED,
45 : DBUS_HANDLER_RESULT_NOT_YET_HANDLED,
46 : DBUS_HANDLER_RESULT_NEED_MEMORY
47 : } DBusHandlerResult;
48 :
49 : typedef enum
50 : {
51 : DBUS_WATCH_READABLE = 1 << 0,
52 : DBUS_WATCH_WRITABLE = 1 << 1,
53 : DBUS_WATCH_ERROR = 1 << 2,
54 : DBUS_WATCH_HANGUP = 1 << 3
55 : /* Internal to libdbus, there is also _DBUS_WATCH_NVAL in dbus-watch.h */
56 : } DBusWatchFlags;
57 :
58 : typedef enum
59 : {
60 : DBUS_DISPATCH_DATA_REMAINS, /**< There is more data to potentially convert to messages. */
61 : DBUS_DISPATCH_COMPLETE, /**< All currently available data has been processed. */
62 : DBUS_DISPATCH_NEED_MEMORY /**< More memory is needed to continue. */
63 : } DBusDispatchStatus;
64 :
65 : struct DBusError
66 : {
67 : const char *name; /**< public error name field */
68 : const char *message; /**< public error message field */
69 :
70 : unsigned int dummy1 : 1; /**< placeholder */
71 : unsigned int dummy2 : 1; /**< placeholder */
72 : unsigned int dummy3 : 1; /**< placeholder */
73 : unsigned int dummy4 : 1; /**< placeholder */
74 : unsigned int dummy5 : 1; /**< placeholder */
75 :
76 : void *padding1; /**< placeholder */
77 : };
78 :
79 : typedef struct DBusMessageIter DBusMessageIter;
80 :
81 : struct DBusMessageIter
82 : {
83 : void *dummy1; /**< Don't use this */
84 : void *dummy2; /**< Don't use this */
85 : uint32_t dummy3; /**< Don't use this */
86 : int dummy4; /**< Don't use this */
87 : int dummy5; /**< Don't use this */
88 : int dummy6; /**< Don't use this */
89 : int dummy7; /**< Don't use this */
90 : int dummy8; /**< Don't use this */
91 : int dummy9; /**< Don't use this */
92 : int dummy10; /**< Don't use this */
93 : int dummy11; /**< Don't use this */
94 : int pad1; /**< Don't use this */
95 : void *pad2; /**< Don't use this */
96 : void *pad3; /**< Don't use this */
97 : };
98 :
99 : typedef uint32_t dbus_bool_t;
100 : typedef struct DBusMessage DBusMessage;
101 : typedef struct DBusConnection DBusConnection;
102 : typedef struct DBusPendingCall DBusPendingCall;
103 : typedef struct DBusWatch DBusWatch;
104 : typedef struct DBusTimeout DBusTimeout;
105 :
106 : typedef dbus_bool_t (*DBusAddWatchFunction)(DBusWatch *watch, void *data);
107 : typedef void (*DBusWatchToggledFunction)(DBusWatch *watch, void *data);
108 : typedef void (*DBusRemoveWatchFunction)(DBusWatch *watch, void *data);
109 : typedef dbus_bool_t (*DBusAddTimeoutFunction)(DBusTimeout *timeout, void *data);
110 : typedef void (*DBusTimeoutToggledFunction)(DBusTimeout *timeout, void *data);
111 : typedef void (*DBusRemoveTimeoutFunction)(DBusTimeout *timeout, void *data);
112 : typedef void (*DBusDispatchStatusFunction)(DBusConnection *connection, DBusDispatchStatus new_status, void *data);
113 : typedef void (*DBusWakeupMainFunction)(void *data);
114 : typedef dbus_bool_t (*DBusAllowUnixUserFunction)(DBusConnection *connection, unsigned long uid, void *data);
115 : typedef dbus_bool_t (*DBusAllowWindowsUserFunction)(DBusConnection *connection, const char *user_sid, void *data);
116 : typedef void (*DBusPendingCallNotifyFunction) (DBusPendingCall *pending, void *user_data);
117 : typedef void (*DBusFreeFunction) (void *memory);
118 : typedef DBusHandlerResult (*DBusHandleMessageFunction) (DBusConnection *connection, DBusMessage *message, void *user_data);
119 :
120 : enum DBusTypeWrapper {
121 : DBUS_TYPE_INVALID = int('\0'),
122 : DBUS_TYPE_BYTE = int( 'y'),
123 : DBUS_TYPE_BOOLEAN = int( 'b'),
124 : DBUS_TYPE_INT16 = int( 'n'),
125 : DBUS_TYPE_UINT16 = int( 'q'),
126 : DBUS_TYPE_INT32 = int( 'i'),
127 : DBUS_TYPE_UINT32 = int( 'u'),
128 : DBUS_TYPE_INT64 = int( 'x'),
129 : DBUS_TYPE_UINT64 = int( 't'),
130 : DBUS_TYPE_DOUBLE = int( 'd'),
131 : DBUS_TYPE_STRING = int( 's'),
132 : DBUS_TYPE_OBJECT_PATH = int( 'o'),
133 : DBUS_TYPE_SIGNATURE = int( 'g'),
134 : DBUS_TYPE_UNIX_FD = int( 'h'),
135 :
136 : /* Compound types */
137 : DBUS_TYPE_ARRAY = int( 'a'),
138 : DBUS_TYPE_VARIANT = int( 'v'),
139 : DBUS_TYPE_STRUCT = int( 'r'),
140 : DBUS_TYPE_DICT_ENTRY = int( 'e'),
141 : };
142 :
143 : enum DBusMessageTypeWrapper {
144 : DBUS_MESSAGE_TYPE_INVALID = int(0),
145 : DBUS_MESSAGE_TYPE_METHOD_CALL = int(1),
146 : DBUS_MESSAGE_TYPE_METHOD_RETURN = int(2),
147 : DBUS_MESSAGE_TYPE_ERROR = int(3),
148 : DBUS_MESSAGE_TYPE_SIGNAL = int(4),
149 : };
150 :
151 : enum NMDeviceType {
152 : NM_DEVICE_TYPE_UNKNOWN = 0, // unknown device
153 : NM_DEVICE_TYPE_GENERIC = 14, // generic support for unrecognized device types
154 : NM_DEVICE_TYPE_ETHERNET = 1, // a wired ethernet device
155 : NM_DEVICE_TYPE_WIFI = 2, // an 802.11 WiFi device
156 : NM_DEVICE_TYPE_UNUSED1 = 3, // not used
157 : NM_DEVICE_TYPE_UNUSED2 = 4, // not used
158 : NM_DEVICE_TYPE_BT = 5, // a Bluetooth device supporting PAN or DUN access protocols
159 : NM_DEVICE_TYPE_OLPC_MESH = 6, // an OLPC XO mesh networking device
160 : NM_DEVICE_TYPE_WIMAX = 7, // an 802.16e Mobile WiMAX broadband device
161 : NM_DEVICE_TYPE_MODEM = 8, // a modem supporting analog telephone, CDMA/EVDO, GSM/UMTS, or LTE network access protocols
162 : NM_DEVICE_TYPE_INFINIBAND = 9, // an IP-over-InfiniBand device
163 : NM_DEVICE_TYPE_BOND = 10, // a bond master interface
164 : NM_DEVICE_TYPE_VLAN = 11, // an 802.1Q VLAN interface
165 : NM_DEVICE_TYPE_ADSL = 12, // ADSL modem
166 : NM_DEVICE_TYPE_BRIDGE = 13, // a bridge master interface
167 : NM_DEVICE_TYPE_TEAM = 15, // a team master interface
168 : NM_DEVICE_TYPE_TUN = 16, // a TUN or TAP interface
169 : NM_DEVICE_TYPE_IP_TUNNEL = 17, // a IP tunnel interface
170 : NM_DEVICE_TYPE_MACVLAN = 18, // a MACVLAN interface
171 : NM_DEVICE_TYPE_VXLAN = 19, // a VXLAN interface
172 : NM_DEVICE_TYPE_VETH = 20, // a VETH interface
173 : };
174 :
175 : static constexpr auto DBUS_TIMEOUT_USE_DEFAULT = int(-1);
176 :
177 : #if XL_LINK
178 : extern "C" {
179 : void dbus_error_init (DBusError *error);
180 : void dbus_error_free (DBusError *error);
181 : DBusMessage* dbus_message_new_method_call(const char *bus_name, const char *path, const char *iface, const char *method);
182 : dbus_bool_t dbus_message_append_args(DBusMessage *message, int first_arg_type, ...);
183 : dbus_bool_t dbus_message_is_signal(DBusMessage *message, const char *iface, const char *signal_name);
184 : dbus_bool_t dbus_message_is_error(DBusMessage *message, const char *error_name);
185 : void dbus_message_unref(DBusMessage *message);
186 : dbus_bool_t dbus_message_iter_init(DBusMessage *message, DBusMessageIter *iter);
187 : void dbus_message_iter_recurse(DBusMessageIter *iter, DBusMessageIter *sub);
188 : void dbus_message_iter_next(DBusMessageIter *iter);
189 : int dbus_message_iter_get_arg_type(DBusMessageIter *iter);
190 : void dbus_message_iter_get_basic(DBusMessageIter *iter, void *value);
191 : int dbus_message_get_type(DBusMessage *message);
192 : const char* dbus_message_get_path(DBusMessage *message);
193 : const char* dbus_message_get_interface(DBusMessage *message);
194 : const char* dbus_message_get_member(DBusMessage *message);
195 : const char* dbus_message_get_error_name(DBusMessage *message);
196 : const char* dbus_message_get_destination(DBusMessage *message);
197 : const char* dbus_message_get_sender(DBusMessage *message);
198 : const char* dbus_message_get_signature(DBusMessage *message);
199 : DBusMessage* dbus_connection_send_with_reply_and_block(DBusConnection *connection,
200 : DBusMessage *message, int timeout_milliseconds, DBusError *error);
201 : dbus_bool_t dbus_connection_send_with_reply(DBusConnection *connection,
202 : DBusMessage *message, DBusPendingCall **pending_return, int timeout_milliseconds);
203 : dbus_bool_t dbus_connection_set_watch_functions(DBusConnection *connection, DBusAddWatchFunction add_function,
204 : DBusRemoveWatchFunction remove_function, DBusWatchToggledFunction toggled_function,
205 : void *data, DBusFreeFunction free_data_function);
206 : dbus_bool_t dbus_connection_set_timeout_functions(DBusConnection *connection, DBusAddTimeoutFunction add_function,
207 : DBusRemoveTimeoutFunction remove_function, DBusTimeoutToggledFunction toggled_function,
208 : void *data, DBusFreeFunction free_data_function);
209 : void dbus_connection_set_wakeup_main_function(DBusConnection *connection, DBusWakeupMainFunction wakeup_main_function,
210 : void *data, DBusFreeFunction free_data_function);
211 : void dbus_connection_set_dispatch_status_function(DBusConnection *connection, DBusDispatchStatusFunction function,
212 : void *data, DBusFreeFunction free_data_function);
213 : dbus_bool_t dbus_connection_add_filter(DBusConnection *connection, DBusHandleMessageFunction function,
214 : void *user_data, DBusFreeFunction free_data_function);
215 : void dbus_connection_close(DBusConnection *connection);
216 : void dbus_connection_unref(DBusConnection *connection);
217 : void dbus_connection_flush(DBusConnection *connection);
218 : DBusDispatchStatus dbus_connection_dispatch(DBusConnection *connection);
219 : dbus_bool_t dbus_error_is_set(const DBusError *error);
220 : DBusConnection* dbus_bus_get(DBusBusType type, DBusError *error);
221 : DBusConnection* dbus_bus_get_private(DBusBusType type, DBusError *error);
222 : void dbus_bus_add_match(DBusConnection *connection, const char *rule, DBusError *error);
223 : DBusPendingCall* dbus_pending_call_ref(DBusPendingCall *pending);
224 : void dbus_pending_call_unref(DBusPendingCall *pending);
225 : dbus_bool_t dbus_pending_call_set_notify(DBusPendingCall *pending, DBusPendingCallNotifyFunction function,
226 : void *user_data, DBusFreeFunction free_user_data);
227 : dbus_bool_t dbus_pending_call_get_completed(DBusPendingCall *pending);
228 : DBusMessage* dbus_pending_call_steal_reply(DBusPendingCall *pending);
229 : void dbus_pending_call_block(DBusPendingCall *pending);
230 : int dbus_watch_get_unix_fd(DBusWatch *watch);
231 : unsigned int dbus_watch_get_flags(DBusWatch *watch);
232 : void* dbus_watch_get_data(DBusWatch *watch);
233 : void dbus_watch_set_data(DBusWatch *watch, void *data, DBusFreeFunction free_data_function);
234 : dbus_bool_t dbus_watch_handle(DBusWatch *watch, unsigned int flags);
235 : dbus_bool_t dbus_watch_get_enabled(DBusWatch *watch);
236 : int dbus_timeout_get_interval(DBusTimeout *timeout);
237 : void* dbus_timeout_get_data(DBusTimeout *timeout);
238 : void dbus_timeout_set_data(DBusTimeout *timeout, void *data, DBusFreeFunction free_data_function);
239 : dbus_bool_t dbus_timeout_handle(DBusTimeout *timeout);
240 : dbus_bool_t dbus_timeout_get_enabled(DBusTimeout *timeout);
241 : }
242 : #endif
243 :
244 :
245 : namespace STAPPLER_VERSIONIZED stappler::xenolith::platform {
246 :
247 : struct DBusInterface : public thread::ThreadInterface<Interface> {
248 : struct Error {
249 : DBusError error;
250 : DBusInterface *iface;
251 :
252 : Error(DBusInterface *);
253 : ~Error();
254 :
255 : bool isSet() const;
256 : void reset();
257 : };
258 :
259 : struct Connection {
260 : DBusInterface *iface;
261 : DBusConnection *connection;
262 :
263 : Connection();
264 : Connection(DBusInterface *, DBusBusType type);
265 : ~Connection();
266 :
267 : void setup();
268 :
269 : dbus_bool_t addWatch(DBusWatch *);
270 : void watchToggled(DBusWatch *);
271 : void removeWatch(DBusWatch *);
272 :
273 : dbus_bool_t addTimeout(DBusTimeout *);
274 : void timeoutToggled(DBusTimeout *);
275 : void removeTimeout(DBusTimeout *);
276 :
277 : void wakeup();
278 : void schedule_dispatch();
279 :
280 : DBusHandlerResult handleMessage(DBusMessage *);
281 :
282 : explicit operator bool() const { return connection != nullptr; }
283 :
284 : void flush();
285 : DBusDispatchStatus dispatch();
286 : void dispatchAll();
287 :
288 : void close();
289 :
290 : Connection(Connection &&) = delete;
291 : Connection &operator=(Connection &&) = delete;
292 : Connection(const Connection &) = delete;
293 : Connection &operator=(const Connection &) = delete;
294 : };
295 :
296 : enum class EventType {
297 : Watch,
298 : Timeout,
299 : };
300 :
301 : struct EventStruct {
302 : EventType type;
303 : int fd;
304 : struct epoll_event event;
305 : Connection *connection;
306 : bool enabled = false;
307 : union {
308 : DBusWatch *watch;
309 : DBusTimeout *timeout;
310 : };
311 :
312 : static void free(void *);
313 :
314 : void handle(uint32_t ev);
315 : };
316 :
317 : DBusInterface();
318 : virtual ~DBusInterface();
319 :
320 : DBusMessage *getSettingSync(Connection &c, const char *key, const char *value, Error &err);
321 : bool parseType(DBusMessage *const reply, const int type, void *value);
322 :
323 : explicit operator bool () const { return handle ? true : false; }
324 :
325 : bool openHandle(Dso &d);
326 :
327 : bool startThread();
328 :
329 : virtual void threadInit();
330 : virtual void threadDispose();
331 : virtual bool worker();
332 :
333 : void wakeup();
334 : void addEvent(Function<void()> &&);
335 : void addEvent(EventStruct *);
336 : void updateEvent(EventStruct *);
337 : void removeEvent(EventStruct *);
338 :
339 : void handleEvents();
340 : DBusHandlerResult handleMessage(Connection *, DBusMessage *);
341 : DBusHandlerResult handleNetworkStateChanged(DBusMessage *);
342 :
343 : DBusPendingCall *readInterfaceTheme(Function<void(InterfaceThemeInfo &&)> &&cb);
344 : DBusPendingCall *updateNetworkState(Connection &c, Function<void(NetworkState &&)> &&cb);
345 :
346 : DBusPendingCall *loadServiceNames(Connection &c, Set<String> &, Function<void()> &&);
347 :
348 : DBusPendingCall *callMethod(Connection &c, StringView bus, StringView path, StringView iface, StringView method,
349 : const Callback<void(DBusMessage *)> &, Function<void(DBusMessage *)> &&);
350 :
351 : void parseServiceList(Set<String> &, DBusMessage *);
352 : NetworkState parseNetworkState(DBusMessage *);
353 : InterfaceThemeInfo parseInterfaceThemeSettings(DBusMessage *);
354 :
355 : bool parseProperty(DBusMessageIter *entry, void *value, DBusTypeWrapper = DBUS_TYPE_INVALID);
356 :
357 : void setNetworkState(NetworkState &&);
358 :
359 : void addNetworkConnectionCallback(void *key, Function<void(const NetworkState &)> &&);
360 : void removeNetworkConnectionCallback(void *key);
361 :
362 0 : InterfaceThemeInfo getCurrentTheme() {
363 0 : std::unique_lock lock(interfaceMutex);
364 0 : if (interfaceLoaded) {
365 0 : return interfaceTheme;
366 : }
367 0 : interfaceCondvar.wait(lock);
368 0 : return interfaceTheme;
369 0 : }
370 :
371 : void (*dbus_error_init) (DBusError *error) = nullptr;
372 : void (*dbus_error_free) (DBusError *error) = nullptr;
373 : DBusMessage* (*dbus_message_new_method_call) (const char *bus_name, const char *path, const char *iface, const char *method) = nullptr;
374 : dbus_bool_t (*dbus_message_append_args) (DBusMessage *message, int first_arg_type, ...) = nullptr;
375 : dbus_bool_t (*dbus_message_is_signal) (DBusMessage *message, const char *iface, const char *signal_name) = nullptr;
376 : dbus_bool_t (*dbus_message_is_error) (DBusMessage *message, const char *error_name) = nullptr; void (*dbus_message_unref) (DBusMessage *message) = nullptr;
377 : dbus_bool_t (*dbus_message_iter_init) (DBusMessage *message, DBusMessageIter *iter) = nullptr;
378 : void (*dbus_message_iter_recurse) (DBusMessageIter *iter, DBusMessageIter *sub) = nullptr;
379 : void (*dbus_message_iter_next) (DBusMessageIter *iter) = nullptr;
380 : int (*dbus_message_iter_get_arg_type) (DBusMessageIter *iter) = nullptr;
381 : void (*dbus_message_iter_get_basic) (DBusMessageIter *iter, void *value) = nullptr;
382 : int (*dbus_message_get_type)(DBusMessage *message) = nullptr;
383 : const char* (*dbus_message_get_path) (DBusMessage *message) = nullptr;
384 : const char* (*dbus_message_get_interface) (DBusMessage *message) = nullptr;
385 : const char* (*dbus_message_get_member) (DBusMessage *message) = nullptr;
386 : const char* (*dbus_message_get_error_name) (DBusMessage *message) = nullptr;
387 : const char* (*dbus_message_get_destination) (DBusMessage *message) = nullptr;
388 : const char* (*dbus_message_get_sender) (DBusMessage *message) = nullptr;
389 : const char* (*dbus_message_get_signature) (DBusMessage *message) = nullptr;
390 : DBusMessage* (*dbus_connection_send_with_reply_and_block) (DBusConnection *connection,
391 : DBusMessage *message, int timeout_milliseconds, DBusError *error) = nullptr;
392 : dbus_bool_t (*dbus_connection_send_with_reply) (DBusConnection *connection,
393 : DBusMessage *message, DBusPendingCall **pending_return, int timeout_milliseconds);
394 : dbus_bool_t (*dbus_connection_set_watch_functions) (DBusConnection *connection, DBusAddWatchFunction add_function,
395 : DBusRemoveWatchFunction remove_function, DBusWatchToggledFunction toggled_function,
396 : void *data, DBusFreeFunction free_data_function) = nullptr;
397 : dbus_bool_t (*dbus_connection_set_timeout_functions) (DBusConnection *connection, DBusAddTimeoutFunction add_function,
398 : DBusRemoveTimeoutFunction remove_function, DBusTimeoutToggledFunction toggled_function,
399 : void *data, DBusFreeFunction free_data_function) = nullptr;
400 : void (*dbus_connection_set_wakeup_main_function) (DBusConnection *connection, DBusWakeupMainFunction wakeup_main_function,
401 : void *data, DBusFreeFunction free_data_function) = nullptr;
402 : void (*dbus_connection_set_dispatch_status_function) (DBusConnection *connection, DBusDispatchStatusFunction function,
403 : void *data, DBusFreeFunction free_data_function) = nullptr;
404 : dbus_bool_t (*dbus_connection_add_filter) (DBusConnection *connection, DBusHandleMessageFunction function,
405 : void *user_data, DBusFreeFunction free_data_function) = nullptr;
406 : void (*dbus_connection_close) (DBusConnection *connection) = nullptr;
407 : void (*dbus_connection_unref) (DBusConnection *connection) = nullptr;
408 : void (*dbus_connection_flush)(DBusConnection *connection) = nullptr;
409 : DBusDispatchStatus (*dbus_connection_dispatch)(DBusConnection *connection) = nullptr;
410 : dbus_bool_t (*dbus_error_is_set) (const DBusError *error) = nullptr;
411 : DBusConnection* (*dbus_bus_get) (DBusBusType type, DBusError *error) = nullptr;
412 : DBusConnection* (*dbus_bus_get_private) (DBusBusType type, DBusError *error) = nullptr;
413 : void (*dbus_bus_add_match) (DBusConnection *connection, const char *rule, DBusError *error) = nullptr;
414 : DBusPendingCall* (*dbus_pending_call_ref) (DBusPendingCall *pending) = nullptr;
415 : void (*dbus_pending_call_unref) (DBusPendingCall *pending) = nullptr;
416 : dbus_bool_t (*dbus_pending_call_set_notify) (DBusPendingCall *pending, DBusPendingCallNotifyFunction function,
417 : void *user_data, DBusFreeFunction free_user_data) = nullptr;
418 : dbus_bool_t (*dbus_pending_call_get_completed) (DBusPendingCall *pending) = nullptr;
419 : DBusMessage* (*dbus_pending_call_steal_reply) (DBusPendingCall *pending) = nullptr;
420 : void (*dbus_pending_call_block) (DBusPendingCall *pending) = nullptr;
421 : int (*dbus_watch_get_unix_fd) (DBusWatch *watch) = nullptr;
422 : unsigned int (*dbus_watch_get_flags) (DBusWatch *watch) = nullptr;
423 : void* (*dbus_watch_get_data) (DBusWatch *watch) = nullptr;
424 : void (*dbus_watch_set_data) (DBusWatch *watch, void *data, DBusFreeFunction free_data_function) = nullptr;
425 : dbus_bool_t (*dbus_watch_handle) (DBusWatch *watch, unsigned int flags) = nullptr;
426 : dbus_bool_t (*dbus_watch_get_enabled) (DBusWatch *watch) = nullptr;
427 : int (*dbus_timeout_get_interval) (DBusTimeout *timeout) = nullptr;
428 : void* (*dbus_timeout_get_data) (DBusTimeout *timeout) = nullptr;
429 : void (*dbus_timeout_set_data) (DBusTimeout *timeout, void *data, DBusFreeFunction free_data_function) = nullptr;
430 : dbus_bool_t (*dbus_timeout_handle) (DBusTimeout *timeout) = nullptr;
431 : dbus_bool_t (*dbus_timeout_get_enabled) (DBusTimeout *timeout) = nullptr;
432 :
433 : Dso handle;
434 : Connection *sessionConnection = nullptr;
435 : Connection *systemConnection = nullptr;
436 :
437 : std::thread dbusThread;
438 : std::atomic_flag shouldExit;
439 :
440 : std::mutex interfaceMutex;
441 : std::condition_variable interfaceCondvar;
442 : bool interfaceLoaded = false;
443 : InterfaceThemeInfo interfaceTheme;
444 :
445 : NetworkState networkState;
446 : Set<String> sessionServices;
447 : Set<String> systemServices;
448 :
449 : bool hasDesktopPortal = false;
450 : bool hasNetworkManager = false;
451 :
452 : int epollFd = -1;
453 : int eventFd = -1;
454 : struct epoll_event epollEventFd;
455 :
456 : std::mutex eventMutex;
457 : Vector<Function<void()>> events;
458 :
459 : struct StateCallback {
460 : Function<void(const NetworkState &)> callback;
461 : Rc<Ref> ref;
462 : };
463 :
464 : Map<void *, StateCallback> networkCallbacks;
465 : };
466 :
467 : static Rc<DBusInterface> s_connection = Rc<DBusInterface>::alloc();
468 :
469 100 : static uint32_t DBusInterface_watchFlagsToEpoll(unsigned int flags) {
470 100 : uint32_t events = 0;
471 100 : if (flags & DBUS_WATCH_READABLE)
472 50 : events |= EPOLLIN;
473 100 : if (flags & DBUS_WATCH_WRITABLE)
474 50 : events |= EPOLLOUT;
475 100 : return events;
476 : }
477 :
478 125 : static unsigned int DBusInterface_epollToWatchFlags(uint32_t events) {
479 125 : short flags = 0;
480 125 : if (events & EPOLLIN)
481 125 : flags |= DBUS_WATCH_READABLE;
482 125 : if (events & EPOLLOUT)
483 0 : flags |= DBUS_WATCH_WRITABLE;
484 125 : if (events & EPOLLHUP)
485 0 : flags |= DBUS_WATCH_HANGUP;
486 125 : if (events & EPOLLERR)
487 0 : flags |= DBUS_WATCH_ERROR;
488 125 : return flags;
489 : }
490 :
491 75 : DBusInterface::Error::Error(DBusInterface *i) : iface(i) {
492 75 : iface->dbus_error_init(&error);
493 75 : }
494 :
495 75 : DBusInterface::Error::~Error() {
496 75 : if (iface->dbus_error_is_set(&error)) {
497 0 : iface->dbus_error_free(&error);
498 : }
499 75 : }
500 :
501 25 : bool DBusInterface::Error::isSet() const {
502 25 : return iface->dbus_error_is_set(&error);
503 : }
504 :
505 0 : void DBusInterface::Error::reset() {
506 0 : if (iface->dbus_error_is_set(&error)) {
507 0 : iface->dbus_error_free(&error);
508 : }
509 0 : }
510 :
511 0 : DBusInterface::Connection::Connection() : iface(nullptr), connection(nullptr) { }
512 :
513 50 : DBusInterface::Connection::Connection(DBusInterface *i, DBusBusType type)
514 50 : : iface(i) {
515 50 : Error error(iface);
516 50 : connection = iface->dbus_bus_get_private(type, &error.error);
517 50 : }
518 :
519 0 : DBusInterface::Connection::~Connection() {
520 0 : close();
521 0 : }
522 :
523 100 : static dbus_bool_t DBusInterface_Connection_addWatch(DBusWatch *watch, void *data) {
524 100 : auto conn = reinterpret_cast<DBusInterface::Connection *>(data);
525 100 : return conn->addWatch(watch);
526 : }
527 :
528 0 : static void DBusInterface_Connection_watchToggled(DBusWatch *watch, void *data) {
529 0 : auto conn = reinterpret_cast<DBusInterface::Connection *>(data);
530 0 : conn->watchToggled(watch);
531 0 : }
532 :
533 0 : static void DBusInterface_Connection_removeWatch(DBusWatch *watch, void *data) {
534 0 : auto conn = reinterpret_cast<DBusInterface::Connection *>(data);
535 0 : conn->removeWatch(watch);
536 0 : }
537 :
538 125 : static dbus_bool_t DBusInterface_Connection_addTimeout(DBusTimeout *timeout, void *data) {
539 125 : auto conn = reinterpret_cast<DBusInterface::Connection *>(data);
540 125 : return conn->addTimeout(timeout);
541 : }
542 :
543 125 : static void DBusInterface_Connection_timeoutToggled(DBusTimeout *timeout, void *data) {
544 125 : auto conn = reinterpret_cast<DBusInterface::Connection *>(data);
545 125 : conn->timeoutToggled(timeout);
546 125 : }
547 :
548 0 : static void DBusInterface_Connection_removeTimeout(DBusTimeout *timeout, void *data) {
549 0 : auto conn = reinterpret_cast<DBusInterface::Connection *>(data);
550 0 : conn->removeTimeout(timeout);
551 0 : }
552 :
553 125 : static void DBusInterface_Connection_wakeupMain(void *data) {
554 125 : auto conn = reinterpret_cast<DBusInterface::Connection *>(data);
555 125 : conn->wakeup();
556 125 : }
557 :
558 250 : static void DBusInterface_Connection_dispatchStatus(DBusConnection *connection, DBusDispatchStatus new_status, void *data) {
559 250 : if (new_status == DBUS_DISPATCH_DATA_REMAINS) {
560 100 : auto conn = reinterpret_cast<DBusInterface::Connection *>(data);
561 100 : conn->schedule_dispatch();
562 : }
563 250 : }
564 :
565 50 : static DBusHandlerResult DBusInterface_Connection_handleMessage(DBusConnection *connection, DBusMessage *message, void *data) {
566 50 : auto conn = reinterpret_cast<DBusInterface::Connection *>(data);
567 50 : return conn->handleMessage(message);
568 : }
569 :
570 50 : void DBusInterface::Connection::setup() {
571 50 : if (connection) {
572 50 : iface->dbus_connection_set_watch_functions(connection, DBusInterface_Connection_addWatch,
573 : DBusInterface_Connection_watchToggled, DBusInterface_Connection_removeWatch, this, nullptr);
574 50 : iface->dbus_connection_set_timeout_functions(connection, DBusInterface_Connection_addTimeout,
575 : DBusInterface_Connection_timeoutToggled, DBusInterface_Connection_removeTimeout, this, nullptr);
576 50 : iface->dbus_connection_set_wakeup_main_function(connection, DBusInterface_Connection_wakeupMain, this, nullptr);
577 50 : iface->dbus_connection_set_dispatch_status_function(connection, DBusInterface_Connection_dispatchStatus, this, nullptr);
578 50 : iface->dbus_connection_add_filter(connection, DBusInterface_Connection_handleMessage, this, nullptr);
579 50 : schedule_dispatch();
580 : }
581 50 : }
582 :
583 100 : dbus_bool_t DBusInterface::Connection::addWatch(DBusWatch *watch) {
584 100 : auto ev = new EventStruct;
585 100 : ev->type = DBusInterface::EventType::Watch;
586 100 : ev->fd = iface->dbus_watch_get_unix_fd(watch);
587 100 : ev->event.data.ptr = ev;
588 100 : ev->event.events = DBusInterface_watchFlagsToEpoll(iface->dbus_watch_get_flags(watch));
589 100 : ev->connection = this;
590 100 : ev->enabled = false;
591 100 : ev->watch = watch;
592 100 : iface->dbus_watch_set_data(watch, ev, EventStruct::free);
593 :
594 100 : if (iface->dbus_watch_get_enabled(watch)) {
595 50 : ev->enabled = true;
596 50 : iface->addEvent(ev);
597 : }
598 100 : return 1;
599 : }
600 :
601 0 : void DBusInterface::Connection::watchToggled(DBusWatch *watch) {
602 0 : auto ev = reinterpret_cast<EventStruct *>(iface->dbus_watch_get_data(watch));
603 0 : if (iface->dbus_watch_get_enabled(watch)) {
604 0 : if (!ev->enabled) {
605 0 : ev->enabled = true;
606 0 : iface->addEvent(ev);
607 : }
608 : } else {
609 0 : if (ev->enabled) {
610 0 : iface->removeEvent(ev);
611 0 : ev->enabled = false;
612 : }
613 : }
614 0 : }
615 :
616 0 : void DBusInterface::Connection::removeWatch(DBusWatch *watch) {
617 0 : auto ev = reinterpret_cast<EventStruct *>(iface->dbus_watch_get_data(watch));
618 0 : if (ev->enabled) {
619 0 : iface->removeEvent(ev);
620 0 : ev->enabled = false;
621 : }
622 0 : iface->dbus_watch_set_data(watch, nullptr, nullptr);
623 0 : }
624 :
625 125 : dbus_bool_t DBusInterface::Connection::addTimeout(DBusTimeout *timeout) {
626 125 : auto ev = new EventStruct;
627 125 : ev->type = DBusInterface::EventType::Timeout;
628 :
629 125 : ev->fd = ::timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
630 :
631 125 : auto milliseconds = iface->dbus_timeout_get_interval(timeout);
632 :
633 : struct itimerspec initTimer;
634 125 : initTimer.it_interval.tv_nsec = 0;
635 125 : initTimer.it_interval.tv_sec = 0;
636 125 : initTimer.it_value.tv_nsec = (milliseconds % 1000) * 1000 * 1000;
637 125 : initTimer.it_value.tv_sec = milliseconds / 1000;
638 :
639 125 : ::timerfd_settime(ev->fd, 0, &initTimer, nullptr);
640 :
641 125 : ev->event.data.ptr = ev;
642 125 : ev->event.events = EPOLLIN;
643 125 : ev->connection = this;
644 125 : ev->enabled = false;
645 125 : ev->timeout = timeout;
646 125 : iface->dbus_timeout_set_data(timeout, ev, EventStruct::free);
647 :
648 125 : if (iface->dbus_timeout_get_enabled(timeout)) {
649 125 : ev->enabled = true;
650 125 : iface->addEvent(ev);
651 : }
652 :
653 125 : return 1;
654 : }
655 :
656 125 : void DBusInterface::Connection::timeoutToggled(DBusTimeout *timeout) {
657 125 : auto ev = reinterpret_cast<EventStruct *>(iface->dbus_timeout_get_data(timeout));
658 125 : if (iface->dbus_timeout_get_enabled(timeout)) {
659 125 : if (!ev->enabled) {
660 0 : ev->enabled = true;
661 :
662 0 : auto milliseconds = iface->dbus_timeout_get_interval(timeout);
663 :
664 : struct itimerspec initTimer;
665 0 : initTimer.it_interval.tv_nsec = 0;
666 0 : initTimer.it_interval.tv_sec = 0;
667 0 : initTimer.it_value.tv_nsec = (milliseconds % 1000) * 1000 * 1000;
668 0 : initTimer.it_value.tv_sec = milliseconds / 1000;
669 :
670 0 : ::timerfd_settime(ev->fd, 0, &initTimer, nullptr);
671 :
672 0 : iface->addEvent(ev);
673 : }
674 : } else {
675 0 : if (ev->enabled) {
676 0 : iface->removeEvent(ev);
677 0 : ev->enabled = false;
678 : }
679 : }
680 125 : }
681 :
682 0 : void DBusInterface::Connection::removeTimeout(DBusTimeout *timeout) {
683 0 : auto ev = reinterpret_cast<EventStruct *>(iface->dbus_timeout_get_data(timeout));
684 0 : if (ev->enabled) {
685 0 : iface->removeEvent(ev);
686 0 : ev->enabled = false;
687 : }
688 0 : iface->dbus_timeout_set_data(timeout, nullptr, nullptr);
689 0 : }
690 :
691 125 : void DBusInterface::Connection::wakeup() {
692 125 : iface->wakeup();
693 125 : }
694 :
695 150 : void DBusInterface::Connection::schedule_dispatch() {
696 150 : iface->addEvent([this] {
697 150 : dispatchAll();
698 150 : });
699 150 : }
700 :
701 50 : DBusHandlerResult DBusInterface::Connection::handleMessage(DBusMessage *message) {
702 50 : return iface->handleMessage(this, message);
703 : }
704 :
705 125 : void DBusInterface::Connection::flush() {
706 125 : iface->dbus_connection_flush(connection);
707 125 : }
708 :
709 0 : DBusDispatchStatus DBusInterface::Connection::dispatch() {
710 0 : return iface->dbus_connection_dispatch(connection);
711 : }
712 :
713 150 : void DBusInterface::Connection::dispatchAll() {
714 150 : while (iface->dbus_connection_dispatch(connection) == DBUS_DISPATCH_DATA_REMAINS) {
715 : // empty
716 : }
717 150 : }
718 :
719 0 : void DBusInterface::Connection::close() {
720 0 : if (iface && connection) {
721 0 : iface->dbus_connection_close(connection);
722 0 : iface->dbus_connection_unref(connection);
723 0 : connection = nullptr;
724 : }
725 0 : }
726 :
727 125 : void DBusInterface::EventStruct::free(void *obj) {
728 125 : EventStruct *ev = reinterpret_cast<EventStruct *>(obj);
729 125 : switch (ev->type) {
730 0 : case EventType::Watch:
731 0 : break;
732 125 : case EventType::Timeout:
733 125 : ::close(ev->fd);
734 125 : break;
735 : }
736 125 : delete ev;
737 125 : }
738 :
739 125 : void DBusInterface::EventStruct::handle(uint32_t ev) {
740 125 : switch (type) {
741 125 : case EventType::Watch:
742 125 : connection->iface->dbus_watch_handle(watch, DBusInterface_epollToWatchFlags(ev));
743 125 : break;
744 0 : case EventType::Timeout: {
745 0 : auto milliseconds = connection->iface->dbus_timeout_get_interval(timeout);
746 : struct itimerspec initTimer;
747 0 : initTimer.it_interval.tv_nsec = 0;
748 0 : initTimer.it_interval.tv_sec = 0;
749 0 : initTimer.it_value.tv_nsec = (milliseconds % 1000) * 1000 * 1000;
750 0 : initTimer.it_value.tv_sec = milliseconds / 1000;
751 :
752 0 : ::timerfd_settime(fd, 0, &initTimer, nullptr);
753 :
754 0 : connection->iface->dbus_timeout_handle(timeout);
755 0 : break;
756 : }
757 : }
758 125 : }
759 :
760 25 : DBusInterface::DBusInterface() {
761 25 : epollEventFd.data.fd = -1;
762 :
763 : #ifndef XL_LINK
764 25 : handle = Dso("libdbus-1.so");
765 25 : if (!handle) {
766 0 : return;
767 : }
768 : #endif
769 :
770 25 : if (openHandle(handle)) {
771 25 : sessionConnection = new Connection(this, DBUS_BUS_SESSION);
772 25 : if (sessionConnection->connection == nullptr) {
773 0 : delete sessionConnection;
774 0 : sessionConnection = nullptr;
775 : }
776 :
777 25 : systemConnection = new Connection(this, DBUS_BUS_SYSTEM);
778 25 : if (systemConnection->connection == nullptr) {
779 0 : delete systemConnection;
780 0 : systemConnection = nullptr;
781 : }
782 : } else {
783 0 : handle = Dso();
784 : }
785 :
786 25 : if (sessionConnection && systemConnection) {
787 25 : startThread();
788 0 : } else if (handle) {
789 0 : delete sessionConnection;
790 0 : delete systemConnection;
791 : }
792 0 : }
793 :
794 0 : DBusInterface::~DBusInterface() {
795 0 : shouldExit.clear();
796 0 : wakeup();
797 0 : dbusThread.join();
798 0 : if (sessionConnection) {
799 0 : delete sessionConnection;
800 0 : sessionConnection = nullptr;
801 : }
802 0 : if (systemConnection) {
803 0 : delete systemConnection;
804 0 : systemConnection = nullptr;
805 : }
806 0 : }
807 :
808 25 : bool DBusInterface::openHandle(Dso &d) {
809 : #if XL_LINK
810 : this->dbus_error_init = &::dbus_error_init;
811 : this->dbus_error_free = &::dbus_error_free;
812 : this->dbus_message_new_method_call = &::dbus_message_new_method_call;
813 : this->dbus_message_append_args = &::dbus_message_append_args;
814 : this->dbus_message_is_signal = &::dbus_message_is_signal;
815 : this->dbus_message_is_error = &::dbus_message_is_error;
816 : this->dbus_message_unref = &::dbus_message_unref;
817 : this->dbus_message_iter_init = &::dbus_message_iter_init;
818 : this->dbus_message_iter_next = &::dbus_message_iter_next;
819 : this->dbus_message_iter_recurse = &::dbus_message_iter_recurse;
820 : this->dbus_message_iter_get_arg_type = &::dbus_message_iter_get_arg_type;
821 : this->dbus_message_iter_get_basic = &::dbus_message_iter_get_basic;
822 : this->dbus_message_get_type = &::dbus_message_get_type;
823 : this->dbus_message_get_path = &::dbus_message_get_path;
824 : this->dbus_message_get_interface = &::dbus_message_get_interface;
825 : this->dbus_message_get_member = &::dbus_message_get_member;
826 : this->dbus_message_get_error_name = &::dbus_message_get_error_name;
827 : this->dbus_message_get_destination = &::dbus_message_get_destination;
828 : this->dbus_message_get_sender = &::dbus_message_get_sender;
829 : this->dbus_message_get_signature = &::dbus_message_get_signature;
830 : this->dbus_connection_send_with_reply_and_block = &::dbus_connection_send_with_reply_and_block;
831 : this->dbus_connection_send_with_reply = &::dbus_connection_send_with_reply;
832 : this->dbus_connection_set_watch_functions = &::dbus_connection_set_watch_functions;
833 : this->dbus_connection_set_timeout_functions = &::dbus_connection_set_timeout_functions;
834 : this->dbus_connection_set_wakeup_main_function = &::dbus_connection_set_wakeup_main_function;
835 : this->dbus_connection_set_dispatch_status_function = &::dbus_connection_set_dispatch_status_function;
836 : this->dbus_connection_add_filter = &::dbus_connection_add_filter;
837 : this->dbus_connection_close = &::dbus_connection_close;
838 : this->dbus_connection_unref = &::dbus_connection_unref;
839 : this->dbus_connection_flush = &::dbus_connection_flush;
840 : this->dbus_connection_dispatch = &::dbus_connection_dispatch;
841 : this->dbus_error_is_set = &::dbus_error_is_set;
842 : this->dbus_bus_get = &::dbus_bus_get;
843 : this->dbus_bus_get_private = &::dbus_bus_get_private;
844 : this->dbus_bus_add_match = &::dbus_bus_add_match;
845 : this->dbus_pending_call_ref = &::dbus_pending_call_ref;
846 : this->dbus_pending_call_unref = &::dbus_pending_call_unref;
847 : this->dbus_pending_call_set_notify = &::dbus_pending_call_set_notify;
848 : this->dbus_pending_call_get_completed = &::dbus_pending_call_get_completed;
849 : this->dbus_pending_call_steal_reply = &::dbus_pending_call_steal_reply;
850 : this->dbus_pending_call_block = &::dbus_pending_call_block;
851 : this->dbus_watch_get_unix_fd = &::dbus_watch_get_unix_fd;
852 : this->dbus_watch_get_flags = &::dbus_watch_get_flags;
853 : this->dbus_watch_get_data = &::dbus_watch_get_data;
854 : this->dbus_watch_set_data = &::dbus_watch_set_data;
855 : this->dbus_watch_handle = &::dbus_watch_handle;
856 : this->dbus_watch_get_enabled = &::dbus_watch_get_enabled;
857 : this->dbus_timeout_get_interval = &::dbus_timeout_get_interval;
858 : this->dbus_timeout_get_data = &::dbus_timeout_get_data;
859 : this->dbus_timeout_set_data = &::dbus_timeout_set_data;
860 : this->dbus_timeout_handle = &::dbus_timeout_handle;
861 : this->dbus_timeout_get_enabled = &::dbus_timeout_get_enabled;
862 : #else
863 25 : this->dbus_error_init =
864 25 : d.sym<decltype(this->dbus_error_init)>("dbus_error_init");
865 25 : this->dbus_error_free =
866 25 : d.sym<decltype(this->dbus_error_free)>("dbus_error_free");
867 25 : this->dbus_message_new_method_call =
868 25 : d.sym<decltype(this->dbus_message_new_method_call)>("dbus_message_new_method_call");
869 25 : this->dbus_message_append_args =
870 25 : d.sym<decltype(this->dbus_message_append_args)>("dbus_message_append_args");
871 25 : this->dbus_message_is_signal =
872 25 : d.sym<decltype(this->dbus_message_is_signal)>("dbus_message_is_signal");
873 25 : this->dbus_message_is_error =
874 25 : d.sym<decltype(this->dbus_message_is_error)>("dbus_message_is_error");
875 25 : this->dbus_message_unref =
876 25 : d.sym<decltype(this->dbus_message_unref)>("dbus_message_unref");
877 25 : this->dbus_message_iter_init =
878 25 : d.sym<decltype(this->dbus_message_iter_init)>("dbus_message_iter_init");
879 25 : this->dbus_message_iter_next =
880 25 : d.sym<decltype(this->dbus_message_iter_next)>("dbus_message_iter_next");
881 25 : this->dbus_message_iter_recurse =
882 25 : d.sym<decltype(this->dbus_message_iter_recurse)>("dbus_message_iter_recurse");
883 25 : this->dbus_message_iter_get_arg_type =
884 25 : d.sym<decltype(this->dbus_message_iter_get_arg_type)>("dbus_message_iter_get_arg_type");
885 25 : this->dbus_message_iter_get_basic =
886 25 : d.sym<decltype(this->dbus_message_iter_get_basic)>("dbus_message_iter_get_basic");
887 25 : this->dbus_message_get_type =
888 25 : d.sym<decltype(this->dbus_message_get_type)>("dbus_message_get_type");
889 25 : this->dbus_message_get_path =
890 25 : d.sym<decltype(this->dbus_message_get_path)>("dbus_message_get_path");
891 25 : this->dbus_message_get_interface =
892 25 : d.sym<decltype(this->dbus_message_get_interface)>("dbus_message_get_interface");
893 25 : this->dbus_message_get_member =
894 25 : d.sym<decltype(this->dbus_message_get_member)>("dbus_message_get_member");
895 25 : this->dbus_message_get_error_name =
896 25 : d.sym<decltype(this->dbus_message_get_error_name)>("dbus_message_get_error_name");
897 25 : this->dbus_message_get_destination =
898 25 : d.sym<decltype(this->dbus_message_get_destination)>("dbus_message_get_destination");
899 25 : this->dbus_message_get_sender =
900 25 : d.sym<decltype(this->dbus_message_get_sender)>("dbus_message_get_sender");
901 25 : this->dbus_message_get_signature =
902 25 : d.sym<decltype(this->dbus_message_get_signature)>("dbus_message_get_signature");
903 25 : this->dbus_connection_send_with_reply_and_block =
904 25 : d.sym<decltype(this->dbus_connection_send_with_reply_and_block)>("dbus_connection_send_with_reply_and_block");
905 25 : this->dbus_connection_send_with_reply =
906 25 : d.sym<decltype(this->dbus_connection_send_with_reply)>("dbus_connection_send_with_reply");
907 25 : this->dbus_connection_set_watch_functions =
908 25 : d.sym<decltype(this->dbus_connection_set_watch_functions)>("dbus_connection_set_watch_functions");
909 25 : this->dbus_connection_set_timeout_functions =
910 25 : d.sym<decltype(this->dbus_connection_set_timeout_functions)>("dbus_connection_set_timeout_functions");
911 25 : this->dbus_connection_set_wakeup_main_function =
912 25 : d.sym<decltype(this->dbus_connection_set_wakeup_main_function)>("dbus_connection_set_wakeup_main_function");
913 25 : this->dbus_connection_set_dispatch_status_function =
914 25 : d.sym<decltype(this->dbus_connection_set_dispatch_status_function)>("dbus_connection_set_dispatch_status_function");
915 25 : this->dbus_connection_add_filter =
916 25 : d.sym<decltype(this->dbus_connection_add_filter)>("dbus_connection_add_filter");
917 25 : this->dbus_connection_close =
918 25 : d.sym<decltype(this->dbus_connection_close)>("dbus_connection_close");
919 25 : this->dbus_connection_unref =
920 25 : d.sym<decltype(this->dbus_connection_unref)>("dbus_connection_unref");
921 25 : this->dbus_connection_flush =
922 25 : d.sym<decltype(this->dbus_connection_flush)>("dbus_connection_flush");
923 25 : this->dbus_connection_dispatch =
924 25 : d.sym<decltype(this->dbus_connection_dispatch)>("dbus_connection_dispatch");
925 25 : this->dbus_error_is_set =
926 25 : d.sym<decltype(this->dbus_error_is_set)>("dbus_error_is_set");
927 25 : this->dbus_bus_get =
928 25 : d.sym<decltype(this->dbus_bus_get)>("dbus_bus_get");
929 25 : this->dbus_bus_get_private =
930 25 : d.sym<decltype(this->dbus_bus_get_private)>("dbus_bus_get_private");
931 25 : this->dbus_bus_add_match =
932 25 : d.sym<decltype(this->dbus_bus_add_match)>("dbus_bus_add_match");
933 25 : this->dbus_pending_call_ref =
934 25 : d.sym<decltype(this->dbus_pending_call_ref)>("dbus_pending_call_ref");
935 25 : this->dbus_pending_call_unref =
936 25 : d.sym<decltype(this->dbus_pending_call_unref)>("dbus_pending_call_unref");
937 25 : this->dbus_pending_call_set_notify =
938 25 : d.sym<decltype(this->dbus_pending_call_set_notify)>("dbus_pending_call_set_notify");
939 25 : this->dbus_pending_call_get_completed =
940 25 : d.sym<decltype(this->dbus_pending_call_get_completed)>("dbus_pending_call_get_completed");
941 25 : this->dbus_pending_call_steal_reply =
942 25 : d.sym<decltype(this->dbus_pending_call_steal_reply)>("dbus_pending_call_steal_reply");
943 25 : this->dbus_pending_call_block =
944 25 : d.sym<decltype(this->dbus_pending_call_block)>("dbus_pending_call_block");
945 25 : this->dbus_watch_get_unix_fd =
946 25 : d.sym<decltype(this->dbus_watch_get_unix_fd)>("dbus_watch_get_unix_fd");
947 25 : this->dbus_watch_get_flags =
948 25 : d.sym<decltype(this->dbus_watch_get_flags)>("dbus_watch_get_flags");
949 25 : this->dbus_watch_get_data =
950 25 : d.sym<decltype(this->dbus_watch_get_data)>("dbus_watch_get_data");
951 25 : this->dbus_watch_set_data =
952 25 : d.sym<decltype(this->dbus_watch_set_data)>("dbus_watch_set_data");
953 25 : this->dbus_watch_handle =
954 25 : d.sym<decltype(this->dbus_watch_handle)>("dbus_watch_handle");
955 25 : this->dbus_watch_get_enabled =
956 25 : d.sym<decltype(this->dbus_watch_get_enabled)>("dbus_watch_get_enabled");
957 25 : this->dbus_timeout_get_interval =
958 25 : d.sym<decltype(this->dbus_timeout_get_interval)>("dbus_timeout_get_interval");
959 25 : this->dbus_timeout_get_data =
960 25 : d.sym<decltype(this->dbus_timeout_get_data)>("dbus_timeout_get_data");
961 25 : this->dbus_timeout_set_data =
962 25 : d.sym<decltype(this->dbus_timeout_set_data)>("dbus_timeout_set_data");
963 25 : this->dbus_timeout_handle =
964 25 : d.sym<decltype(this->dbus_timeout_handle)>("dbus_timeout_handle");
965 25 : this->dbus_timeout_get_enabled =
966 25 : d.sym<decltype(this->dbus_timeout_get_enabled)>("dbus_timeout_get_enabled");
967 : #endif
968 :
969 25 : return this->dbus_error_init
970 25 : && this->dbus_error_free
971 25 : && this->dbus_message_new_method_call
972 25 : && this->dbus_message_append_args
973 25 : && this->dbus_message_unref
974 25 : && this->dbus_message_iter_init
975 25 : && this->dbus_message_iter_next
976 25 : && this->dbus_message_iter_recurse
977 25 : && this->dbus_message_iter_get_arg_type
978 25 : && this->dbus_message_iter_get_basic
979 25 : && this->dbus_message_get_type
980 25 : && this->dbus_message_get_path
981 25 : && this->dbus_message_get_interface
982 25 : && this->dbus_message_get_member
983 25 : && this->dbus_message_get_error_name
984 25 : && this->dbus_message_get_destination
985 25 : && this->dbus_message_get_sender
986 25 : && this->dbus_message_get_signature
987 25 : && this->dbus_connection_send_with_reply_and_block
988 25 : && this->dbus_connection_send_with_reply
989 25 : && this->dbus_connection_set_watch_functions
990 25 : && this->dbus_connection_set_timeout_functions
991 25 : && this->dbus_connection_set_wakeup_main_function
992 25 : && this->dbus_connection_set_dispatch_status_function
993 25 : && this->dbus_connection_add_filter
994 25 : && this->dbus_connection_close
995 25 : && this->dbus_connection_unref
996 25 : && this->dbus_connection_flush
997 25 : && this->dbus_connection_dispatch
998 25 : && this->dbus_error_is_set
999 25 : && this->dbus_bus_get
1000 25 : && this->dbus_bus_get_private
1001 25 : && this->dbus_bus_add_match
1002 25 : && this->dbus_pending_call_ref
1003 25 : && this->dbus_pending_call_unref
1004 25 : && this->dbus_pending_call_set_notify
1005 25 : && this->dbus_pending_call_get_completed
1006 25 : && this->dbus_pending_call_steal_reply
1007 25 : && this->dbus_watch_get_unix_fd
1008 25 : && this->dbus_watch_get_flags
1009 25 : && this->dbus_watch_get_data
1010 25 : && this->dbus_watch_set_data
1011 25 : && this->dbus_watch_handle
1012 25 : && this->dbus_watch_get_enabled
1013 25 : && this->dbus_timeout_get_interval
1014 25 : && this->dbus_timeout_get_data
1015 25 : && this->dbus_timeout_set_data
1016 25 : && this->dbus_timeout_handle
1017 50 : && this->dbus_timeout_get_enabled;
1018 : }
1019 :
1020 25 : bool DBusInterface::startThread() {
1021 25 : shouldExit.test_and_set();
1022 25 : dbusThread = std::thread(DBusInterface::workerThread, this, nullptr);
1023 25 : return true;
1024 : }
1025 :
1026 25 : void DBusInterface::threadInit() {
1027 25 : thread::ThreadInfo::setThreadInfo("DBusThread");
1028 :
1029 25 : eventFd = ::eventfd(0, EFD_NONBLOCK);
1030 25 : epollEventFd.events = EPOLLIN | EPOLLET | EPOLLEXCLUSIVE;
1031 25 : epollEventFd.data.ptr = this;
1032 :
1033 25 : epollFd = ::epoll_create1(0);
1034 :
1035 25 : int err = ::epoll_ctl(epollFd, EPOLL_CTL_ADD, eventFd, &epollEventFd);
1036 25 : if (err == -1) {
1037 0 : char buf[256] = { 0 };
1038 0 : log::error("DBusInterface", "Fail to add eventFd with EPOLL_CTL_ADD: ", strerror_r(errno, buf, 255));
1039 : }
1040 :
1041 25 : sessionConnection->setup();
1042 25 : systemConnection->setup();
1043 :
1044 25 : addEvent([this] {
1045 25 : loadServiceNames(*sessionConnection, sessionServices, [this] {
1046 25 : log::verbose("DBusInterface", "Session bus loaded");
1047 25 : if (sessionServices.find("org.freedesktop.portal.Desktop") != sessionServices.end()) {
1048 25 : hasDesktopPortal = true;
1049 25 : readInterfaceTheme([this] (InterfaceThemeInfo &&theme) {
1050 25 : std::unique_lock lock(interfaceMutex);
1051 25 : interfaceTheme = move(theme);
1052 25 : interfaceLoaded = true;
1053 25 : interfaceCondvar.notify_all();
1054 25 : });
1055 : } else {
1056 0 : std::unique_lock lock(interfaceMutex);
1057 0 : interfaceLoaded = true;
1058 0 : interfaceCondvar.notify_all();
1059 0 : }
1060 25 : });
1061 25 : });
1062 :
1063 25 : addEvent([this] {
1064 25 : loadServiceNames(*systemConnection, systemServices, [this] {
1065 25 : log::verbose("DBusInterface", "System bus loaded");
1066 25 : if (systemServices.find("org.freedesktop.NetworkManager") != systemServices.end()) {
1067 25 : Error error(this);
1068 25 : hasNetworkManager = true;
1069 25 : dbus_bus_add_match(systemConnection->connection, "type='signal',interface='"
1070 : NM_DBUS_INTERFACE_NAME "'", &error.error);
1071 : // see signals from the given interface
1072 25 : systemConnection->flush();
1073 25 : if (error.isSet()) {
1074 0 : log::error("DBusConnection", "fail to add signal match: ", error.error.message);
1075 : }
1076 :
1077 25 : updateNetworkState(*systemConnection, [this] (NetworkState &&state) {
1078 25 : setNetworkState(move(state));
1079 25 : });
1080 25 : }
1081 25 : });
1082 25 : });
1083 25 : }
1084 :
1085 0 : void DBusInterface::threadDispose() {
1086 0 : if (eventFd >= 0) {
1087 0 : ::close(eventFd);
1088 0 : eventFd = -1;
1089 : }
1090 0 : if (epollFd >= 0) {
1091 0 : ::close(epollFd);
1092 0 : epollFd = -1;
1093 : }
1094 0 : }
1095 :
1096 25 : bool DBusInterface::worker() {
1097 : std::array<struct epoll_event, 16> _events;
1098 :
1099 21502 : while (shouldExit.test_and_set()) {
1100 10751 : int nevents = epoll_wait(epollFd, _events.data(), 16, 100);
1101 10726 : if (nevents == -1 && errno != EINTR) {
1102 0 : char buf[256] = { 0 };
1103 0 : log::error("DBusConnection", "epoll_wait() failed with errno ", errno, " (", strerror_r(errno, buf, 255), ")");
1104 0 : break;
1105 10726 : } else if (errno == EINTR) {
1106 0 : continue;
1107 : }
1108 :
1109 11008 : for (int i = 0; i < nevents; i++) {
1110 282 : if (_events[i].data.ptr == this && (_events[i].events & EPOLLIN)) {
1111 : // wakeup trigger
1112 157 : handleEvents();
1113 : } else {
1114 125 : EventStruct *event = reinterpret_cast<EventStruct *>(_events[i].data.ptr);
1115 125 : event->handle(_events[i].events);
1116 : }
1117 : }
1118 : }
1119 0 : return false;
1120 : }
1121 :
1122 125 : void DBusInterface::wakeup() {
1123 125 : addEvent([] () {}); // add empty function for event
1124 125 : }
1125 :
1126 350 : void DBusInterface::addEvent(Function<void()> &&ev) {
1127 350 : std::unique_lock lock(eventMutex);
1128 350 : events.emplace_back(move(ev));
1129 350 : lock.unlock();
1130 :
1131 350 : uint64_t value = 1;
1132 350 : ::write(eventFd, &value, sizeof(uint64_t));
1133 350 : }
1134 :
1135 175 : void DBusInterface::addEvent(EventStruct *ev) {
1136 175 : int err = ::epoll_ctl(epollFd, EPOLL_CTL_ADD, ev->fd, &ev->event);
1137 175 : if (err == -1) {
1138 0 : char buf[256] = { 0 };
1139 0 : log::error("DBusInterface", "Fail to add event with EPOLL_CTL_ADD: ", strerror_r(errno, buf, 255));
1140 : }
1141 175 : }
1142 :
1143 0 : void DBusInterface::updateEvent(EventStruct *ev) {
1144 0 : int err = ::epoll_ctl(epollFd, EPOLL_CTL_MOD, ev->fd, &ev->event);
1145 0 : if (err == -1) {
1146 0 : char buf[256] = { 0 };
1147 0 : log::error("DBusInterface", "Fail to add event with EPOLL_CTL_ADD: ", strerror_r(errno, buf, 255));
1148 : }
1149 0 : }
1150 :
1151 0 : void DBusInterface::removeEvent(EventStruct *ev) {
1152 0 : int err = ::epoll_ctl(epollFd, EPOLL_CTL_DEL, ev->fd, &ev->event);
1153 0 : if (err == -1) {
1154 0 : char buf[256] = { 0 };
1155 0 : log::error("DBusInterface", "Fail to add event with EPOLL_CTL_ADD: ", strerror_r(errno, buf, 255));
1156 : }
1157 0 : }
1158 :
1159 157 : void DBusInterface::handleEvents() {
1160 157 : uint64_t value = 0;
1161 157 : auto sz = ::read(eventFd, &value, sizeof(uint64_t));
1162 157 : if (sz == 8 && value) {
1163 157 : std::unique_lock lock(eventMutex);
1164 157 : auto data = move(events);
1165 157 : events.clear();
1166 157 : lock.unlock();
1167 :
1168 507 : for (auto &it : data) {
1169 350 : it();
1170 : }
1171 157 : }
1172 157 : }
1173 :
1174 50 : DBusHandlerResult DBusInterface::handleMessage(Connection *, DBusMessage *message) {
1175 50 : auto type = DBusMessageTypeWrapper(dbus_message_get_type(message));
1176 50 : if (dbus_message_is_signal(message, NM_DBUS_INTERFACE_NAME, NM_DBUS_SIGNAL_STATE_CHANGED)) {
1177 0 : return handleNetworkStateChanged(message);
1178 50 : } else if (type == DBUS_MESSAGE_TYPE_ERROR) {
1179 0 : log::verbose("DBusInterface", "DBUS_MESSAGE_TYPE_ERROR");
1180 : }
1181 50 : return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1182 : }
1183 :
1184 0 : DBusHandlerResult DBusInterface::handleNetworkStateChanged(DBusMessage *message) {
1185 0 : updateNetworkState(*systemConnection, [this] (NetworkState &&state) {
1186 0 : setNetworkState(move(state));
1187 0 : });
1188 0 : return DBUS_HANDLER_RESULT_HANDLED;
1189 : }
1190 :
1191 25 : DBusPendingCall *DBusInterface::readInterfaceTheme(Function<void(InterfaceThemeInfo &&)> &&cb) {
1192 50 : return callMethod(*sessionConnection, "org.freedesktop.portal.Desktop",
1193 : "/org/freedesktop/portal/desktop", "org.freedesktop.portal.Settings", "ReadAll",
1194 25 : [&, this] (DBusMessage *message) {
1195 25 : const char * array[] = { "org.gnome.desktop.interface" };
1196 25 : const char **v_ARRAY = array;
1197 :
1198 25 : dbus_message_append_args(message,
1199 : DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &v_ARRAY, 1, DBUS_TYPE_INVALID);
1200 50 : }, [this, cb = move(cb)] (DBusMessage *reply) {
1201 25 : cb(parseInterfaceThemeSettings(reply));
1202 75 : });
1203 : }
1204 :
1205 25 : DBusPendingCall *DBusInterface::updateNetworkState(Connection &c, Function<void(NetworkState &&)> &&cb) {
1206 50 : return callMethod(c, "org.freedesktop.NetworkManager",
1207 : "/org/freedesktop/NetworkManager", "org.freedesktop.DBus.Properties", "GetAll",
1208 25 : [this] (DBusMessage *msg) {
1209 25 : const char *interface_name = "org.freedesktop.NetworkManager";
1210 25 : dbus_message_append_args(msg, DBUS_TYPE_STRING, &interface_name, DBUS_TYPE_INVALID);
1211 50 : }, [this, cb = move(cb)] (DBusMessage *reply) {
1212 25 : cb(parseNetworkState(reply));
1213 75 : });
1214 : }
1215 :
1216 0 : DBusMessage *DBusInterface::getSettingSync(Connection &c, const char *key, const char *value, Error &err) {
1217 : dbus_bool_t success;
1218 : DBusMessage *message;
1219 : DBusMessage *reply;
1220 :
1221 0 : message = this->dbus_message_new_method_call("org.freedesktop.portal.Desktop",
1222 : "/org/freedesktop/portal/desktop", "org.freedesktop.portal.Settings", "Read");
1223 :
1224 0 : success = this->dbus_message_append_args(message, DBUS_TYPE_STRING, &key, DBUS_TYPE_STRING, &value, DBUS_TYPE_INVALID);
1225 :
1226 0 : if (!success) {
1227 0 : return NULL;
1228 : }
1229 :
1230 0 : reply = this->dbus_connection_send_with_reply_and_block(c.connection, message, DBUS_TIMEOUT_USE_DEFAULT, &err.error);
1231 :
1232 0 : this->dbus_message_unref(message);
1233 :
1234 0 : if (err.isSet()) {
1235 0 : return NULL;
1236 : }
1237 :
1238 0 : return reply;
1239 : }
1240 :
1241 0 : bool DBusInterface::parseType(DBusMessage *const reply, const int type, void *value) {
1242 : DBusTypeWrapper currentType;
1243 : DBusMessageIter iter[3];
1244 :
1245 0 : this->dbus_message_iter_init(reply, &iter[0]);
1246 0 : currentType = DBusTypeWrapper(this->dbus_message_iter_get_arg_type(&iter[0]));
1247 0 : if (currentType != DBUS_TYPE_VARIANT)
1248 0 : return false;
1249 :
1250 0 : this->dbus_message_iter_recurse(&iter[0], &iter[1]);
1251 0 : currentType = DBusTypeWrapper(this->dbus_message_iter_get_arg_type(&iter[1]));
1252 0 : if (currentType != DBUS_TYPE_VARIANT)
1253 0 : return false;
1254 :
1255 0 : this->dbus_message_iter_recurse(&iter[1], &iter[2]);
1256 0 : currentType = DBusTypeWrapper(this->dbus_message_iter_get_arg_type(&iter[2]));
1257 0 : if (currentType != type)
1258 0 : return false;
1259 :
1260 0 : this->dbus_message_iter_get_basic(&iter[2], value);
1261 :
1262 0 : return true;
1263 : }
1264 :
1265 : struct MessageData {
1266 : DBusInterface *interface;
1267 : DBusInterface::Connection *connection;
1268 : Function<void(DBusMessage *)> callback;
1269 :
1270 100 : static void parseReply(DBusPendingCall *pending, void *user_data) {
1271 100 : auto data = reinterpret_cast<MessageData *>(user_data);
1272 :
1273 100 : if (data->interface->dbus_pending_call_get_completed(pending)) {
1274 100 : auto reply = data->interface->dbus_pending_call_steal_reply(pending);
1275 100 : if (reply) {
1276 :
1277 100 : if (data->callback) {
1278 100 : data->callback(reply);
1279 : }
1280 100 : data->interface->dbus_message_unref(reply);
1281 : }
1282 : }
1283 :
1284 100 : data->interface->dbus_pending_call_unref(pending);
1285 100 : }
1286 :
1287 100 : static void freeMessage(void *user_data) {
1288 100 : auto data = reinterpret_cast<MessageData *>(user_data);
1289 100 : delete data;
1290 100 : }
1291 : };
1292 :
1293 50 : DBusPendingCall *DBusInterface::loadServiceNames(Connection &c, Set<String> &services, Function<void()> &&cb) {
1294 100 : return callMethod(c, "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "ListNames",
1295 50 : nullptr, [this, services = &services, cb = move(cb)] (DBusMessage *reply) {
1296 50 : parseServiceList(*services, reply);
1297 50 : cb();
1298 100 : });
1299 : }
1300 :
1301 100 : DBusPendingCall *DBusInterface::callMethod(Connection &c, StringView bus, StringView path, StringView iface, StringView method,
1302 : const Callback<void(DBusMessage *)> &argsCallback, Function<void(DBusMessage *)> &&resultCallback) {
1303 100 : DBusPendingCall *ret = nullptr;
1304 :
1305 100 : auto message = this->dbus_message_new_method_call(bus.data(),
1306 : path.data(), iface.data(), method.data());
1307 :
1308 100 : if (argsCallback) {
1309 50 : argsCallback(message);
1310 : }
1311 :
1312 100 : auto success = this->dbus_connection_send_with_reply(c.connection, message, &ret, DBUS_TIMEOUT_USE_DEFAULT);
1313 100 : this->dbus_message_unref(message);
1314 :
1315 100 : if (success && ret) {
1316 100 : auto data = new MessageData;
1317 100 : data->interface = this;
1318 100 : data->connection = &c;
1319 100 : data->callback = move(resultCallback);
1320 :
1321 100 : this->dbus_pending_call_set_notify(ret, MessageData::parseReply, data, MessageData::freeMessage);
1322 100 : c.flush();
1323 : }
1324 100 : return ret;
1325 : }
1326 :
1327 50 : void DBusInterface::parseServiceList(Set<String> &services, DBusMessage *reply) {
1328 50 : DBusTypeWrapper current_type = DBUS_TYPE_INVALID;
1329 : DBusMessageIter iter;
1330 :
1331 50 : dbus_message_iter_init(reply, &iter);
1332 100 : while ((current_type = DBusTypeWrapper(dbus_message_iter_get_arg_type(&iter))) != DBUS_TYPE_INVALID) {
1333 50 : if (current_type == DBUS_TYPE_ARRAY) {
1334 50 : DBusTypeWrapper sub_type = DBUS_TYPE_INVALID;
1335 : DBusMessageIter sub;
1336 50 : dbus_message_iter_recurse(&iter, &sub);
1337 6935 : while ((sub_type = DBusTypeWrapper(dbus_message_iter_get_arg_type(&sub))) != DBUS_TYPE_INVALID) {
1338 6885 : if (sub_type == DBUS_TYPE_STRING) {
1339 6885 : char *str = nullptr;
1340 6885 : dbus_message_iter_get_basic(&sub, &str);
1341 6885 : if (str && *str != ':') {
1342 2795 : services.emplace(str);
1343 : }
1344 : }
1345 6885 : dbus_message_iter_next(&sub);
1346 : }
1347 : }
1348 50 : dbus_message_iter_next(&iter);
1349 : }
1350 50 : }
1351 :
1352 25 : NetworkState DBusInterface::parseNetworkState(DBusMessage *reply) {
1353 25 : NetworkState ret;
1354 :
1355 1425 : auto readEntry = [&, this] (DBusMessageIter *entry) {
1356 600 : DBusTypeWrapper entry_type = DBusTypeWrapper(dbus_message_iter_get_arg_type(entry));
1357 :
1358 600 : if (entry_type == DBUS_TYPE_STRING) {
1359 600 : char *name = nullptr;
1360 600 : dbus_message_iter_get_basic(entry, &name);
1361 600 : StringView prop(name);
1362 600 : if (prop == "NetworkingEnabled") {
1363 25 : uint32_t value = 0;
1364 25 : if (parseProperty(entry, &value)) {
1365 25 : ret.networkingEnabled = value ? true : false;
1366 : }
1367 575 : } else if (prop == "WirelessEnabled") {
1368 25 : uint32_t value = 0;
1369 25 : if (parseProperty(entry, &value)) {
1370 25 : ret.wirelessEnabled = value ? true : false;
1371 : }
1372 550 : } else if (prop == "WwanEnabled") {
1373 25 : uint32_t value = 0;
1374 25 : if (parseProperty(entry, &value)) {
1375 25 : ret.wwanEnabled = value ? true : false;
1376 : }
1377 525 : } else if (prop == "WimaxEnabled") {
1378 25 : uint32_t value = 0;
1379 25 : if (parseProperty(entry, &value)) {
1380 25 : ret.wimaxEnabled = value ? true : false;
1381 : }
1382 500 : } else if (prop == "PrimaryConnectionType") {
1383 25 : char *value = nullptr;
1384 25 : if (parseProperty(entry, &value)) {
1385 25 : ret.primaryConnectionType = String(value);
1386 : }
1387 475 : } else if (prop == "Metered") {
1388 25 : uint32_t value = 0;
1389 25 : if (parseProperty(entry, &value)) {
1390 25 : ret.metered = NMMetered(value);
1391 : }
1392 450 : } else if (prop == "State") {
1393 25 : uint32_t value = 0;
1394 25 : if (parseProperty(entry, &value)) {
1395 25 : ret.state = NMState(value);
1396 : }
1397 425 : } else if (prop == "Connectivity") {
1398 25 : uint32_t value = 0;
1399 25 : if (parseProperty(entry, &value)) {
1400 25 : ret.connectivity = NMConnectivityState(value);
1401 : }
1402 400 : } else if (prop == "Capabilities") {
1403 25 : Vector<uint32_t> value;
1404 25 : if (parseProperty(entry, &value)) {
1405 25 : ret.capabilities = move(value);
1406 : }
1407 25 : }
1408 : }
1409 600 : };
1410 :
1411 25 : DBusTypeWrapper current_type = DBUS_TYPE_INVALID;
1412 : DBusMessageIter iter;
1413 :
1414 25 : dbus_message_iter_init(reply, &iter);
1415 50 : while ((current_type = DBusTypeWrapper(dbus_message_iter_get_arg_type(&iter))) != DBUS_TYPE_INVALID) {
1416 25 : if (current_type == DBUS_TYPE_ARRAY) {
1417 25 : DBusTypeWrapper sub_type = DBUS_TYPE_INVALID;
1418 : DBusMessageIter sub;
1419 25 : dbus_message_iter_recurse(&iter, &sub);
1420 625 : while ((sub_type = DBusTypeWrapper(dbus_message_iter_get_arg_type(&sub))) != DBUS_TYPE_INVALID) {
1421 600 : if (sub_type == DBUS_TYPE_DICT_ENTRY) {
1422 : DBusMessageIter entry;
1423 600 : dbus_message_iter_recurse(&sub, &entry);
1424 600 : readEntry(&entry);
1425 : }
1426 600 : dbus_message_iter_next(&sub);
1427 : }
1428 : }
1429 25 : dbus_message_iter_next(&iter);
1430 : }
1431 :
1432 50 : return ret;
1433 0 : }
1434 :
1435 25 : InterfaceThemeInfo DBusInterface::parseInterfaceThemeSettings(DBusMessage *reply) {
1436 25 : InterfaceThemeInfo ret;
1437 :
1438 4400 : auto readEntry = [&, this] (DBusMessageIter *entry) {
1439 2150 : DBusTypeWrapper entry_type = DBusTypeWrapper(dbus_message_iter_get_arg_type(entry));
1440 :
1441 2150 : if (entry_type == DBUS_TYPE_STRING) {
1442 2150 : char *name = nullptr;
1443 2150 : dbus_message_iter_get_basic(entry, &name);
1444 2150 : StringView prop(name);
1445 2150 : if (prop == "cursor-size") {
1446 50 : uint32_t value = 0;
1447 50 : if (parseProperty(entry, &value)) {
1448 0 : ret.cursorSize = value;
1449 : }
1450 2100 : } else if (prop == "cursor-theme") {
1451 50 : char *value = nullptr;
1452 50 : if (parseProperty(entry, &value)) {
1453 50 : ret.cursorTheme = value;
1454 : }
1455 : }
1456 : }
1457 2150 : };
1458 :
1459 6750 : auto readNamespaceEntry = [&, this] (DBusMessageIter *entry) {
1460 50 : DBusTypeWrapper entry_type = DBusTypeWrapper(dbus_message_iter_get_arg_type(entry));
1461 :
1462 50 : if (entry_type == DBUS_TYPE_STRING) {
1463 50 : char *name = nullptr;
1464 50 : dbus_message_iter_get_basic(entry, &name);
1465 50 : StringView prop(name);
1466 50 : if (prop == "org.gnome.desktop.interface") {
1467 50 : dbus_message_iter_next(entry);
1468 50 : if (DBusTypeWrapper(dbus_message_iter_get_arg_type(entry)) == DBUS_TYPE_ARRAY) {
1469 50 : DBusTypeWrapper sub_type = DBUS_TYPE_INVALID;
1470 : DBusMessageIter sub;
1471 50 : dbus_message_iter_recurse(entry, &sub);
1472 2200 : while ((sub_type = DBusTypeWrapper(dbus_message_iter_get_arg_type(&sub))) != DBUS_TYPE_INVALID) {
1473 2150 : if (sub_type == DBUS_TYPE_DICT_ENTRY) {
1474 : DBusMessageIter dict;
1475 2150 : dbus_message_iter_recurse(&sub, &dict);
1476 2150 : readEntry(&dict);
1477 : }
1478 2150 : dbus_message_iter_next(&sub);
1479 : }
1480 : }
1481 : }
1482 : }
1483 50 : };
1484 :
1485 25 : DBusTypeWrapper current_type = DBUS_TYPE_INVALID;
1486 : DBusMessageIter iter;
1487 :
1488 25 : dbus_message_iter_init(reply, &iter);
1489 50 : while ((current_type = DBusTypeWrapper(dbus_message_iter_get_arg_type(&iter))) != DBUS_TYPE_INVALID) {
1490 25 : if (current_type == DBUS_TYPE_ARRAY) {
1491 25 : DBusTypeWrapper sub_type = DBUS_TYPE_INVALID;
1492 : DBusMessageIter sub;
1493 25 : dbus_message_iter_recurse(&iter, &sub);
1494 75 : while ((sub_type = DBusTypeWrapper(dbus_message_iter_get_arg_type(&sub))) != DBUS_TYPE_INVALID) {
1495 50 : if (sub_type == DBUS_TYPE_DICT_ENTRY) {
1496 : DBusMessageIter entry;
1497 50 : dbus_message_iter_recurse(&sub, &entry);
1498 50 : readNamespaceEntry(&entry);
1499 : }
1500 50 : dbus_message_iter_next(&sub);
1501 : }
1502 : }
1503 25 : dbus_message_iter_next(&iter);
1504 : }
1505 :
1506 50 : return ret;
1507 0 : }
1508 :
1509 325 : bool DBusInterface::parseProperty(DBusMessageIter *entry, void *value, DBusTypeWrapper expectedType) {
1510 325 : dbus_message_iter_next(entry);
1511 325 : DBusTypeWrapper type = DBusTypeWrapper(dbus_message_iter_get_arg_type(entry));
1512 325 : if (type == DBUS_TYPE_VARIANT) {
1513 : DBusMessageIter prop;
1514 325 : dbus_message_iter_recurse(entry, &prop);
1515 325 : DBusTypeWrapper propType = DBusTypeWrapper(dbus_message_iter_get_arg_type(&prop));
1516 325 : if (expectedType == DBUS_TYPE_INVALID || expectedType == propType) {
1517 325 : switch (propType) {
1518 250 : case DBUS_TYPE_BOOLEAN:
1519 : case DBUS_TYPE_STRING:
1520 : case DBUS_TYPE_UINT32:
1521 250 : dbus_message_iter_get_basic(&prop, value);
1522 275 : return true;
1523 : break;
1524 25 : case DBUS_TYPE_ARRAY: {
1525 25 : DBusTypeWrapper sub_type = DBUS_TYPE_INVALID;
1526 : DBusMessageIter sub;
1527 25 : dbus_message_iter_recurse(&prop, &sub);
1528 50 : while ((sub_type = DBusTypeWrapper(dbus_message_iter_get_arg_type(&sub))) != DBUS_TYPE_INVALID) {
1529 25 : auto target = reinterpret_cast<Vector<uint32_t> *>(value);
1530 25 : switch (sub_type) {
1531 25 : case DBUS_TYPE_UINT32: {
1532 25 : uint32_t type = 0;
1533 25 : dbus_message_iter_get_basic(&sub, &type);
1534 25 : target->emplace_back(type);
1535 25 : break;
1536 : }
1537 0 : default:
1538 0 : break;
1539 : }
1540 25 : dbus_message_iter_next(&sub);
1541 : }
1542 25 : return true;
1543 : break;
1544 : }
1545 50 : default:
1546 50 : break;
1547 : }
1548 : }
1549 : }
1550 50 : return false;
1551 : }
1552 :
1553 25 : void DBusInterface::setNetworkState(NetworkState &&state) {
1554 25 : if (networkState != state) {
1555 25 : networkState = move(state);
1556 : #if DEBUG
1557 25 : log::debug("DBusInterface", "Network: ", networkState.description());
1558 : #endif
1559 : }
1560 25 : }
1561 :
1562 25 : void DBusInterface::addNetworkConnectionCallback(void *key, Function<void(const NetworkState &)> &&cb) {
1563 25 : addEvent([this, cb = move(cb), key] () mutable {
1564 25 : cb(networkState);
1565 25 : networkCallbacks.emplace(key, StateCallback{move(cb), this});
1566 25 : });
1567 25 : }
1568 :
1569 0 : void DBusInterface::removeNetworkConnectionCallback(void *key) {
1570 0 : addEvent([this, key] () mutable {
1571 0 : auto refId = retain();
1572 0 : networkCallbacks.erase(key);
1573 0 : release(refId);
1574 0 : });
1575 0 : }
1576 :
1577 25 : String NetworkState::description() const {
1578 25 : StringStream out;
1579 25 : out << primaryConnectionType << ": ( ";
1580 25 : if (networkingEnabled) {
1581 25 : out << "networking ";
1582 : }
1583 25 : if (wirelessEnabled) {
1584 0 : out << "wireless ";
1585 : }
1586 25 : if (wwanEnabled) {
1587 25 : out << "wwan ";
1588 : }
1589 25 : if (wimaxEnabled) {
1590 0 : out << "wimax ";
1591 : }
1592 25 : out << ")";
1593 :
1594 25 : switch (connectivity) {
1595 0 : case NM_CONNECTIVITY_UNKNOWN: out << " NM_CONNECTIVITY_UNKNOWN"; break;
1596 0 : case NM_CONNECTIVITY_NONE: out << " NM_CONNECTIVITY_NONE"; break;
1597 0 : case NM_CONNECTIVITY_PORTAL: out << " NM_CONNECTIVITY_PORTAL"; break;
1598 25 : case NM_CONNECTIVITY_LIMITED: out << " NM_CONNECTIVITY_LIMITED"; break;
1599 0 : case NM_CONNECTIVITY_FULL: out << " NM_CONNECTIVITY_FULL"; break;
1600 : }
1601 :
1602 25 : switch (state) {
1603 0 : case NM_STATE_UNKNOWN: out << " NM_STATE_UNKNOWN"; break;
1604 0 : case NM_STATE_ASLEEP: out << " NM_STATE_ASLEEP"; break;
1605 0 : case NM_STATE_DISCONNECTED: out << " NM_STATE_DISCONNECTED"; break;
1606 0 : case NM_STATE_DISCONNECTING: out << " NM_STATE_DISCONNECTING"; break;
1607 0 : case NM_STATE_CONNECTING: out << " NM_STATE_CONNECTING"; break;
1608 0 : case NM_STATE_CONNECTED_LOCAL: out << " NM_STATE_CONNECTED_LOCAL"; break;
1609 0 : case NM_STATE_CONNECTED_SITE: out << " NM_STATE_CONNECTED_SITE"; break;
1610 25 : case NM_STATE_CONNECTED_GLOBAL: out << " NM_STATE_CONNECTED_GLOBAL"; break;
1611 : }
1612 :
1613 25 : switch (metered) {
1614 0 : case NM_METERED_UNKNOWN: out << " NM_METERED_UNKNOWN"; break;
1615 0 : case NM_METERED_YES: out << " NM_METERED_YES"; break;
1616 0 : case NM_METERED_GUESS_YES: out << " NM_METERED_GUESS_YES"; break;
1617 0 : case NM_METERED_NO: out << " NM_METERED_NO"; break;
1618 25 : case NM_METERED_GUESS_NO: out << " NM_METERED_GUESS_NO"; break;
1619 : }
1620 :
1621 25 : if (!capabilities.empty()) {
1622 25 : out << " ( ";
1623 50 : for (auto &it : capabilities) {
1624 25 : out << it << " ";
1625 : }
1626 25 : out << ")";
1627 : }
1628 50 : return out.str();
1629 25 : }
1630 :
1631 25 : DBusLibrary DBusLibrary::get() {
1632 25 : return DBusLibrary(s_connection.get());
1633 : }
1634 :
1635 0 : bool DBusLibrary::isAvailable() const {
1636 0 : return _connection->sessionConnection && _connection->systemConnection;
1637 : }
1638 :
1639 0 : InterfaceThemeInfo DBusLibrary::getCurrentInterfaceTheme() const {
1640 0 : return _connection->getCurrentTheme();
1641 : }
1642 :
1643 25 : void DBusLibrary::addNetworkConnectionCallback(void *key, Function<void(const NetworkState &)> &&cb) {
1644 25 : _connection->addNetworkConnectionCallback(key, move(cb));
1645 25 : }
1646 :
1647 0 : void DBusLibrary::removeNetworkConnectionCallback(void *key) {
1648 0 : _connection->removeNetworkConnectionCallback(key);
1649 0 : }
1650 :
1651 25 : DBusLibrary::DBusLibrary(DBusInterface *c) : _connection(c) { }
1652 :
1653 : }
|