[RFC,spice-vdagent,13/18] systemd-login: use GDBus

Submitted by Jakub Janku on Aug. 14, 2018, 6:53 p.m.

Details

Message ID 20180814185352.6080-14-jjanku@redhat.com
State New
Headers show
Series "GLib integration" ( rev: 1 ) in Spice

Not browsing as part of any series.

Commit Message

Jakub Janku Aug. 14, 2018, 6:53 p.m.
Rewrite systemd-login.c using GDBus instead of libdbus.

Use GDBusProxy. This is less efficient than the previous impl
as it caches all properties and listens to all signals of the
given DBus object. But it is just so much more convenient...
---
 src/vdagentd/systemd-login.c | 254 +++++++++++------------------------
 1 file changed, 79 insertions(+), 175 deletions(-)

Patch hide | download patch | download mbox

diff --git a/src/vdagentd/systemd-login.c b/src/vdagentd/systemd-login.c
index 88de1a6..2afd0dd 100644
--- a/src/vdagentd/systemd-login.c
+++ b/src/vdagentd/systemd-login.c
@@ -20,23 +20,21 @@ 
 */
 
 #include "session-info.h"
-#include <errno.h>
 #include <stdlib.h>
-#include <string.h>
 #include <syslog.h>
 #include <systemd/sd-login.h>
-#include <dbus/dbus.h>
+#include <gio/gio.h>
+#include <glib-unix.h>
 
 struct session_info {
     int verbose;
     sd_login_monitor *mon;
     char *session;
-    struct {
-        DBusConnection *system_connection;
-        char *match_session_signals;
-    } dbus;
+    GDBusProxy *dbus_proxy;
     gboolean session_is_locked;
-    gboolean session_locked_hint;
+    GIOChannel *io_channel;
+    guint io_watch_id;
+    ActiveSessionChangeCb session_change_cb;
 };
 
 #define LOGIND_INTERFACE            "org.freedesktop.login1"
@@ -44,185 +42,66 @@  struct session_info {
 #define LOGIND_SESSION_INTERFACE    "org.freedesktop.login1.Session"
 #define LOGIND_SESSION_OBJ_TEMPLATE "/org/freedesktop/login1/session/_3%s"
 
-#define DBUS_PROPERTIES_INTERFACE   "org.freedesktop.DBus.Properties"
-
 #define SESSION_SIGNAL_LOCK         "Lock"
 #define SESSION_SIGNAL_UNLOCK       "Unlock"
 
 #define SESSION_PROP_LOCKED_HINT    "LockedHint"
 
-/* dbus related */
-static DBusConnection *si_dbus_get_system_bus(void)
-{
-    DBusConnection *connection;
-    DBusError error;
-
-    dbus_error_init(&error);
-    connection = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
-    if (connection == NULL || dbus_error_is_set(&error)) {
-        if (dbus_error_is_set(&error)) {
-            syslog(LOG_WARNING, "Unable to connect to system bus: %s",
-                   error.message);
-            dbus_error_free(&error);
-        } else {
-            syslog(LOG_WARNING, "Unable to connect to system bus");
-        }
-        return NULL;
-    }
-    return connection;
-}
-
-static void si_dbus_match_remove(struct session_info *si)
-{
-    DBusError error;
-    if (si->dbus.match_session_signals == NULL)
-        return;
-
-    dbus_error_init(&error);
-    dbus_bus_remove_match(si->dbus.system_connection,
-                          si->dbus.match_session_signals,
-                          &error);
-
-    g_free(si->dbus.match_session_signals);
-    si->dbus.match_session_signals = NULL;
-}
-
-static void si_dbus_match_rule_update(struct session_info *si)
+static void session_signal_cb(GDBusProxy *proxy,
+                              gchar      *sender_name,
+                              gchar      *signal_name,
+                              GVariant   *parameters,
+                              gpointer    user_data)
 {
-    DBusError error;
-
-    if (si->dbus.system_connection == NULL ||
-            si->session == NULL)
-        return;
-
-    si_dbus_match_remove(si);
-
-    si->dbus.match_session_signals =
-        g_strdup_printf ("type='signal',interface='%s',path='"
-                         LOGIND_SESSION_OBJ_TEMPLATE"'",
-                         LOGIND_SESSION_INTERFACE,
-                         si->session);
-    if (si->verbose)
-        syslog(LOG_DEBUG, "logind match: %s", si->dbus.match_session_signals);
-
-    dbus_error_init(&error);
-    dbus_bus_add_match(si->dbus.system_connection,
-                       si->dbus.match_session_signals,
-                       &error);
-    if (dbus_error_is_set(&error)) {
-        syslog(LOG_WARNING, "Unable to add dbus rule match: %s",
-               error.message);
-        dbus_error_free(&error);
-        g_free(si->dbus.match_session_signals);
-        si->dbus.match_session_signals = NULL;
+    struct session_info *si = user_data;
+
+    if (g_strcmp0(signal_name, SESSION_SIGNAL_LOCK) == 0) {
+        si->session_is_locked = TRUE;
+    } else if (g_strcmp0(signal_name, SESSION_SIGNAL_UNLOCK) == 0) {
+        si->session_is_locked = FALSE;
+    } else if (si->verbose) {
+        syslog(LOG_DEBUG, "(systemd-login) Signal not handled: %s", signal_name);
     }
 }
 
-static void
-si_dbus_read_properties(struct session_info *si)
+static void si_dbus_proxy_update(struct session_info *si)
 {
-    dbus_bool_t locked_hint, ret;
-    DBusMessageIter iter, iter_variant;
-    gint type;
-    DBusError error;
-    DBusMessage *message = NULL;
-    DBusMessage *reply = NULL;
+    GError *err = NULL;
     gchar *session_object;
-    const gchar *interface, *property;
+
+    g_clear_object(&si->dbus_proxy);
 
     if (si->session == NULL)
         return;
 
     session_object = g_strdup_printf(LOGIND_SESSION_OBJ_TEMPLATE, si->session);
-    message = dbus_message_new_method_call(LOGIND_INTERFACE,
-                                           session_object,
-                                           DBUS_PROPERTIES_INTERFACE,
-                                           "Get");
-    g_free (session_object);
-    if (message == NULL) {
-        syslog(LOG_ERR, "Unable to create dbus message");
-        goto exit;
-    }
-
-    interface = LOGIND_SESSION_INTERFACE;
-    property = SESSION_PROP_LOCKED_HINT;
-    ret = dbus_message_append_args(message,
-                                   DBUS_TYPE_STRING, &interface,
-                                   DBUS_TYPE_STRING, &property,
-                                   DBUS_TYPE_INVALID);
-    if (!ret) {
-        syslog(LOG_ERR, "Unable to request locked-hint");
-        goto exit;
-    }
-
-    dbus_error_init(&error);
-    reply = dbus_connection_send_with_reply_and_block(si->dbus.system_connection,
-                                                      message,
-                                                      -1,
-                                                      &error);
-    if (reply == NULL) {
-        if (dbus_error_is_set(&error)) {
-            syslog(LOG_ERR, "Properties.Get failed (locked-hint) due %s", error.message);
-            dbus_error_free(&error);
-        } else {
-            syslog(LOG_ERR, "Properties.Get failed (locked-hint)");
-        }
-        goto exit;
-    }
-
-    dbus_message_iter_init(reply, &iter);
-    type = dbus_message_iter_get_arg_type(&iter);
-    if (type != DBUS_TYPE_VARIANT) {
-        syslog(LOG_ERR, "expected a variant, got a '%c' instead", type);
-        goto exit;
-    }
-
-    dbus_message_iter_recurse(&iter, &iter_variant);
-    type = dbus_message_iter_get_arg_type(&iter_variant);
-    if (type != DBUS_TYPE_BOOLEAN) {
-        syslog(LOG_ERR, "expected a boolean, got a '%c' instead", type);
-        goto exit;
-    }
-    dbus_message_iter_get_basic(&iter_variant, &locked_hint);
-
-    si->session_locked_hint = (locked_hint) ? TRUE : FALSE;
-exit:
-    if (reply != NULL) {
-        dbus_message_unref(reply);
-    }
-
-    if (message != NULL) {
-        dbus_message_unref(message);
+    si->dbus_proxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM,
+                                                   G_DBUS_PROXY_FLAGS_NONE,
+                                                   NULL,
+                                                   LOGIND_INTERFACE,
+                                                   session_object,
+                                                   LOGIND_SESSION_INTERFACE,
+                                                   NULL,
+                                                   &err);
+    g_free(session_object);
+    if (err) {
+        syslog(LOG_ERR, "(systemd-login) %s: %s", __func__, err->message);
+        g_error_free(err);
+        return;
     }
+    g_signal_connect(si->dbus_proxy, "g-signal",
+                     G_CALLBACK(session_signal_cb), si);
 }
 
-static void
-si_dbus_read_signals(struct session_info *si)
+static gboolean io_channel_cb(GIOChannel  *source,
+                              GIOCondition condition,
+                              gpointer     data)
 {
-    DBusMessage *message = NULL;
-
-    dbus_connection_read_write(si->dbus.system_connection, 0);
-    message = dbus_connection_pop_message(si->dbus.system_connection);
-    while (message != NULL) {
-        const char *member;
-
-        member = dbus_message_get_member (message);
-        if (g_strcmp0(member, SESSION_SIGNAL_LOCK) == 0) {
-            si->session_is_locked = TRUE;
-        } else if (g_strcmp0(member, SESSION_SIGNAL_UNLOCK) == 0) {
-            si->session_is_locked = FALSE;
-        } else {
-            if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL) {
-                syslog(LOG_WARNING, "(systemd-login) received non signal message");
-            } else if (si->verbose) {
-                syslog(LOG_DEBUG, "(systemd-login) Signal not handled: %s", member);
-            }
-        }
-
-        dbus_message_unref(message);
-        dbus_connection_read_write(si->dbus.system_connection, 0);
-        message = dbus_connection_pop_message(si->dbus.system_connection);
-    }
+    struct session_info *si = data;
+    session_info_get_active_session(si);
+    if (si->session_change_cb)
+        si->session_change_cb(si->session);
+    return G_SOURCE_CONTINUE;
 }
 
 struct session_info *session_info_create(int verbose, ActiveSessionChangeCb cb)
@@ -236,6 +115,7 @@  struct session_info *session_info_create(int verbose, ActiveSessionChangeCb cb)
 
     si->verbose = verbose;
     si->session_is_locked = FALSE;
+    si->session_change_cb = cb;
 
     r = sd_login_monitor_new("session", &si->mon);
     if (r < 0) {
@@ -244,7 +124,9 @@  struct session_info *session_info_create(int verbose, ActiveSessionChangeCb cb)
         return NULL;
     }
 
-    si->dbus.system_connection = si_dbus_get_system_bus();
+    si->io_channel = g_io_channel_unix_new(sd_login_monitor_get_fd(si->mon));
+    si->io_watch_id = g_io_add_watch(si->io_channel, G_IO_IN, io_channel_cb, si);
+
     return si;
 }
 
@@ -253,8 +135,9 @@  void session_info_destroy(struct session_info *si)
     if (!si)
         return;
 
-    si_dbus_match_remove(si);
-    dbus_connection_close(si->dbus.system_connection);
+    g_clear_object(&si->dbus_proxy);
+    g_source_remove(si->io_watch_id);
+    g_io_channel_unref(si->io_channel);
     sd_login_monitor_unref(si->mon);
     free(si->session);
     free(si);
@@ -284,7 +167,7 @@  const char *session_info_get_active_session(struct session_info *si)
     sd_login_monitor_flush(si->mon);
     free(old_session);
 
-    si_dbus_match_rule_update(si);
+    si_dbus_proxy_update(si);
     return si->session;
 }
 
@@ -303,16 +186,37 @@  char *session_info_session_for_pid(struct session_info *si, uint32_t pid)
     return session;
 }
 
+gboolean get_locked_hint_property(struct session_info *si)
+{
+    GVariant *prop;
+    gboolean locked = FALSE;
+
+    if (si->dbus_proxy == NULL)
+        return locked;
+
+    prop = g_dbus_proxy_get_cached_property(si->dbus_proxy,
+               SESSION_PROP_LOCKED_HINT);
+    if (prop) {
+        if (g_variant_is_of_type(prop, G_VARIANT_TYPE_BOOLEAN))
+            locked = g_variant_get_boolean(prop);
+        else
+            syslog(LOG_ERR, "(systemd-login) unexpected LockedHint property type");
+
+        g_variant_unref(prop);
+    } else {
+        syslog(LOG_ERR, "(systemd-login) cannot get LockedHint property");
+    }
+
+    return locked;
+}
+
 gboolean session_info_session_is_locked(struct session_info *si)
 {
     gboolean locked;
 
     g_return_val_if_fail (si != NULL, FALSE);
 
-    si_dbus_read_signals(si);
-    si_dbus_read_properties(si);
-
-    locked = (si->session_is_locked || si->session_locked_hint);
+    locked = (si->session_is_locked || get_locked_hint_property(si));
     if (si->verbose) {
         syslog(LOG_DEBUG, "(systemd-login) session is locked: %s",
                locked ? "yes" : "no");