[libvirt] [PATCH v2] Pull DBus event code out into common area

Daniel P. Berrange berrange at redhat.com
Thu Apr 12 20:07:22 UTC 2012


From: "Daniel P. Berrange" <berrange at redhat.com>

The policy kit and HAL node device drivers both require a
DBus connection. The HAL device code further requires that
the DBus connection is integrated with the event loop and
provides such glue logic itself.

The forthcoming FirewallD integration also requires a
dbus connection with event loop integration. Thus we need
to pull the current event loop glue out of the HAL driver.

Thus we create src/util/virdbus.{c,h} files. This contains
just one method virDBusGetSystemBus() which obtains a handle
to the single shared system bus instance, with event glue
automagically setup.
---
 .gitignore                        |    6 +-
 configure.ac                      |   37 ++++++-
 daemon/Makefile.am                |    3 +-
 daemon/libvirtd.c                 |    4 -
 daemon/remote.c                   |    8 +-
 include/libvirt/virterror.h       |    1 +
 src/Makefile.am                   |   13 +--
 src/libvirt_dbus.syms             |    2 -
 src/node_device/node_device_hal.c |  143 ++------------------------
 src/rpc/virnetserver.c            |   40 --------
 src/rpc/virnetserver.h            |    8 --
 src/util/virdbus.c                |  201 +++++++++++++++++++++++++++++++++++++
 src/util/virdbus.h                |   34 ++++++
 src/util/virterror.c              |    3 +
 14 files changed, 296 insertions(+), 207 deletions(-)
 delete mode 100644 src/libvirt_dbus.syms
 create mode 100644 src/util/virdbus.c
 create mode 100644 src/util/virdbus.h

diff --git a/.gitignore b/.gitignore
index 5aa9c9b..14a21d0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -48,12 +48,12 @@
 /daemon/*_dispatch.h
 /daemon/libvirt_qemud
 /daemon/libvirtd
-/daemon/libvirtd.init
-/daemon/libvirtd.service
 /daemon/libvirtd*.logrotate
 /daemon/libvirtd.8
 /daemon/libvirtd.8.in
+/daemon/libvirtd.init
 /daemon/libvirtd.pod
+/daemon/libvirtd.service
 /docs/devhelp/libvirt.devhelp
 /docs/hvsupport.html.in
 /docs/libvirt-api.xml
@@ -118,6 +118,7 @@
 /tests/eventtest
 /tests/hashtest
 /tests/jsontest
+/tests/libvirtdconftest
 /tests/networkxml2argvtest
 /tests/nodeinfotest
 /tests/nwfilterxml2xmltest
@@ -150,7 +151,6 @@
 /tests/vmx2xmltest
 /tests/xencapstest
 /tests/xmconfigtest
-/tests/libvirtdconftest
 /tools/*.[18]
 /tools/libvirt-guests.init
 /tools/virsh
diff --git a/configure.ac b/configure.ac
index 3f5b3ff..f49b620 100644
--- a/configure.ac
+++ b/configure.ac
@@ -74,6 +74,7 @@ LIBPCAP_REQUIRED="1.0.0"
 LIBNL_REQUIRED="1.1"
 LIBSSH2_REQUIRED="1.0"
 LIBBLKID_REQUIRED="2.17"
+DBUS_REQUIRED="1.0.0"
 
 dnl Checks for C compiler.
 AC_PROG_CC
@@ -1099,6 +1100,36 @@ AC_SUBST([SANLOCK_CFLAGS])
 AC_SUBST([SANLOCK_LIBS])
 
 
+dnl DBus library
+DBUS_CFLAGS=
+DBUS_LIBS=
+AC_ARG_WITH([dbus],
+  AC_HELP_STRING([--with-dbus], [enable communication with DBus @<:@default=check@:>@]),
+  [],
+  [with_dbus=check])
+if test "$with_dbus" = "yes" || test "$with_dbus" = "check" ; then
+  PKG_CHECK_MODULES(DBUS, dbus-1 >= $DBUS_REQUIRED,
+    [with_dbus=yes], [
+     if test "$with_dbus" = "check" ; then
+       with_dbus=no
+     else
+       AC_MSG_ERROR([You must install DBus >= $DBUS_REQUIRED to compile libvirt])
+     fi])
+fi
+
+if test "$with_dbus" = "yes" ; then
+  AC_DEFINE_UNQUOTED([HAVE_DBUS], 1, [enable communication with DBus])
+
+  save_LIBS="$LIBS"
+  save_CFLAGS="$CFLAGS"
+  LIBS="$LIBS $DBUS_LIBS"
+  CFLAGS="$CFLAGS $DBUS_CFLAGS"
+  AC_CHECK_FUNCS([dbus_watch_get_unix_fd])
+  LIBS="$save_LIBS"
+  CFLAGS="$save_CFLAGS"
+fi
+
+
 dnl PolicyKit library
 POLKIT_CFLAGS=
 POLKIT_LIBS=
@@ -1109,7 +1140,6 @@ AC_ARG_WITH([polkit],
   [with_polkit=check])
 
 with_polkit0=no
-with_dbus=no
 with_polkit1=no
 if test "x$with_polkit" = "xyes" || test "x$with_polkit" = "xcheck"; then
   dnl Check for new polkit first - just a binary
@@ -1138,8 +1168,6 @@ if test "x$with_polkit" = "xyes" || test "x$with_polkit" = "xcheck"; then
         [use PolicyKit for UNIX socket access checks])
       AC_DEFINE_UNQUOTED([HAVE_POLKIT0], 1,
         [use PolicyKit for UNIX socket access checks])
-      AC_DEFINE_UNQUOTED([HAVE_DBUS], 1,
-        [use DBus for PolicyKit])
 
       old_CFLAGS=$CFLAGS
       old_LIBS=$LIBS
@@ -1154,13 +1182,11 @@ if test "x$with_polkit" = "xyes" || test "x$with_polkit" = "xcheck"; then
         AC_DEFINE_UNQUOTED([POLKIT_AUTH],["$POLKIT_AUTH"],[Location of polkit-auth program])
       fi
       with_polkit0="yes"
-      with_dbus="yes"
     fi
   fi
 fi
 AM_CONDITIONAL([HAVE_POLKIT], [test "x$with_polkit" = "xyes"])
 AM_CONDITIONAL([HAVE_POLKIT0], [test "x$with_polkit0" = "xyes"])
-AM_CONDITIONAL([HAVE_DBUS], [test "x$with_dbus" = "xyes"])
 AM_CONDITIONAL([HAVE_POLKIT1], [test "x$with_polkit1" = "xyes"])
 AC_SUBST([POLKIT_CFLAGS])
 AC_SUBST([POLKIT_LIBS])
@@ -2413,7 +2439,6 @@ if test "x$with_hal" = "xyes" || test "x$with_hal" = "xcheck"; then
     CFLAGS="$CFLAGS $HAL_CFLAGS"
     LIBS="$LIBS $HAL_LIBS"
     AC_CHECK_FUNCS([libhal_get_all_devices],,[with_hal=no])
-    AC_CHECK_FUNCS([dbus_watch_get_unix_fd])
     CFLAGS="$old_CFLAGS"
     LIBS="$old_LIBS"
   fi
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index 5d9f5d7..24cce8f 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -94,7 +94,7 @@ libvirtd_SOURCES = $(DAEMON_SOURCES)
 #-D_XOPEN_SOURCE=600 -D_XOPEN_SOURCE_EXTENDED=1 -D_POSIX_C_SOURCE=199506L
 libvirtd_CFLAGS = \
 	$(LIBXML_CFLAGS) $(GNUTLS_CFLAGS) $(SASL_CFLAGS) \
-	$(XDR_CFLAGS) $(POLKIT_CFLAGS) \
+	$(XDR_CFLAGS) $(POLKIT_CFLAGS) $(DBUS_CFLAGS) \
 	$(WARN_CFLAGS) \
 	$(COVERAGE_CFLAGS) \
 	-DQEMUD_PID_FILE="\"$(QEMUD_PID_FILE)\"" \
@@ -108,6 +108,7 @@ libvirtd_LDADD =					\
 	$(LIBXML_LIBS)					\
 	$(GNUTLS_LIBS)					\
 	$(SASL_LIBS)					\
+	$(DBUS_LIBS)					\
 	$(POLKIT_LIBS)
 
 if WITH_DTRACE_PROBES
diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c
index ce931d4..b098f6a 100644
--- a/daemon/libvirtd.c
+++ b/daemon/libvirtd.c
@@ -812,7 +812,6 @@ int main(int argc, char **argv) {
     struct daemonConfig *config;
     bool privileged = geteuid() == 0 ? true : false;
     bool implicit_conf = false;
-    bool use_polkit_dbus;
     char *run_dir = NULL;
     mode_t old_umask;
 
@@ -1008,8 +1007,6 @@ int main(int argc, char **argv) {
         goto cleanup;
     }
 
-    use_polkit_dbus = config->auth_unix_rw == REMOTE_AUTH_POLKIT ||
-            config->auth_unix_ro == REMOTE_AUTH_POLKIT;
     if (!(srv = virNetServerNew(config->min_workers,
                                 config->max_workers,
                                 config->prio_workers,
@@ -1018,7 +1015,6 @@ int main(int argc, char **argv) {
                                 config->keepalive_count,
                                 !!config->keepalive_required,
                                 config->mdns_adv ? config->mdns_name : NULL,
-                                use_polkit_dbus,
                                 remoteClientInitHook))) {
         ret = VIR_DAEMON_ERR_INIT;
         goto cleanup;
diff --git a/daemon/remote.c b/daemon/remote.c
index b71ffa2..16a8a05 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -45,7 +45,7 @@
 #include "virnetserver.h"
 #include "virfile.h"
 #include "virtypedparam.h"
-
+#include "virdbus.h"
 #include "remote_protocol.h"
 #include "qemu_protocol.h"
 
@@ -2672,6 +2672,7 @@ remoteDispatchAuthPolkit(virNetServerPtr server,
     char *ident = NULL;
     struct daemonClientPrivate *priv =
         virNetServerClientGetPrivateData(client);
+    DBusConnection *sysbus;
 
     virMutexLock(&priv->lock);
 
@@ -2697,10 +2698,13 @@ remoteDispatchAuthPolkit(virNetServerPtr server,
         goto authfail;
     }
 
+    if (!(sysbus = virDBusGetSystemBus()))
+        goto authfail;
+
     VIR_INFO("Checking PID %lld running as %d",
              (long long) callerPid, callerUid);
     dbus_error_init(&err);
-    if (!(pkcaller = polkit_caller_new_from_pid(virNetServerGetDBusConn(server),
+    if (!(pkcaller = polkit_caller_new_from_pid(sysbus,
                                                 callerPid, &err))) {
         VIR_ERROR(_("Failed to lookup policy kit caller: %s"), err.message);
         dbus_error_free(&err);
diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h
index e04d29e..cda15ff 100644
--- a/include/libvirt/virterror.h
+++ b/include/libvirt/virterror.h
@@ -87,6 +87,7 @@ typedef enum {
     VIR_FROM_CAPABILITIES = 44, /* Error from capabilities */
     VIR_FROM_URI = 45,          /* Error from URI handling */
     VIR_FROM_AUTH = 46,         /* Error from auth handling */
+    VIR_FROM_DBUS = 47,         /* Error from DBus */
 } virErrorDomain;
 
 
diff --git a/src/Makefile.am b/src/Makefile.am
index a2aae9d..b8a19b4 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -88,6 +88,7 @@ UTIL_SOURCES =							\
 		util/virtypedparam.c util/virtypedparam.h	\
 		util/xml.c util/xml.h				\
 		util/virterror.c util/virterror_internal.h	\
+		util/virdbus.c util/virdbus.h			\
 		util/virhash.c util/virhash.h			\
 		util/virhashcode.c util/virhashcode.h           \
 		util/virkeycode.c util/virkeycode.h		\
@@ -574,10 +575,11 @@ libvirt_la_BUILT_LIBADD = libvirt_util.la
 libvirt_util_la_SOURCES =					\
 		$(UTIL_SOURCES)
 libvirt_util_la_CFLAGS = $(CAPNG_CFLAGS) $(YAJL_CFLAGS) $(LIBNL_CFLAGS) \
-		$(AM_CFLAGS) $(AUDIT_CFLAGS) $(DEVMAPPER_CFLAGS)
+		$(AM_CFLAGS) $(AUDIT_CFLAGS) $(DEVMAPPER_CFLAGS) \
+		$(DBUS_CFLAGS)
 libvirt_util_la_LIBADD = $(CAPNG_LIBS) $(YAJL_LIBS) $(LIBNL_LIBS) \
 		$(THREAD_LIBS) $(AUDIT_LIBS) $(DEVMAPPER_LIBS) \
-		$(RT_LIBS)
+		$(RT_LIBS) $(DBUS_LIBS)
 
 
 noinst_LTLIBRARIES += libvirt_conf.la
@@ -1198,10 +1200,6 @@ if WITH_LINUX
 USED_SYM_FILES += libvirt_linux.syms
 endif
 
-if HAVE_DBUS
-USED_SYM_FILES += libvirt_dbus.syms
-endif
-
 if WITH_LIBVIRTD
 USED_SYM_FILES += libvirt_daemon.syms
 endif
@@ -1525,7 +1523,7 @@ libvirt_lxc_LDFLAGS = $(WARN_CFLAGS) $(AM_LDFLAGS)
 libvirt_lxc_LDADD = $(CAPNG_LIBS) $(YAJL_LIBS) \
 		$(LIBXML_LIBS) $(NUMACTL_LIBS) $(THREAD_LIBS) \
 		$(LIBNL_LIBS) $(AUDIT_LIBS) $(DEVMAPPER_LIBS) \
-		$(RT_LIBS) \
+		$(RT_LIBS) $(DBUS_LIBS) \
 		../gnulib/lib/libgnu.la
 if WITH_DTRACE_PROBES
 libvirt_lxc_LDADD += probes.o
@@ -1542,6 +1540,7 @@ libvirt_lxc_CFLAGS =				\
 		$(CAPNG_CFLAGS)			\
 		$(YAJL_CFLAGS)			\
 		$(AUDIT_CFLAGS)			\
+		$(DBUS_CFLAGS)			\
 		-I$(top_srcdir)/src/conf	\
 		$(AM_CFLAGS)
 if HAVE_LIBBLKID
diff --git a/src/libvirt_dbus.syms b/src/libvirt_dbus.syms
deleted file mode 100644
index a460ec5..0000000
--- a/src/libvirt_dbus.syms
+++ /dev/null
@@ -1,2 +0,0 @@
-# virnetserver.h
-virNetServerGetDBusConn;
diff --git a/src/node_device/node_device_hal.c b/src/node_device/node_device_hal.c
index a028886..dd14271 100644
--- a/src/node_device/node_device_hal.c
+++ b/src/node_device/node_device_hal.c
@@ -39,6 +39,7 @@
 #include "logging.h"
 #include "node_device_driver.h"
 #include "ignore-value.h"
+#include "virdbus.h"
 
 #define VIR_FROM_THIS VIR_FROM_NODEDEV
 
@@ -586,124 +587,15 @@ static void device_prop_modified(LibHalContext *ctx ATTRIBUTE_UNUSED,
 }
 
 
-static void dbus_watch_callback(int fdatch ATTRIBUTE_UNUSED,
-                                int fd ATTRIBUTE_UNUSED,
-                                int events, void *opaque)
-{
-    DBusWatch *watch = opaque;
-    LibHalContext *hal_ctx;
-    DBusConnection *dbus_conn;
-    int dbus_flags = 0;
-
-    if (events & VIR_EVENT_HANDLE_READABLE)
-        dbus_flags |= DBUS_WATCH_READABLE;
-    if (events & VIR_EVENT_HANDLE_WRITABLE)
-        dbus_flags |= DBUS_WATCH_WRITABLE;
-    if (events & VIR_EVENT_HANDLE_ERROR)
-        dbus_flags |= DBUS_WATCH_ERROR;
-    if (events & VIR_EVENT_HANDLE_HANGUP)
-        dbus_flags |= DBUS_WATCH_HANGUP;
-
-    (void)dbus_watch_handle(watch, dbus_flags);
-
-    nodeDeviceLock(driverState);
-    hal_ctx = DRV_STATE_HAL_CTX(driverState);
-    dbus_conn = libhal_ctx_get_dbus_connection(hal_ctx);
-    nodeDeviceUnlock(driverState);
-    while (dbus_connection_dispatch(dbus_conn) == DBUS_DISPATCH_DATA_REMAINS)
-        /* keep dispatching while data remains */;
-}
-
-
-static int xlate_dbus_watch_flags(int dbus_flags)
-{
-    unsigned int flags = 0;
-    if (dbus_flags & DBUS_WATCH_READABLE)
-        flags |= VIR_EVENT_HANDLE_READABLE;
-    if (dbus_flags & DBUS_WATCH_WRITABLE)
-        flags |= VIR_EVENT_HANDLE_WRITABLE;
-    if (dbus_flags & DBUS_WATCH_ERROR)
-        flags |= VIR_EVENT_HANDLE_ERROR;
-    if (dbus_flags & DBUS_WATCH_HANGUP)
-        flags |= VIR_EVENT_HANDLE_HANGUP;
-    return flags;
-}
-
-
-struct nodeDeviceWatchInfo
-{
-    int watch;
-};
-
-static void nodeDeviceWatchFree(void *data) {
-    struct nodeDeviceWatchInfo *info = data;
-    VIR_FREE(info);
-}
-
-static dbus_bool_t add_dbus_watch(DBusWatch *watch,
-                                  void *data ATTRIBUTE_UNUSED)
-{
-    int flags = 0;
-    int fd;
-    struct nodeDeviceWatchInfo *info;
-
-    if (VIR_ALLOC(info) < 0)
-        return 0;
-
-    if (dbus_watch_get_enabled(watch))
-        flags = xlate_dbus_watch_flags(dbus_watch_get_flags(watch));
-
-#if HAVE_DBUS_WATCH_GET_UNIX_FD
-    fd = dbus_watch_get_unix_fd(watch);
-#else
-    fd = dbus_watch_get_fd(watch);
-#endif
-    info->watch = virEventAddHandle(fd, flags, dbus_watch_callback,
-                                    watch, NULL);
-    if (info->watch < 0) {
-        VIR_FREE(info);
-        return 0;
-    }
-    dbus_watch_set_data(watch, info, nodeDeviceWatchFree);
-
-    return 1;
-}
-
-
-static void remove_dbus_watch(DBusWatch *watch,
-                              void *data ATTRIBUTE_UNUSED)
-{
-    struct nodeDeviceWatchInfo *info;
-
-    info = dbus_watch_get_data(watch);
-
-    (void)virEventRemoveHandle(info->watch);
-}
-
-
-static void toggle_dbus_watch(DBusWatch *watch,
-                              void *data ATTRIBUTE_UNUSED)
-{
-    int flags = 0;
-    struct nodeDeviceWatchInfo *info;
-
-    if (dbus_watch_get_enabled(watch))
-        flags = xlate_dbus_watch_flags(dbus_watch_get_flags(watch));
-
-    info = dbus_watch_get_data(watch);
-
-    (void)virEventUpdateHandle(info->watch, flags);
-}
 
 
 static int halDeviceMonitorStartup(int privileged ATTRIBUTE_UNUSED)
 {
     LibHalContext *hal_ctx = NULL;
-    DBusConnection *dbus_conn = NULL;
-    DBusError err;
     char **udi = NULL;
     int num_devs, i;
     int ret = -1;
+    DBusConnection *sysbus;
 
     /* Ensure caps_tbl is sorted by capability name */
     qsort(caps_tbl, ARRAY_CARDINALITY(caps_tbl), sizeof(caps_tbl[0]),
@@ -718,26 +610,19 @@ static int halDeviceMonitorStartup(int privileged ATTRIBUTE_UNUSED)
     }
     nodeDeviceLock(driverState);
 
-    /* Allocate and initialize a new HAL context */
-    dbus_connection_set_change_sigpipe(FALSE);
-    dbus_threads_init_default();
+    if (!(sysbus == virDBusGetSystemBus())) {
+        virErrorPtr err = virGetLastError();
+        VIR_ERROR(_("DBus not available, disabling HAL driver: %s",
+                    err->message));
+        ret = 0;
+        goto failure;
+    }
 
-    dbus_error_init(&err);
     hal_ctx = libhal_ctx_new();
     if (hal_ctx == NULL) {
         VIR_ERROR(_("libhal_ctx_new returned NULL"));
         goto failure;
     }
-    dbus_conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
-    if (dbus_conn == NULL) {
-        VIR_ERROR(_("dbus_bus_get failed"));
-        /* We don't want to show a fatal error here,
-           otherwise entire libvirtd shuts down when
-           D-Bus isn't running */
-        ret = 0;
-        goto failure;
-    }
-    dbus_connection_set_exit_on_disconnect(dbus_conn, FALSE);
 
     if (!libhal_ctx_set_dbus_connection(hal_ctx, dbus_conn)) {
         VIR_ERROR(_("libhal_ctx_set_dbus_connection failed"));
@@ -752,16 +637,6 @@ static int halDeviceMonitorStartup(int privileged ATTRIBUTE_UNUSED)
         goto failure;
     }
 
-    /* Register dbus watch callbacks */
-    if (!dbus_connection_set_watch_functions(dbus_conn,
-                                             add_dbus_watch,
-                                             remove_dbus_watch,
-                                             toggle_dbus_watch,
-                                             NULL, NULL)) {
-        VIR_ERROR(_("dbus_connection_set_watch_functions failed"));
-        goto failure;
-    }
-
     /* Populate with known devices */
     driverState->privateData = hal_ctx;
 
diff --git a/src/rpc/virnetserver.c b/src/rpc/virnetserver.c
index f761e6b..3965fc2 100644
--- a/src/rpc/virnetserver.c
+++ b/src/rpc/virnetserver.c
@@ -39,9 +39,6 @@
 #if HAVE_AVAHI
 # include "virnetservermdns.h"
 #endif
-#if HAVE_DBUS
-# include <dbus/dbus.h>
-#endif
 
 #define VIR_FROM_THIS VIR_FROM_RPC
 #define virNetError(code, ...)                                    \
@@ -88,10 +85,6 @@ struct _virNetServer {
     virNetServerMDNSGroupPtr mdnsGroup;
 #endif
 
-#if HAVE_DBUS
-    DBusConnection *sysbus;
-#endif
-
     size_t nservices;
     virNetServerServicePtr *services;
 
@@ -311,7 +304,6 @@ virNetServerPtr virNetServerNew(size_t min_workers,
                                 unsigned int keepaliveCount,
                                 bool keepaliveRequired,
                                 const char *mdnsGroupName,
-                                bool connectDBus ATTRIBUTE_UNUSED,
                                 virNetServerClientInitHook clientInitHook)
 {
     virNetServerPtr srv;
@@ -353,25 +345,6 @@ virNetServerPtr virNetServerNew(size_t min_workers,
     }
 #endif
 
-#if HAVE_DBUS
-    if (connectDBus) {
-        DBusError derr;
-
-        dbus_connection_set_change_sigpipe(FALSE);
-        dbus_threads_init_default();
-
-        dbus_error_init(&derr);
-        srv->sysbus = dbus_bus_get(DBUS_BUS_SYSTEM, &derr);
-        if (!(srv->sysbus)) {
-            VIR_ERROR(_("Failed to connect to system bus for PolicyKit auth: %s"),
-                      derr.message);
-            dbus_error_free(&derr);
-            goto error;
-        }
-        dbus_connection_set_exit_on_disconnect(srv->sysbus, FALSE);
-    }
-#endif
-
     if (virMutexInit(&srv->lock) < 0) {
         virNetError(VIR_ERR_INTERNAL_ERROR, "%s",
                     _("cannot initialize mutex"));
@@ -429,14 +402,6 @@ bool virNetServerIsPrivileged(virNetServerPtr srv)
 }
 
 
-#if HAVE_DBUS
-DBusConnection* virNetServerGetDBusConn(virNetServerPtr srv)
-{
-    return srv->sysbus;
-}
-#endif
-
-
 void virNetServerAutoShutdown(virNetServerPtr srv,
                               unsigned int timeout,
                               virNetServerAutoShutdownFunc func,
@@ -828,11 +793,6 @@ void virNetServerFree(virNetServerPtr srv)
     virNetServerMDNSFree(srv->mdns);
 #endif
 
-#if HAVE_DBUS
-    if (srv->sysbus)
-        dbus_connection_unref(srv->sysbus);
-#endif
-
     virNetServerUnlock(srv);
     virMutexDestroy(&srv->lock);
     VIR_FREE(srv);
diff --git a/src/rpc/virnetserver.h b/src/rpc/virnetserver.h
index a04ffdd..0ebe00e 100644
--- a/src/rpc/virnetserver.h
+++ b/src/rpc/virnetserver.h
@@ -25,9 +25,6 @@
 # define __VIR_NET_SERVER_H__
 
 # include <signal.h>
-# if HAVE_DBUS
-#  include <dbus/dbus.h>
-# endif
 
 # include "virnettlscontext.h"
 # include "virnetserverprogram.h"
@@ -45,7 +42,6 @@ virNetServerPtr virNetServerNew(size_t min_workers,
                                 unsigned int keepaliveCount,
                                 bool keepaliveRequired,
                                 const char *mdnsGroupName,
-                                bool connectDBus,
                                 virNetServerClientInitHook clientInitHook);
 
 typedef int (*virNetServerAutoShutdownFunc)(virNetServerPtr srv, void *opaque);
@@ -54,10 +50,6 @@ void virNetServerRef(virNetServerPtr srv);
 
 bool virNetServerIsPrivileged(virNetServerPtr srv);
 
-# if HAVE_DBUS
-DBusConnection* virNetServerGetDBusConn(virNetServerPtr srv);
-# endif
-
 void virNetServerAutoShutdown(virNetServerPtr srv,
                               unsigned int timeout,
                               virNetServerAutoShutdownFunc func,
diff --git a/src/util/virdbus.c b/src/util/virdbus.c
new file mode 100644
index 0000000..badfe8c
--- /dev/null
+++ b/src/util/virdbus.c
@@ -0,0 +1,201 @@
+/*
+ * virdbus.c: helper for using DBus
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ *
+ */
+
+#include <config.h>
+
+#include "virdbus.h"
+#include "memory.h"
+#include "virterror_internal.h"
+#include "logging.h"
+#include "threads.h"
+
+#define VIR_FROM_THIS VIR_FROM_DBUS
+
+#define virDBusReportError(code, ...)                                   \
+    virReportErrorHelper(VIR_FROM_THIS, code, __FILE__,                 \
+                         __FUNCTION__, __LINE__, __VA_ARGS__)
+
+#ifdef HAVE_DBUS
+
+static DBusConnection *systembus = NULL;
+static virOnceControl once = VIR_ONCE_CONTROL_INITIALIZER;
+static DBusError dbuserr;
+
+static dbus_bool_t virDBusAddWatch(DBusWatch *watch, void *data);
+static void virDBusRemoveWatch(DBusWatch *watch, void *data);
+static void virDBusToggleWatch(DBusWatch *watch, void *data);
+
+static void virDBusSystemBusInit(void)
+{
+    /* Allocate and initialize a new HAL context */
+    dbus_connection_set_change_sigpipe(FALSE);
+    dbus_threads_init_default();
+
+    dbus_error_init(&dbuserr);
+    if (!(systembus = dbus_bus_get(DBUS_BUS_SYSTEM, &dbuserr)))
+        return;
+
+    dbus_connection_set_exit_on_disconnect(systembus, FALSE);
+
+    /* Register dbus watch callbacks */
+    if (!dbus_connection_set_watch_functions(systembus,
+                                             virDBusAddWatch,
+                                             virDBusRemoveWatch,
+                                             virDBusToggleWatch,
+                                             NULL, NULL)) {
+        systembus = NULL;
+        return;
+    }
+}
+
+
+DBusConnection *virDBusGetSystemBus(void)
+{
+    if (virOnce(&once, virDBusSystemBusInit) < 0) {
+        virDBusReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("Unable to run one time DBus initializer"));
+        return NULL;
+    }
+
+    if (!systembus) {
+        virDBusReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("Unable to get DBus system bus connection: %s"),
+                           dbuserr.message ? dbuserr.message : "watch setup failed");
+        return NULL;
+    }
+
+    return systembus;
+}
+
+
+static void virDBusWatchCallback(int fdatch ATTRIBUTE_UNUSED,
+                                 int fd ATTRIBUTE_UNUSED,
+                                 int events, void *opaque)
+{
+    DBusWatch *watch = opaque;
+    int dbus_flags = 0;
+
+    if (events & VIR_EVENT_HANDLE_READABLE)
+        dbus_flags |= DBUS_WATCH_READABLE;
+    if (events & VIR_EVENT_HANDLE_WRITABLE)
+        dbus_flags |= DBUS_WATCH_WRITABLE;
+    if (events & VIR_EVENT_HANDLE_ERROR)
+        dbus_flags |= DBUS_WATCH_ERROR;
+    if (events & VIR_EVENT_HANDLE_HANGUP)
+        dbus_flags |= DBUS_WATCH_HANGUP;
+
+    (void)dbus_watch_handle(watch, dbus_flags);
+
+    while (dbus_connection_dispatch(systembus) == DBUS_DISPATCH_DATA_REMAINS)
+        /* keep dispatching while data remains */;
+}
+
+
+static int virDBusTranslateWatchFlags(int dbus_flags)
+{
+    unsigned int flags = 0;
+    if (dbus_flags & DBUS_WATCH_READABLE)
+        flags |= VIR_EVENT_HANDLE_READABLE;
+    if (dbus_flags & DBUS_WATCH_WRITABLE)
+        flags |= VIR_EVENT_HANDLE_WRITABLE;
+    if (dbus_flags & DBUS_WATCH_ERROR)
+        flags |= VIR_EVENT_HANDLE_ERROR;
+    if (dbus_flags & DBUS_WATCH_HANGUP)
+        flags |= VIR_EVENT_HANDLE_HANGUP;
+    return flags;
+}
+
+
+struct virDBusWatch
+{
+    int watch;
+};
+
+static void virDBusWatchFree(void *data) {
+    struct virDBusWatch *info = data;
+    VIR_FREE(info);
+}
+
+static dbus_bool_t virDBusAddWatch(DBusWatch *watch,
+                                  void *data ATTRIBUTE_UNUSED)
+{
+    int flags = 0;
+    int fd;
+    struct virDBusWatch *info;
+
+    if (VIR_ALLOC(info) < 0)
+        return 0;
+
+    if (dbus_watch_get_enabled(watch))
+        flags = virDBusTranslateWatchFlags(dbus_watch_get_flags(watch));
+
+# if HAVE_DBUS_WATCH_GET_UNIX_FD
+    fd = dbus_watch_get_unix_fd(watch);
+# else
+    fd = dbus_watch_get_fd(watch);
+# endif
+    info->watch = virEventAddHandle(fd, flags,
+                                    virDBusWatchCallback,
+                                    watch, NULL);
+    if (info->watch < 0) {
+        VIR_FREE(info);
+        return 0;
+    }
+    dbus_watch_set_data(watch, info, virDBusWatchFree);
+
+    return 1;
+}
+
+
+static void virDBusRemoveWatch(DBusWatch *watch,
+                               void *data ATTRIBUTE_UNUSED)
+{
+    struct virDBusWatch *info;
+
+    info = dbus_watch_get_data(watch);
+
+    (void)virEventRemoveHandle(info->watch);
+}
+
+
+static void virDBusToggleWatch(DBusWatch *watch,
+                               void *data ATTRIBUTE_UNUSED)
+{
+    int flags = 0;
+    struct virDBusWatch *info;
+
+    if (dbus_watch_get_enabled(watch))
+        flags = virDBusTranslateWatchFlags(dbus_watch_get_flags(watch));
+
+    info = dbus_watch_get_data(watch);
+
+    (void)virEventUpdateHandle(info->watch, flags);
+}
+
+#else /* ! HAVE_DBUS */
+DBusConnection *virDBusGetSystemBus(void)
+{
+    virDBusReportError(VIR_ERR_INTERNAL_ERROR,
+                       "%s", _("DBus support not compiled into this binary"));
+    return NULL;
+}
+
+#endif /* ! HAVE_DBUS */
diff --git a/src/util/virdbus.h b/src/util/virdbus.h
new file mode 100644
index 0000000..7d9ec8f
--- /dev/null
+++ b/src/util/virdbus.h
@@ -0,0 +1,34 @@
+/*
+ * virdbus.h: helper for using DBus
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ *
+ */
+
+#ifndef __VIR_DBUS_H__
+# define __VIR_DBUS_H__
+
+# ifdef HAVE_DBUS
+#  include <dbus/dbus.h>
+# else
+#  define DBusConnection void
+# endif
+# include "internal.h"
+
+DBusConnection *virDBusGetSystemBus(void);
+
+#endif /* __VIR_DBUS_H__ */
diff --git a/src/util/virterror.c b/src/util/virterror.c
index ff9a36f..de45bb0 100644
--- a/src/util/virterror.c
+++ b/src/util/virterror.c
@@ -184,6 +184,9 @@ static const char *virErrorDomainName(virErrorDomain domain) {
         case VIR_FROM_AUTH:
             dom = "Auth ";
             break;
+        case VIR_FROM_DBUS:
+            dom = "DBus ";
+            break;
     }
     return dom;
 }
-- 
1.7.7.6




More information about the libvir-list mailing list