LCOV - code coverage report
Current view: top level - xenolith/platform/linux - XLPlatformLinuxDbus.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 617 825 74.8 %
Date: 2024-05-12 00:16:13 Functions: 66 92 71.7 %

          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             : }

Generated by: LCOV version 1.14