We will switch to GDBus implementation of D-Bus protocol because
sd-bus implementation is not thread safe.
Processing messages in threads is essential since Libvirt API can
take some significant amount of time to return and that would block
the whole libvirt-dbus daemon.
Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
---
README | 1 +
configure.ac | 12 ++
data/Makefile.am | 5 +
libvirt-dbus.spec.in | 6 +
src/Makefile.am | 17 ++-
src/gdbus.c | 393 +++++++++++++++++++++++++++++++++++++++++++++++++++
src/gdbus.h | 95 +++++++++++++
test/Makefile.am | 3 +-
test/travis-run | 2 +-
9 files changed, 529 insertions(+), 5 deletions(-)
create mode 100644 src/gdbus.c
create mode 100644 src/gdbus.h
diff --git a/README b/README
index 754d957..a85114e 100644
--- a/README
+++ b/README
@@ -58,6 +58,7 @@ The packages required to build libvirt-dbus are
- systemd-211
- libvirt
+ - glib2
Patches submissions
===================
diff --git a/configure.ac b/configure.ac
index ba397ca..d6ed0ef 100644
--- a/configure.ac
+++ b/configure.ac
@@ -11,10 +11,14 @@ AC_USE_SYSTEM_EXTENSIONS
AM_SILENT_RULES([yes])
+GLIB2_REQUIRED=2.50.0
LIBVIRT_REQUIRED=AC_PACKAGE_VERSION
SYSTEMD_REQUIRED=211
+LIBVIRT_GLIB_REQUIRED=1.0.0
+AC_SUBST([GLIB2_REQUIRED]) dnl used in the .spec file
AC_SUBST([LIBVIRT_REQUIRED]) dnl used in the .spec file
AC_SUBST([SYSTEMD_REQUIRED]) dnl used in the .spec file
+AC_SUBST([LIBVIRT_GLIB_REQUIRED]) dnl used in the .spec file
LIBVIRT_DBUS_MAJOR_VERSION=`echo $VERSION | awk -F. '{print $1}'`
LIBVIRT_DBUS_MINOR_VERSION=`echo $VERSION | awk -F. '{print $2}'`
@@ -34,8 +38,11 @@ AC_PROG_MKDIR_P
AM_PROG_CC_C_O
AC_PROG_CC_STDC
+PKG_CHECK_MODULES(GIO2, gio-unix-2.0 >= GLIB2_REQUIRED)
+PKG_CHECK_MODULES(GLIB2, glib-2.0 >= GLIB2_REQUIRED)
PKG_CHECK_MODULES(LIBVIRT, libvirt >= $LIBVIRT_REQUIRED)
PKG_CHECK_MODULES(SYSTEMD, libsystemd >= $SYSTEMD_REQUIRED)
+PKG_CHECK_MODULES(LIBVIRT_GLIB, libvirt-glib-1.0 >= LIBVIRT_GLIB_REQUIRED)
LIBVIRT_COMPILE_WARNINGS
LIBVIRT_LINKER_RELRO
@@ -56,6 +63,11 @@ LIBVIRT_ARG_WITH([DBUS_SYSTEM_POLICIES], [where D-Bus system policies directory
DBUS_SYSTEM_POLICIES_DIR="$with_dbus_system_policies"
AC_SUBST(DBUS_SYSTEM_POLICIES_DIR)
+LIBVIRT_ARG_WITH([DBUS_INTERFACES], [where D-Bus interfaces directory is],
+ ['$(datadir)/dbus-1/interfaces'])
+DBUS_INTERFACES_DIR="$with_dbus_interfaces"
+AC_SUBST([DBUS_INTERFACES_DIR])
+
LIBVIRT_ARG_WITH([SYSTEM_USER], [username to run system instance as],
['libvirtdbus'])
SYSTEM_USER=$with_system_user
diff --git a/data/Makefile.am b/data/Makefile.am
index 9a53305..a886687 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -18,11 +18,16 @@ polkit_files = \
polkitdir = $(sysconfdir)/polkit-1/rules.d
polkit_DATA = $(polkit_files:.rules.in=.rules)
+interfaces_files =
+interfacesdir = $(DBUS_INTERFACES_DIR)
+interfaces_DATA = $(interfaces_files)
+
EXTRA_DIST = \
$(service_in_files) \
$(system_service_in_files) \
$(system_policy_files) \
$(polkit_files) \
+ $(interfaces_files) \
$(NULL)
CLEANFILES = \
diff --git a/libvirt-dbus.spec.in b/libvirt-dbus.spec.in
index ce5cecf..662ece1 100644
--- a/libvirt-dbus.spec.in
+++ b/libvirt-dbus.spec.in
@@ -1,7 +1,9 @@
# -*- rpm-spec -*-
+%define glib2_version @GLIB2_REQUIRED@
%define libvirt_version @LIBVIRT_REQUIRED@
%define systemd_version @SYSTEMD_REQUIRED@
+%define libvirt_glib_version @LIBVIRT_GLIB_REQUIRED@
%define system_user @SYSTEM_USER@
Name: @PACKAGE@
@@ -15,11 +17,15 @@ Source0: ftp://libvirt.org/libvirt/dbus/%{name}-%{version}.tar.gz
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
BuildRequires: gcc
+BuildRequires: glib2-devel >= %{glib2_version}
BuildRequires: libvirt-devel >= %{libvirt_version}
BuildRequires: systemd-devel >= %{systemd_version}
+BuildRequires: libvirt-glib-devel >= %{libvirt_glib_version}
+Requires: glib2 >= %{glib2_version}
Requires: libvirt-libs >= %{libvirt_version}
Requires: systemd-libs >= %{systemd_version}
+Requires: libvirt-glib >= %{libvirt_glib_version}
Requires(pre): shadow-utils
diff --git a/src/Makefile.am b/src/Makefile.am
index 1a5b50b..e7bba9d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,12 +1,14 @@
AM_CPPFLAGS = \
- -I$(top_srcdir)/src
+ -I$(top_srcdir)/src \
+ -DVIRT_DBUS_INTERFACES_DIR=\"$(DBUS_INTERFACES_DIR)\"
DAEMON_SOURCES = \
main.c \
connect.c connect.h \
util.c util.h \
domain.c domain.h \
- events.c events.h
+ events.c events.h \
+ gdbus.c gdbus.h
EXTRA_DIST = \
$(DAEMON_SOURCES)
@@ -18,18 +20,27 @@ libvirt_dbus_SOURCES = $(DAEMON_SOURCES)
libvirt_dbus_CFLAGS = \
$(SYSTEMD_CFLAGS) \
+ $(GIO2_CFLAGS) \
+ $(GLIB2_CFLAGS) \
$(LIBVIRT_CFLAGS) \
+ $(LIBVIRT_GLIB_CFLAGS) \
$(WARN_CFLAGS) \
$(PIE_CFLAGS) \
$(NULL)
libvirt_dbus_LDFLAGS = \
$(SYSTEMD_LDFLAGS) \
+ $(GIO2_LDFLAGS) \
+ $(GLIB2_LDFLAGS) \
$(LIBVIRT_LDFLAGS) \
+ $(LIBVIRT_GLIB_LDFLAGS) \
$(RELRO_LDFLAGS) \
$(PID_LDFLAGS) \
$(NULL)
libvirt_dbus_LDADD = \
$(SYSTEMD_LIBS) \
- $(LIBVIRT_LIBS)
+ $(GIO2_LIBS) \
+ $(GLIB2_LIBS) \
+ $(LIBVIRT_LIBS) \
+ $(LIBVIRT_GLIB_LIBS)
diff --git a/src/gdbus.c b/src/gdbus.c
new file mode 100644
index 0000000..7dd5766
--- /dev/null
+++ b/src/gdbus.c
@@ -0,0 +1,393 @@
+#include "gdbus.h"
+
+#include <glib/gprintf.h>
+
+struct _virtDBusGDBusMethodData {
+ virtDBusGDBusMethodTable *methods;
+ virtDBusGDBusPropertyTable *properties;
+ gpointer *userData;
+};
+typedef struct _virtDBusGDBusMethodData virtDBusGDBusMethodData;
+
+struct _virtDBusGDBusSubtreeData {
+ GDBusInterfaceInfo *interface;
+ virtDBusGDBusMethodData *methodData;
+};
+typedef struct _virtDBusGDBusSubtreeData virtDBusGDBusSubtreeData;
+
+static const gchar *dbusInterfacePrefix = NULL;
+
+/**
+ * virtDBusGDBusLoadIntrospectData:
+ * @interface: name of the interface
+ *
+ * Reads an interface XML description from file and returns new
+ * interface info. The caller owns an reference to the returned info.
+ *
+ * The file path is constructed as:
+ *
+ * VIRT_DBUS_INTERFACES_DIR/{@interface}.xml
+ *
+ * Returns interface info on success, NULL on failure.
+ */
+GDBusInterfaceInfo *
+virtDBusGDBusLoadIntrospectData(gchar const *interface)
+{
+ g_autofree gchar *introspectFile = NULL;
+ g_autofree gchar *introspectXML = NULL;
+ g_autoptr(GDBusNodeInfo) nodeInfo = NULL;
+ GDBusInterfaceInfo *ret;
+
+ if (!dbusInterfacePrefix) {
+ dbusInterfacePrefix = g_getenv("VIRT_DBUS_INTERFACES_DIR");
+ if (!dbusInterfacePrefix)
+ dbusInterfacePrefix = VIRT_DBUS_INTERFACES_DIR;
+ }
+
+ introspectFile = g_strdup_printf("%s/%s.xml", dbusInterfacePrefix, interface);
+ g_assert(introspectFile != NULL);
+
+ g_file_get_contents(introspectFile, &introspectXML, NULL, NULL);
+ g_assert(introspectXML != NULL);
+
+ nodeInfo = g_dbus_node_info_new_for_xml(introspectXML, NULL);
+ if (!nodeInfo)
+ return NULL;
+
+ ret = nodeInfo->interfaces[0];
+ if (!ret)
+ return NULL;
+
+ return g_dbus_interface_info_ref(ret);
+}
+
+static void
+virtDBusGDBusHandlePropertyGet(GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ const gchar *objectPath,
+ virtDBusGDBusMethodData *data)
+{
+ virtDBusGDBusPropertyGetFunc getFunc = NULL;
+ const gchar *interface;
+ const gchar *name;
+ GVariant *value = NULL;
+ GError *error = NULL;
+
+ g_variant_get(parameters, "(&s&s)", &interface, &name);
+
+ for (gint i = 0; data->properties[i].name; i++) {
+ if (g_strcmp0(name, data->properties[i].name) == 0) {
+ getFunc = data->properties[i].getFunc;
+ break;
+ }
+ }
+
+ if (!getFunc) {
+ g_dbus_method_invocation_return_error(invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_UNKNOWN_PROPERTY,
+ "unknown property '%s'", name);
+ return;
+ }
+
+ getFunc(objectPath, data->userData, &value, &error);
+
+ if (error) {
+ g_dbus_method_invocation_return_gerror(invocation, error);
+ return;
+ }
+
+ g_return_if_fail(value);
+
+ g_dbus_method_invocation_return_value(invocation,
+ g_variant_new("(v)", value));
+}
+
+static void
+virtDBusGDBusHandlePropertySet(GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ const gchar *objectPath,
+ virtDBusGDBusMethodData *data)
+{
+ virtDBusGDBusPropertySetFunc setFunc = NULL;
+ const gchar *interface;
+ const gchar *name;
+ g_autoptr(GVariant) value = NULL;
+ GError *error = NULL;
+
+ g_variant_get(parameters, "(&s&sv)", &interface, &name, &value);
+
+ for (gint i = 0; data->properties[i].name; i++) {
+ if (g_strcmp0(name, data->properties[i].name) == 0) {
+ setFunc = data->properties[i].setFunc;
+ break;
+ }
+ }
+
+ if (!setFunc) {
+ g_dbus_method_invocation_return_error(invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_UNKNOWN_PROPERTY,
+ "unknown property '%s'", name);
+ return;
+ }
+
+ setFunc(value, objectPath, data->userData, &error);
+
+ if (error)
+ g_dbus_method_invocation_return_gerror(invocation, error);
+ else
+ g_dbus_method_invocation_return_value(invocation, NULL);
+}
+
+static void
+virtDBusGDBusHandlePropertyGetAll(GDBusMethodInvocation *invocation,
+ const gchar *objectPath,
+ virtDBusGDBusMethodData *data)
+{
+ GVariant *value;
+ g_auto(GVariantBuilder) builder;
+ GError *error = NULL;
+
+ g_variant_builder_init(&builder, G_VARIANT_TYPE("(a{sv})"));
+
+ g_variant_builder_open(&builder, G_VARIANT_TYPE("a{sv}"));
+
+ for (gint i = 0; data->properties[i].name; i++) {
+ data->properties[i].getFunc(objectPath, data->userData,
+ &value, &error);
+
+ if (error) {
+ g_dbus_method_invocation_return_gerror(invocation, error);
+ return;
+ }
+
+ g_return_if_fail(value);
+
+ g_variant_builder_add(&builder, "{sv}",
+ data->properties[i].name,
+ g_variant_new_variant(value));
+ }
+
+ g_variant_builder_close(&builder);
+
+ g_dbus_method_invocation_return_value(invocation,
+ g_variant_builder_end(&builder));
+}
+
+static void
+virtDBusGDBusHandleMethod(GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ const gchar *objectPath,
+ const gchar *methodName,
+ virtDBusGDBusMethodData *data)
+{
+ virtDBusGDBusMethodFunc methodFunc = NULL;
+ GDBusMessage *msg = g_dbus_method_invocation_get_message(invocation);
+ GUnixFDList *inFDs = NULL;
+ GVariant *outArgs = NULL;
+ GUnixFDList *outFDs = NULL;
+ GError *error = NULL;
+
+ for (gint i = 0; data->methods[i].name; i++) {
+ if (g_strcmp0(methodName, data->methods[i].name) == 0) {
+ methodFunc = data->methods[i].methodFunc;
+ break;
+ }
+ }
+
+ if (!methodFunc) {
+ g_dbus_method_invocation_return_error(invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_UNKNOWN_METHOD,
+ "unknown method '%s'", methodName);
+ return;
+ }
+
+ inFDs = g_dbus_message_get_unix_fd_list(msg);
+
+ methodFunc(parameters, inFDs, objectPath, data->userData,
+ &outArgs, &outFDs, &error);
+
+ if (error) {
+ g_dbus_method_invocation_return_gerror(invocation, error);
+ return;
+ }
+
+ g_return_if_fail(outArgs || !outFDs);
+
+ g_dbus_method_invocation_return_value_with_unix_fd_list(invocation,
+ outArgs,
+ outFDs);
+}
+
+static void
+virtDBusGDBusHandleMethodCall(GDBusConnection *connection G_GNUC_UNUSED,
+ const gchar *sender G_GNUC_UNUSED,
+ const gchar *objectPath,
+ const gchar *interfaceName,
+ const gchar *methodName,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ gpointer userData)
+{
+ virtDBusGDBusMethodData *data = userData;
+
+ if (g_strcmp0(interfaceName, "org.freedesktop.DBus.Properties") == 0) {
+ if (g_strcmp0(methodName, "Get") == 0) {
+ virtDBusGDBusHandlePropertyGet(parameters, invocation,
+ objectPath, data);
+ } else if (g_strcmp0(methodName, "Set") == 0) {
+ virtDBusGDBusHandlePropertySet(parameters, invocation,
+ objectPath, data);
+ } else if (g_strcmp0(methodName, "GetAll") == 0) {
+ virtDBusGDBusHandlePropertyGetAll(invocation, objectPath, data);
+ } else {
+ g_dbus_method_invocation_return_error(invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_UNKNOWN_METHOD,
+ "unknown method '%s'", methodName);
+ }
+ } else {
+ virtDBusGDBusHandleMethod(parameters, invocation, objectPath,
+ methodName, data);
+ }
+}
+
+static const GDBusInterfaceVTable virtDBusGDBusVtable = {
+ virtDBusGDBusHandleMethodCall,
+ NULL,
+ NULL,
+ { NULL }
+};
+
+/**
+ * virtDBusGDBusRegisterObject:
+ * @bus: GDBus connection
+ * @objectPath: object path
+ * @interface: interface info of the object
+ * @methods: table of method handlers
+ * @properties: table of property handlers
+ * @userData: data that are passed to method and property handlers
+ *
+ * Registers a new D-Bus object that we would like to handle.
+ */
+void
+virtDBusGDBusRegisterObject(GDBusConnection *bus,
+ gchar const *objectPath,
+ GDBusInterfaceInfo *interface,
+ virtDBusGDBusMethodTable *methods,
+ virtDBusGDBusPropertyTable *properties,
+ gpointer userData)
+{
+ virtDBusGDBusMethodData *data = g_new0(virtDBusGDBusMethodData, 1);
+
+ g_assert(data);
+
+ data->methods = methods;
+ data->properties = properties;
+ data->userData = userData;
+
+ g_dbus_connection_register_object(bus,
+ objectPath,
+ interface,
+ &virtDBusGDBusVtable,
+ data, g_free,
+ NULL);
+}
+
+static gchar **
+virtDBusGDBusEnumerate(GDBusConnection *connection G_GNUC_UNUSED,
+ const gchar *sender G_GNUC_UNUSED,
+ const gchar *objectPath G_GNUC_UNUSED,
+ gpointer userData G_GNUC_UNUSED)
+{
+ return NULL;
+}
+
+static GDBusInterfaceInfo **
+virtDBusGDBusIntrospect(GDBusConnection *bus G_GNUC_UNUSED,
+ const gchar *sender G_GNUC_UNUSED,
+ const gchar *objectPath G_GNUC_UNUSED,
+ const gchar *node G_GNUC_UNUSED,
+ gpointer userData)
+{
+ virtDBusGDBusSubtreeData *data = userData;
+ GDBusInterfaceInfo **ret = g_new0(GDBusInterfaceInfo *, 2);
+
+ g_assert(ret);
+ ret[0] = g_dbus_interface_info_ref(data->interface);
+
+ return ret;
+}
+
+static const GDBusInterfaceVTable *
+virtDBusGDBusDispatch(GDBusConnection *bus G_GNUC_UNUSED,
+ const gchar *sender G_GNUC_UNUSED,
+ const gchar *objectPath G_GNUC_UNUSED,
+ const gchar *interfaceName G_GNUC_UNUSED,
+ const gchar *node G_GNUC_UNUSED,
+ gpointer *outUserData,
+ gpointer userData)
+{
+ virtDBusGDBusSubtreeData *data = userData;
+
+ *outUserData = data->methodData;
+ return &virtDBusGDBusVtable;
+}
+
+static const GDBusSubtreeVTable virtDBusGDBusSubreeVtable = {
+ virtDBusGDBusEnumerate,
+ virtDBusGDBusIntrospect,
+ virtDBusGDBusDispatch,
+ { NULL }
+};
+
+static void
+virtDBusGDBusSubtreeDataFree(gpointer opaque)
+{
+ virtDBusGDBusSubtreeData *data = opaque;
+ g_free(data->methodData);
+ g_free(data);
+}
+
+/**
+ * virtDBusGDBusRegisterSubtree:
+ * @bus: GDBus connection
+ * @objectPath: object prefix path
+ * @interface: interface info of the object
+ * @methods: table of method handlers
+ * @properties: table of property handlers
+ * @userData: data that are passed to method and property handlers
+ *
+ * Registers a new D-Bus object prefix that we would like to handle.
+ */
+void
+virtDBusGDBusRegisterSubtree(GDBusConnection *bus,
+ gchar const *objectPath,
+ GDBusInterfaceInfo *interface,
+ virtDBusGDBusMethodTable *methods,
+ virtDBusGDBusPropertyTable *properties,
+ gpointer userData)
+{
+ virtDBusGDBusSubtreeData *data = g_new0(virtDBusGDBusSubtreeData, 1);
+
+ g_assert(data);
+
+ data->methodData = g_new0(virtDBusGDBusMethodData, 1);
+
+ g_assert(data->methodData);
+
+ data->interface = interface;
+ data->methodData->methods = methods;
+ data->methodData->properties = properties;
+ data->methodData->userData = userData;
+
+ g_dbus_connection_register_subtree(bus,
+ objectPath,
+ &virtDBusGDBusSubreeVtable,
+ G_DBUS_SUBTREE_FLAGS_DISPATCH_TO_UNENUMERATED_NODES,
+ data,
+ virtDBusGDBusSubtreeDataFree,
+ NULL);
+}
diff --git a/src/gdbus.h b/src/gdbus.h
new file mode 100644
index 0000000..21ee6fc
--- /dev/null
+++ b/src/gdbus.h
@@ -0,0 +1,95 @@
+#pragma once
+
+#include <gio/gio.h>
+
+/**
+ * virtDBusGDBusMethodFunc:
+ * @inArgs: input arguments of the method call
+ * @inFDs: list of input file descriptors
+ * @objectPath: the object path the method was called on
+ * @userData: user data passed when registering new object or subtree
+ * @outArgs: return location of output arguments
+ * @outFDs: return location of output file descriptors
+ * @error: return location for error
+ *
+ * Handles D-Bus method call. In case of error the handler has
+ * to set an @error.
+ */
+typedef void
+(*virtDBusGDBusMethodFunc)(GVariant *inArgs,
+ GUnixFDList *inFDs,
+ const gchar *objectPath,
+ gpointer userData,
+ GVariant **outArgs,
+ GUnixFDList **outFDs,
+ GError **error);
+
+/**
+ * virtDBusGDBusPropertyGetFunc:
+ * @objectPath: the object path the method was called on
+ * @userData: user data passed when registering new object or subtree
+ * @value: return location for property value
+ * @error: return location for error
+ *
+ * Handles D-Bus Get action on a property. In case of error the handler
+ * has to set an @error, otherwise @value has to be set.
+ */
+typedef void
+(*virtDBusGDBusPropertyGetFunc)(const gchar *objectPath,
+ gpointer userData,
+ GVariant **value,
+ GError **error);
+
+/**
+ * virtDBusGDBusPropertySetFunc:
+ * @objectPath: the object path the method was called on
+ * @value: new value that should be set to the property
+ * @userData: user data passed when registering new object or subtree
+ * @error: return location for error
+ *
+ * Handles D-Bus Set action on a property. In case of error the handler
+ * has to set an @error.
+ */
+typedef void
+(*virtDBusGDBusPropertySetFunc)(GVariant *value,
+ const gchar *objectPath,
+ gpointer userData,
+ GError **error);
+
+struct _virtDBusGDBusMethodTable {
+ const gchar *name;
+ virtDBusGDBusMethodFunc methodFunc;
+};
+typedef struct _virtDBusGDBusMethodTable virtDBusGDBusMethodTable;
+
+struct _virtDBusGDBusPropertyTable {
+ const gchar *name;
+ virtDBusGDBusPropertyGetFunc getFunc;
+ virtDBusGDBusPropertySetFunc setFunc;
+};
+typedef struct _virtDBusGDBusPropertyTable virtDBusGDBusPropertyTable;
+
+typedef guint virtDBusGDBusSource;
+typedef guint virtDBusGDBusOwner;
+
+GDBusInterfaceInfo *
+virtDBusGDBusLoadIntrospectData(gchar const *interface);
+
+void
+virtDBusGDBusRegisterObject(GDBusConnection *bus,
+ gchar const *objectPath,
+ GDBusInterfaceInfo *interface,
+ virtDBusGDBusMethodTable *methods,
+ virtDBusGDBusPropertyTable *properties,
+ gpointer userData);
+
+void
+virtDBusGDBusRegisterSubtree(GDBusConnection *bus,
+ gchar const *objectPath,
+ GDBusInterfaceInfo *interface,
+ virtDBusGDBusMethodTable *methods,
+ virtDBusGDBusPropertyTable *properties,
+ gpointer userData);
+
+G_DEFINE_AUTO_CLEANUP_FREE_FUNC(virtDBusGDBusSource, g_source_remove, 0);
+G_DEFINE_AUTO_CLEANUP_FREE_FUNC(virtDBusGDBusOwner, g_bus_unown_name, 0);
diff --git a/test/Makefile.am b/test/Makefile.am
index 4651d08..d3997f3 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -13,4 +13,5 @@ EXTRA_DIST = \
travis-run
TESTS_ENVIRONMENT = \
- abs_top_builddir=$(abs_top_builddir)
+ abs_top_builddir=$(abs_top_builddir) \
+ VIRT_DBUS_INTERFACES_DIR=$(abs_top_srcdir)/data
diff --git a/test/travis-run b/test/travis-run
index 482b286..28260f4 100755
--- a/test/travis-run
+++ b/test/travis-run
@@ -22,7 +22,7 @@ sudo chroot "$CHROOT" << EOF
set -ex
# install build deps
apt-get update
-apt-get install -y dh-autoreconf pkg-config libvirt-dev libsystemd-dev libtool python3-gi python3-dbus dbus
+apt-get install -y dh-autoreconf pkg-config libvirt-dev libsystemd-dev libglib2.0-dev libtool python3-gi python3-dbus dbus
# run build and tests as user
chown -R buildd:buildd /build
--
2.14.3
--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
On Mon, Mar 19, 2018 at 10:30:50AM +0100, Pavel Hrdina wrote: > We will switch to GDBus implementation of D-Bus protocol because > sd-bus implementation is not thread safe. > > Processing messages in threads is essential since Libvirt API can > take some significant amount of time to return and that would block > the whole libvirt-dbus daemon. > > Signed-off-by: Pavel Hrdina <phrdina@redhat.com> > --- > README | 1 + > configure.ac | 12 ++ > data/Makefile.am | 5 + > libvirt-dbus.spec.in | 6 + > src/Makefile.am | 17 ++- > src/gdbus.c | 393 +++++++++++++++++++++++++++++++++++++++++++++++++++ > src/gdbus.h | 95 +++++++++++++ > test/Makefile.am | 3 +- > test/travis-run | 2 +- > 9 files changed, 529 insertions(+), 5 deletions(-) > create mode 100644 src/gdbus.c > create mode 100644 src/gdbus.h > > diff --git a/README b/README > index 754d957..a85114e 100644 > --- a/README > +++ b/README > @@ -58,6 +58,7 @@ The packages required to build libvirt-dbus are > > - systemd-211 > - libvirt > + - glib2 > > Patches submissions > =================== > diff --git a/configure.ac b/configure.ac > index ba397ca..d6ed0ef 100644 > --- a/configure.ac > +++ b/configure.ac > @@ -11,10 +11,14 @@ AC_USE_SYSTEM_EXTENSIONS > > AM_SILENT_RULES([yes]) > > +GLIB2_REQUIRED=2.50.0 Is there a rational for that version, or is just what's on your OS install ? The GBus APIs have been around alot longer than this - mostly 2.30.0 iiuc > LIBVIRT_REQUIRED=AC_PACKAGE_VERSION > SYSTEMD_REQUIRED=211 > +LIBVIRT_GLIB_REQUIRED=1.0.0 Same question here ? > +AC_SUBST([GLIB2_REQUIRED]) dnl used in the .spec file > AC_SUBST([LIBVIRT_REQUIRED]) dnl used in the .spec file > AC_SUBST([SYSTEMD_REQUIRED]) dnl used in the .spec file > +AC_SUBST([LIBVIRT_GLIB_REQUIRED]) dnl used in the .spec file > > LIBVIRT_DBUS_MAJOR_VERSION=`echo $VERSION | awk -F. '{print $1}'` > LIBVIRT_DBUS_MINOR_VERSION=`echo $VERSION | awk -F. '{print $2}'` > @@ -34,8 +38,11 @@ AC_PROG_MKDIR_P > AM_PROG_CC_C_O > AC_PROG_CC_STDC > > +PKG_CHECK_MODULES(GIO2, gio-unix-2.0 >= GLIB2_REQUIRED) > +PKG_CHECK_MODULES(GLIB2, glib-2.0 >= GLIB2_REQUIRED) > PKG_CHECK_MODULES(LIBVIRT, libvirt >= $LIBVIRT_REQUIRED) > PKG_CHECK_MODULES(SYSTEMD, libsystemd >= $SYSTEMD_REQUIRED) > +PKG_CHECK_MODULES(LIBVIRT_GLIB, libvirt-glib-1.0 >= LIBVIRT_GLIB_REQUIRED) > diff --git a/src/gdbus.c b/src/gdbus.c > new file mode 100644 > index 0000000..7dd5766 > --- /dev/null > +++ b/src/gdbus.c > @@ -0,0 +1,393 @@ > +#include "gdbus.h" > + > +#include <glib/gprintf.h> > + > +struct _virtDBusGDBusMethodData { > + virtDBusGDBusMethodTable *methods; > + virtDBusGDBusPropertyTable *properties; > + gpointer *userData; > +}; > +typedef struct _virtDBusGDBusMethodData virtDBusGDBusMethodData; > + > +struct _virtDBusGDBusSubtreeData { > + GDBusInterfaceInfo *interface; > + virtDBusGDBusMethodData *methodData; > +}; > +typedef struct _virtDBusGDBusSubtreeData virtDBusGDBusSubtreeData; > + > +static const gchar *dbusInterfacePrefix = NULL; > + > +/** > + * virtDBusGDBusLoadIntrospectData: > + * @interface: name of the interface > + * > + * Reads an interface XML description from file and returns new > + * interface info. The caller owns an reference to the returned info. > + * > + * The file path is constructed as: > + * > + * VIRT_DBUS_INTERFACES_DIR/{@interface}.xml > + * > + * Returns interface info on success, NULL on failure. > + */ > +GDBusInterfaceInfo * > +virtDBusGDBusLoadIntrospectData(gchar const *interface) > +{ > + g_autofree gchar *introspectFile = NULL; > + g_autofree gchar *introspectXML = NULL; > + g_autoptr(GDBusNodeInfo) nodeInfo = NULL; > + GDBusInterfaceInfo *ret; > + > + if (!dbusInterfacePrefix) { > + dbusInterfacePrefix = g_getenv("VIRT_DBUS_INTERFACES_DIR"); > + if (!dbusInterfacePrefix) > + dbusInterfacePrefix = VIRT_DBUS_INTERFACES_DIR; > + } > + > + introspectFile = g_strdup_printf("%s/%s.xml", dbusInterfacePrefix, interface); > + g_assert(introspectFile != NULL); > + > + g_file_get_contents(introspectFile, &introspectXML, NULL, NULL); > + g_assert(introspectXML != NULL); > + > + nodeInfo = g_dbus_node_info_new_for_xml(introspectXML, NULL); > + if (!nodeInfo) > + return NULL; > + > + ret = nodeInfo->interfaces[0]; > + if (!ret) > + return NULL; > + > + return g_dbus_interface_info_ref(ret); > +} My main comment would be that this is all using the low level dbus APIs in glib, rather than the high level APIs. I can understand if that is easier to adapt to given the existing code though. Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :| -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
On Mon, Mar 19, 2018 at 01:47:20PM +0000, Daniel P. Berrangé wrote: > On Mon, Mar 19, 2018 at 10:30:50AM +0100, Pavel Hrdina wrote: > > We will switch to GDBus implementation of D-Bus protocol because > > sd-bus implementation is not thread safe. > > > > Processing messages in threads is essential since Libvirt API can > > take some significant amount of time to return and that would block > > the whole libvirt-dbus daemon. > > > > Signed-off-by: Pavel Hrdina <phrdina@redhat.com> > > --- > > README | 1 + > > configure.ac | 12 ++ > > data/Makefile.am | 5 + > > libvirt-dbus.spec.in | 6 + > > src/Makefile.am | 17 ++- > > src/gdbus.c | 393 +++++++++++++++++++++++++++++++++++++++++++++++++++ > > src/gdbus.h | 95 +++++++++++++ > > test/Makefile.am | 3 +- > > test/travis-run | 2 +- > > 9 files changed, 529 insertions(+), 5 deletions(-) > > create mode 100644 src/gdbus.c > > create mode 100644 src/gdbus.h > > > > diff --git a/README b/README > > index 754d957..a85114e 100644 > > --- a/README > > +++ b/README > > @@ -58,6 +58,7 @@ The packages required to build libvirt-dbus are > > > > - systemd-211 > > - libvirt > > + - glib2 > > > > Patches submissions > > =================== > > diff --git a/configure.ac b/configure.ac > > index ba397ca..d6ed0ef 100644 > > --- a/configure.ac > > +++ b/configure.ac > > @@ -11,10 +11,14 @@ AC_USE_SYSTEM_EXTENSIONS > > > > AM_SILENT_RULES([yes]) > > > > +GLIB2_REQUIRED=2.50.0 > > Is there a rational for that version, or is just what's on your OS install ? > > The GBus APIs have been around alot longer than this - mostly 2.30.0 iiuc This is version taken from CentOS 7. I can check the minimal version based on the used APIs. > > LIBVIRT_REQUIRED=AC_PACKAGE_VERSION > > SYSTEMD_REQUIRED=211 > > +LIBVIRT_GLIB_REQUIRED=1.0.0 > > Same question here ? For some reason I though that this is the first release. Form libvirt-glib we need only the gvir_event_register which means that we don't have to depend on any specific version. I will fix that. > > +AC_SUBST([GLIB2_REQUIRED]) dnl used in the .spec file > > AC_SUBST([LIBVIRT_REQUIRED]) dnl used in the .spec file > > AC_SUBST([SYSTEMD_REQUIRED]) dnl used in the .spec file > > +AC_SUBST([LIBVIRT_GLIB_REQUIRED]) dnl used in the .spec file > > > > LIBVIRT_DBUS_MAJOR_VERSION=`echo $VERSION | awk -F. '{print $1}'` > > LIBVIRT_DBUS_MINOR_VERSION=`echo $VERSION | awk -F. '{print $2}'` > > @@ -34,8 +38,11 @@ AC_PROG_MKDIR_P > > AM_PROG_CC_C_O > > AC_PROG_CC_STDC > > > > +PKG_CHECK_MODULES(GIO2, gio-unix-2.0 >= GLIB2_REQUIRED) > > +PKG_CHECK_MODULES(GLIB2, glib-2.0 >= GLIB2_REQUIRED) > > PKG_CHECK_MODULES(LIBVIRT, libvirt >= $LIBVIRT_REQUIRED) > > PKG_CHECK_MODULES(SYSTEMD, libsystemd >= $SYSTEMD_REQUIRED) > > +PKG_CHECK_MODULES(LIBVIRT_GLIB, libvirt-glib-1.0 >= LIBVIRT_GLIB_REQUIRED) > > > > diff --git a/src/gdbus.c b/src/gdbus.c > > new file mode 100644 > > index 0000000..7dd5766 > > --- /dev/null > > +++ b/src/gdbus.c > > @@ -0,0 +1,393 @@ > > +#include "gdbus.h" > > + > > +#include <glib/gprintf.h> > > + > > +struct _virtDBusGDBusMethodData { > > + virtDBusGDBusMethodTable *methods; > > + virtDBusGDBusPropertyTable *properties; > > + gpointer *userData; > > +}; > > +typedef struct _virtDBusGDBusMethodData virtDBusGDBusMethodData; > > + > > +struct _virtDBusGDBusSubtreeData { > > + GDBusInterfaceInfo *interface; > > + virtDBusGDBusMethodData *methodData; > > +}; > > +typedef struct _virtDBusGDBusSubtreeData virtDBusGDBusSubtreeData; > > + > > +static const gchar *dbusInterfacePrefix = NULL; > > + > > +/** > > + * virtDBusGDBusLoadIntrospectData: > > + * @interface: name of the interface > > + * > > + * Reads an interface XML description from file and returns new > > + * interface info. The caller owns an reference to the returned info. > > + * > > + * The file path is constructed as: > > + * > > + * VIRT_DBUS_INTERFACES_DIR/{@interface}.xml > > + * > > + * Returns interface info on success, NULL on failure. > > + */ > > +GDBusInterfaceInfo * > > +virtDBusGDBusLoadIntrospectData(gchar const *interface) > > +{ > > + g_autofree gchar *introspectFile = NULL; > > + g_autofree gchar *introspectXML = NULL; > > + g_autoptr(GDBusNodeInfo) nodeInfo = NULL; > > + GDBusInterfaceInfo *ret; > > + > > + if (!dbusInterfacePrefix) { > > + dbusInterfacePrefix = g_getenv("VIRT_DBUS_INTERFACES_DIR"); > > + if (!dbusInterfacePrefix) > > + dbusInterfacePrefix = VIRT_DBUS_INTERFACES_DIR; > > + } > > + > > + introspectFile = g_strdup_printf("%s/%s.xml", dbusInterfacePrefix, interface); > > + g_assert(introspectFile != NULL); > > + > > + g_file_get_contents(introspectFile, &introspectXML, NULL, NULL); > > + g_assert(introspectXML != NULL); > > + > > + nodeInfo = g_dbus_node_info_new_for_xml(introspectXML, NULL); > > + if (!nodeInfo) > > + return NULL; > > + > > + ret = nodeInfo->interfaces[0]; > > + if (!ret) > > + return NULL; > > + > > + return g_dbus_interface_info_ref(ret); > > +} > > My main comment would be that this is all using the low level dbus APIs > in glib, rather than the high level APIs. I can understand if that is > easier to adapt to given the existing code though. This was based on the gio/tests/gdbus-example-server.c since we don't need to use GObjects. From what I understand the high level API is supposed to be used together with GObjects. And it looks like that even in that case, you need to also use the low level APIs anyway. Pavel -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
© 2016 - 2025 Red Hat, Inc.